#74 fixed null handling in batch inserts

This commit is contained in:
Timo Westkämper 2012-02-08 17:14:27 +02:00
parent a3ab07f9fe
commit aa4e49cf9a
12 changed files with 155 additions and 24 deletions

View File

@ -1,7 +1,7 @@
----------------------------------------------------------------
Sun Nov 20 21:21:36 EET 2011:
Booting Derby version The Apache Software Foundation - Apache Derby - 10.8.2.2 - (1181258): instance a816c00e-0133-c26d-3187-000002b80608
on database directory /home/tiwe/work/querydsl/querydsl-sql/target/demoDB with class loader sun.misc.Launcher$AppClassLoader@1a16869
Wed Feb 08 17:05:09 EET 2012:
Booting Derby version The Apache Software Foundation - Apache Derby - 10.8.2.2 - (1181258): instance a816c00e-0135-5d7f-29ad-000002c981b8
on database directory /home/tiwe/work/querydsl/querydsl-sql/target/demoDB with class loader sun.misc.Launcher$AppClassLoader@1cde100
Loaded from file:/home/tiwe/.m2/repository/org/apache/derby/derby/10.8.2.2/derby-10.8.2.2.jar
java.vendor=Sun Microsystems Inc.
java.runtime.version=1.6.0_26-b03

View File

