When we can switch entirely to 1.6 we can use Postgres's value = any(?::int[])

form to pass as many damned keys we want in a giant array. At that time we can
nix all the >32,768 key fiddly business.


git-svn-id: https://samskivert.googlecode.com/svn/trunk@2465 6335cc39-0255-0410-8fd6-9bcaacd3b74c
This commit is contained in:
samskivert
2008-10-31 00:17:36 +00:00
parent 182f6cae60
commit 5a71283b5e
6 changed files with 72 additions and 23 deletions
@@ -21,6 +21,7 @@
package com.samskivert.jdbc.depot; package com.samskivert.jdbc.depot;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Map; import java.util.Map;
@@ -261,9 +262,10 @@ public class BindVisitor implements ExpressionVisitor
deleteClause.getWhereClause().accept(this); deleteClause.getWhereClause().accept(this);
} }
protected BindVisitor (DepotTypes types, PreparedStatement stmt) protected BindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt)
{ {
_types = types; _types = types;
_conn = conn;
_stmt = stmt; _stmt = stmt;
_argIdx = 1; _argIdx = 1;
} }
@@ -299,6 +301,7 @@ public class BindVisitor implements ExpressionVisitor
} }
protected DepotTypes _types; protected DepotTypes _types;
protected Connection _conn;
protected PreparedStatement _stmt; protected PreparedStatement _stmt;
protected int _argIdx; protected int _argIdx;
} }
+10 -1
View File
@@ -52,13 +52,22 @@ public class KeySet<T extends PersistentRecord> extends WhereClause
_condition = new LiteralExp("false"); _condition = new LiteralExp("false");
} else if (keyFields.length == 1) { } else if (keyFields.length == 1) {
// TODO: remove when we update to 1.6 and change Postgres In handling
if (keys.size() > Conditionals.In.MAX_KEYS) { if (keys.size() > Conditionals.In.MAX_KEYS) {
throw new IllegalArgumentException("Cannot create where clause for more than " + throw new IllegalArgumentException("Cannot create where clause for more than " +
Conditionals.In.MAX_KEYS + " at a time."); Conditionals.In.MAX_KEYS + " at a time.");
} }
// Single-column keys result in the compact IN(keyVal1, keyVal2, ...) // Single-column keys result in the compact IN(keyVal1, keyVal2, ...)
Comparable<?>[] keyFieldValues = new Comparable<?>[keys.size()]; Comparable<?> first = keys.iterator().next().getValues().get(0);
Comparable<?>[] keyFieldValues;
if (first instanceof Integer) {
keyFieldValues = new Integer[keys.size()];
} else if (first instanceof Integer) {
keyFieldValues = new String[keys.size()];
} else {
keyFieldValues = new Comparable<?>[keys.size()];
}
int ii = 0; int ii = 0;
for (Key<T> key : keys) { for (Key<T> key : keys) {
keyFieldValues[ii++] = key.getValues().get(0); keyFieldValues[ii++] = key.getValues().get(0);
@@ -117,8 +117,8 @@ public class MySQLBuilder
public class MSBindVisitor extends BindVisitor public class MSBindVisitor extends BindVisitor
{ {
protected MSBindVisitor (DepotTypes types, PreparedStatement stmt) { protected MSBindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt) {
super(types, stmt); super(types, conn, stmt);
} }
@Override public void visit (FullTextMatch match) { @Override public void visit (FullTextMatch match) {
@@ -195,9 +195,9 @@ public class MySQLBuilder
} }
@Override @Override
protected BindVisitor getBindVisitor (PreparedStatement stmt) protected BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt)
{ {
return new MSBindVisitor(_types, stmt); return new MSBindVisitor(_types, conn, stmt);
} }
@Override @Override
@@ -48,6 +48,7 @@ import com.samskivert.jdbc.depot.FieldMarshaller.ShortMarshaller;
import com.samskivert.jdbc.depot.annotation.FullTextIndex; import com.samskivert.jdbc.depot.annotation.FullTextIndex;
import com.samskivert.jdbc.depot.expression.EpochSeconds; import com.samskivert.jdbc.depot.expression.EpochSeconds;
import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch;
import com.samskivert.jdbc.depot.operator.Conditionals.In;
import com.samskivert.util.ArrayUtil; import com.samskivert.util.ArrayUtil;
import com.samskivert.util.StringUtil; import com.samskivert.util.StringUtil;
@@ -58,26 +59,28 @@ public class PostgreSQLBuilder
{ {
public class PGBuildVisitor extends BuildVisitor public class PGBuildVisitor extends BuildVisitor
{ {
@Override public void visit (FullTextMatch match) @Override public void visit (FullTextMatch match) {
{
appendIdentifier("ftsCol_" + match.getName()); appendIdentifier("ftsCol_" + match.getName());
_builder.append(" @@ TO_TSQUERY('default', ?)"); _builder.append(" @@ TO_TSQUERY('default', ?)");
} }
public void visit (EpochSeconds epochSeconds) @Override public void visit (EpochSeconds epochSeconds) {
{
_builder.append("date_part('epoch', "); _builder.append("date_part('epoch', ");
epochSeconds.getArgument().accept(this); epochSeconds.getArgument().accept(this);
_builder.append(")"); _builder.append(")");
} }
protected PGBuildVisitor (DepotTypes types) // TODO: enable when we can require 1.6 support
{ // @Override public void visit (In in) {
// in.getColumn().accept(this);
// _builder.append(" = any (?)");
// }
protected PGBuildVisitor (DepotTypes types) {
super(types); super(types);
} }
@Override protected void appendIdentifier (String field) @Override protected void appendIdentifier (String field) {
{
_builder.append("\"").append(field).append("\""); _builder.append("\"").append(field).append("\"");
} }
} }
@@ -103,8 +106,32 @@ public class PostgreSQLBuilder
} }
} }
protected PGBindVisitor (DepotTypes types, PreparedStatement stmt) { // TODO: enable when we can require 1.6 support
super(types, stmt); // @Override public void visit (In in) {
// Comparable<?>[] values = in.getValues();
// try {
// _stmt.setObject(
// _argIdx++, _conn.createArrayOf(getElementType(values), (Object[])values));
// } catch (SQLException sqe) {
// throw new DatabaseException(
// "Failed to write value to statement [idx=" + (_argIdx-1) +
// ", values=" + StringUtil.safeToString(values) + "]", sqe);
// }
// }
// protected String getElementType (Comparable<?>[] values) {
// if (values instanceof Integer[]) {
// return "integer";
// } else if (values instanceof String[]) {
// return "character varying";
// } else {
// throw new DatabaseException(
// "Don't know how to make Postgres array for " + values.getClass());
// }
// }
protected PGBindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt) {
super(types, conn, stmt);
} }
} }
@@ -203,9 +230,9 @@ public class PostgreSQLBuilder
} }
@Override @Override
protected BindVisitor getBindVisitor (PreparedStatement stmt) protected BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt)
{ {
return new PGBindVisitor(_types, stmt); return new PGBindVisitor(_types, conn, stmt);
} }
@Override @Override
@@ -78,7 +78,7 @@ public abstract class SQLBuilder
} }
PreparedStatement stmt = conn.prepareStatement(_buildVisitor.getQuery()); PreparedStatement stmt = conn.prepareStatement(_buildVisitor.getQuery());
_bindVisitor = getBindVisitor(stmt); _bindVisitor = getBindVisitor(conn, stmt);
_clause.accept(_bindVisitor); _clause.accept(_bindVisitor);
if (PersistenceContext.DEBUG) { if (PersistenceContext.DEBUG) {
@@ -213,7 +213,7 @@ public abstract class SQLBuilder
/** /**
* Overridden by subclasses to create a dialect-specific {@link BindVisitor}. * Overridden by subclasses to create a dialect-specific {@link BindVisitor}.
*/ */
protected abstract BindVisitor getBindVisitor (PreparedStatement stmt); protected abstract BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt);
/** /**
* Overridden by subclasses to figure the dialect-specific SQL type of the given field. * Overridden by subclasses to figure the dialect-specific SQL type of the given field.
@@ -22,17 +22,21 @@ package com.samskivert.jdbc.depot.tests;
import java.sql.Date; import java.sql.Date;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.samskivert.jdbc.StaticConnectionProvider;
import com.samskivert.util.RandomUtil; import com.samskivert.util.RandomUtil;
import com.samskivert.jdbc.StaticConnectionProvider;
import com.samskivert.jdbc.depot.DepotRepository; import com.samskivert.jdbc.depot.DepotRepository;
import com.samskivert.jdbc.depot.SchemaMigration; import com.samskivert.jdbc.depot.Key;
import com.samskivert.jdbc.depot.KeySet;
import com.samskivert.jdbc.depot.PersistenceContext; import com.samskivert.jdbc.depot.PersistenceContext;
import com.samskivert.jdbc.depot.PersistentRecord; import com.samskivert.jdbc.depot.PersistentRecord;
import com.samskivert.jdbc.depot.SchemaMigration;
import com.samskivert.jdbc.depot.clause.Where;
import com.samskivert.jdbc.depot.expression.LiteralExp; import com.samskivert.jdbc.depot.expression.LiteralExp;
import com.samskivert.jdbc.depot.operator.Conditionals; import com.samskivert.jdbc.depot.operator.Conditionals;
import com.samskivert.jdbc.depot.clause.Where;
/** /**
* A test tool for the Depot repository services. * A test tool for the Depot repository services.
@@ -98,6 +102,12 @@ public class TestRepository extends DepotRepository
TestRecord.RECORD_ID_C, CREATE_RECORDS/2))); TestRecord.RECORD_ID_C, CREATE_RECORDS/2)));
System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records."); System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records.");
repo.deleteAll(TestRecord.class, new Where(new LiteralExp("true"))); repo.deleteAll(TestRecord.class, new Where(new LiteralExp("true")));
// // TODO: try to break our In() clause
// Set<Key<TestRecord>> ids = new HashSet<Key<TestRecord>>();
// for (int ii = 1; ii <= Conditionals.In.MAX_KEYS*2+3; ii++) {
// ids.add(TestRecord.getKey(ii));
// }
// repo.deleteAll(TestRecord.class, new KeySet<TestRecord>(TestRecord.class, ids));
System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records."); System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records.");
} }