@ -21,6 +21,8 @@ import java.util.Map;
import javax.annotation.Nullable;
import com.mysema.query.sql.types.Null;
/**
* JDBCTypeMapping defines a mapping from JDBC types to Java classes.
*
@ -76,7 +78,7 @@ public final class JDBCTypeMapping {
registerDefault(Types.DISTINCT, Object.class);
registerDefault(Types.DATALINK, Object.class);
registerDefault(Types.JAVA_OBJECT, Object.class);
registerDefault(Types.NULL, Object.class);
registerDefault(Types.NULL, Null.class);
registerDefault(Types.OTHER, Object.class);
registerDefault(Types.REF, Object.class);
registerDefault(Types.ROWID, Object.class);

View File

@ -20,7 +20,27 @@ import java.util.Set;
import javax.annotation.Nullable;
import com.mysema.commons.lang.Pair;
import com.mysema.query.sql.types.*;
import com.mysema.query.sql.types.BigDecimalType;
import com.mysema.query.sql.types.BlobType;
import com.mysema.query.sql.types.BooleanType;
import com.mysema.query.sql.types.ByteType;
import com.mysema.query.sql.types.BytesType;
import com.mysema.query.sql.types.CharacterType;
import com.mysema.query.sql.types.ClobType;
import com.mysema.query.sql.types.DateType;
import com.mysema.query.sql.types.DoubleType;
import com.mysema.query.sql.types.FloatType;
import com.mysema.query.sql.types.IntegerType;
import com.mysema.query.sql.types.LongType;
import com.mysema.query.sql.types.NullType;
import com.mysema.query.sql.types.ObjectType;
import com.mysema.query.sql.types.ShortType;
import com.mysema.query.sql.types.StringType;
import com.mysema.query.sql.types.TimeType;
import com.mysema.query.sql.types.TimestampType;
import com.mysema.query.sql.types.Type;
import com.mysema.query.sql.types.URLType;
import com.mysema.query.sql.types.UtilDateType;
import com.mysema.util.ReflectionUtils;
/**
@ -53,6 +73,7 @@ public class JavaTypeMapping {
registerDefault(new TimeType());
registerDefault(new URLType());
registerDefault(new UtilDateType());
registerDefault(new NullType());
// initialize joda time converters only if joda time is available
try {

View File

@ -36,7 +36,8 @@ public class ForeignKeyBuilder {
private final SQLTemplates templates;
public ForeignKeyBuilder(CreateTableClause clause, SQLTemplates templates, List<ForeignKeyData> foreignKeys, String name, String[] columns) {
public ForeignKeyBuilder(CreateTableClause clause, SQLTemplates templates,
List<ForeignKeyData> foreignKeys, String name, String[] columns) {
this.clause = clause;
this.templates = templates;
this.foreignKeys = foreignKeys;

View File

@ -47,7 +47,8 @@ public class AbstractSQLClause {
* @param constantPaths list of paths related to the constants
* @param params map of param to value for param resolving
*/
protected void setParameters(PreparedStatement stmt, List<?> objects, List<Path<?>> constantPaths, Map<Param<?>, ?> params) {
protected void setParameters(PreparedStatement stmt, List<?> objects,
List<Path<?>> constantPaths, Map<Param<?>, ?> params) {
if (objects.size() != constantPaths.size()) {
throw new IllegalArgumentException("Expected " + objects.size() + " paths, but got " + constantPaths.size());
}

View File

@ -42,9 +42,9 @@ import com.mysema.query.sql.Configuration;
import com.mysema.query.sql.RelationalPath;
import com.mysema.query.sql.SQLSerializer;
import com.mysema.query.sql.SQLTemplates;
import com.mysema.query.sql.types.Null;
import com.mysema.query.types.ConstantImpl;
import com.mysema.query.types.Expression;
import com.mysema.query.types.NullExpression;
import com.mysema.query.types.Path;
import com.mysema.query.types.SubQueryExpression;
import com.mysema.query.types.expr.Param;
@ -84,12 +84,14 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
this(connection, new Configuration(templates), entity);
}
public SQLInsertClause(Connection connection, SQLTemplates templates, RelationalPath<?> entity, AbstractSQLSubQuery<?> subQuery) {
public SQLInsertClause(Connection connection, SQLTemplates templates, RelationalPath<?> entity,
AbstractSQLSubQuery<?> subQuery) {
this(connection, new Configuration(templates), entity);
this.subQueryBuilder = subQuery;
}
public SQLInsertClause(Connection connection, Configuration configuration, RelationalPath<?> entity, AbstractSQLSubQuery<?> subQuery) {
public SQLInsertClause(Connection connection, Configuration configuration, RelationalPath<?> entity,
AbstractSQLSubQuery<?> subQuery) {
this(connection, configuration, entity);
this.subQueryBuilder = subQuery;
}
@ -225,7 +227,8 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
serializer.serializeForInsert(metadata, entity, columns, values, subQuery);
stmt = prepareStatementAndSetParameters(serializer, withKeys);
} else {
serializer.serializeForInsert(metadata, entity, batches.get(0).getColumns(), batches.get(0).getValues(), batches.get(0).getSubQuery());
serializer.serializeForInsert(metadata, entity, batches.get(0).getColumns(),
batches.get(0).getValues(), batches.get(0).getSubQuery());
stmt = prepareStatementAndSetParameters(serializer, withKeys);
// add first batch
@ -243,7 +246,8 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
return stmt;
}
private PreparedStatement prepareStatementAndSetParameters(SQLSerializer serializer, boolean withKeys) throws SQLException {
private PreparedStatement prepareStatementAndSetParameters(SQLSerializer serializer,
boolean withKeys) throws SQLException {
queryString = serializer.toString();
logger.debug(queryString);
PreparedStatement stmt;
@ -252,7 +256,8 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
} else {
stmt = connection.prepareStatement(queryString);
}
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
return stmt;
}
@ -322,7 +327,8 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
}else if (value != null) {
values.add(new ConstantImpl<T>(value));
} else {
values.add(new NullExpression<T>(path.getType()));
//values.add(new NullExpression<T>(path.getType()));
values.add(Null.CONSTANT);
}
return this;
}
@ -337,7 +343,8 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
@Override
public <T> SQLInsertClause setNull(Path<T> path) {
columns.add(path);
values.add(new NullExpression<T>(path.getType()));
//values.add(new NullExpression<T>(path.getType()));
values.add(Null.CONSTANT);
return this;
}
@ -349,7 +356,7 @@ public class SQLInsertClause extends AbstractSQLClause implements InsertClause<S
} else if (value != null) {
values.add(new ConstantImpl<Object>(value));
} else {
values.add(NullExpression.DEFAULT);
values.add(Null.CONSTANT);
}
}
return this;

View File

@ -186,7 +186,8 @@ public class SQLMergeClause extends AbstractSQLClause implements StoreClause<SQL
queryString = serializer.toString();
logger.debug(queryString);
stmt = connection.prepareStatement(queryString);
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
} else {
serializer.serializeForMerge(metadata, entity,
batches.get(0).getKeys(), batches.get(0).getColumns(),
@ -194,7 +195,8 @@ public class SQLMergeClause extends AbstractSQLClause implements StoreClause<SQL
queryString = serializer.toString();
logger.debug(queryString);
stmt = connection.prepareStatement(queryString);
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
// add first batch
stmt.addBatch();

View File

@ -128,7 +128,8 @@ public class SQLUpdateClause extends AbstractSQLClause implements UpdateClause<
queryString = serializer.toString();
logger.debug(queryString);
stmt = connection.prepareStatement(queryString);
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
} else {
SQLSerializer serializer = new SQLSerializer(configuration.getTemplates(), true);
serializer.serializeForUpdate(batchMetadata.get(0), entity, batchUpdates.get(0));
@ -137,14 +138,16 @@ public class SQLUpdateClause extends AbstractSQLClause implements UpdateClause<
// add first batch
stmt = connection.prepareStatement(queryString);
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
stmt.addBatch();
// add other batches
for (int i = 1; i < batchUpdates.size(); i++) {
serializer = new SQLSerializer(configuration.getTemplates(), true, true);
serializer.serializeForUpdate(batchMetadata.get(i), entity, batchUpdates.get(i));
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(), Collections.<Param<?>,Object>emptyMap());
setParameters(stmt, serializer.getConstants(), serializer.getConstantPaths(),
Collections.<Param<?>,Object>emptyMap());
stmt.addBatch();
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2011, Mysema Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mysema.query.sql.types;
import com.mysema.query.types.Constant;
import com.mysema.query.types.ConstantImpl;
/**
* @author tiwe
*
*/
public final class Null {
public static final Null DEFAULT = new Null();
public static final Constant<Null> CONSTANT = new ConstantImpl<Null>(DEFAULT);
private Null() {}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 2011, Mysema Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mysema.query.sql.types;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
/**
* @author tiwe
*
*/
public class NullType extends AbstractType<Null> {
public NullType() {
super(Types.OTHER);
}
@Override
public Class<Null> getReturnedClass() {
return Null.class;
}
@Override
public Null getValue(ResultSet rs, int startIndex) throws SQLException {
return null;
}
@Override
public void setValue(PreparedStatement st, int startIndex, Null value) throws SQLException {
int type = st.getParameterMetaData().getParameterType(startIndex);
st.setNull(startIndex, type);
}
}

View File

@ -60,8 +60,7 @@ public abstract class InsertBaseTest extends AbstractBaseTest{
@Test
public void Insert_Without_Columns() {
assertEquals(1, insert(survey)
.values(4, "Hello").execute());
assertEquals(1, insert(survey).values(4, "Hello").execute());
}
@ -109,6 +108,22 @@ public abstract class InsertBaseTest extends AbstractBaseTest{
assertEquals(1l, query().from(survey).where(survey.name.eq("66")).count());
}
@Test
public void Insert_Nulls_In_Batch() {
// QFoo f= QFoo.foo;
// SQLInsertClause sic = new SQLInsertClause(c, new H2Templates(), f);
// sic.columns(f.c1,f.c2).values(null,null).addBatch();
// sic.columns(f.c1,f.c2).values(null,1).addBatch();
// sic.execute();
SQLInsertClause sic = insert(survey);
sic.columns(survey.id, survey.name).values(null, null).addBatch();
sic.columns(survey.id, survey.name).values(null, 1).addBatch();
System.out.println("start batch");
sic.execute();
System.out.println("end batch");
}
@Test
public void Like_with_Escape(){
SQLInsertClause insert = insert(survey);

View File

@ -76,7 +76,7 @@ public class SerializationTest {
SQLInsertClause insertClause = new SQLInsertClause(connection,SQLTemplates.DEFAULT,survey);
insertClause.set(survey.id, 1);
insertClause.set(survey.name, (String)null);
assertEquals("insert into SURVEY(ID, NAME)\nvalues (?, null)", insertClause.toString());
assertEquals("insert into SURVEY(ID, NAME)\nvalues (?, ?)", insertClause.toString());
}
@Test