Java tutorial
// Copyright 2008 Google Inc. // // 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.google.gwtorm.jdbc; import com.google.gwtorm.client.Key; import com.google.gwtorm.schema.ColumnModel; import com.google.gwtorm.schema.KeyModel; import com.google.gwtorm.schema.QueryModel; import com.google.gwtorm.schema.RelationModel; import com.google.gwtorm.schema.Util; import com.google.gwtorm.schema.sql.SqlDialect; import com.google.gwtorm.server.Access; import com.google.gwtorm.server.CodeGenSupport; import com.google.gwtorm.server.GeneratedClassLoader; import com.google.gwtorm.server.OrmException; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; /** Generates a concrete implementation of an {@link Access} extension. */ class AccessGen implements Opcodes { private static final String REL_ALIAS = "T"; private static enum DmlType { INSERT("bindOneInsert"), UPDATE("bindOneUpdate"), DELETE("bindOneDelete"); final String methodName; DmlType(final String m) { methodName = m; } } private final GeneratedClassLoader classLoader; private final RelationModel model; private final SqlDialect dialect; private ClassWriter cw; private String superTypeName; private String implClassName; private String implTypeName; private Type entityType; AccessGen(final GeneratedClassLoader loader, final RelationModel rm, final SqlDialect sd) { classLoader = loader; model = rm; dialect = sd; entityType = Type.getObjectType(model.getEntityTypeClassName().replace('.', '/')); } public Class<?> create() throws OrmException { init(); implementConstructor(); implementGetString("getRelationName", model.getRelationName()); implementGetString("getInsertOneSql", model.getInsertOneSql(dialect)); implementGetRelationID(); if (model.getPrimaryKey() != null) { if (model.getDependentColumns().isEmpty()) { implementMissingGetString("getUpdateOneSql", "update"); } else { implementGetString("getUpdateOneSql", model.getUpdateOneSql(dialect)); } implementGetString("getDeleteOneSql", model.getDeleteOneSql(dialect)); } else { implementMissingGetString("getUpdateOneSql", "update"); implementMissingGetString("getDeleteOneSql", "delete"); } implementPrimaryKey(); implementGetOne(); implementNewEntityInstance(); implementBindOne(DmlType.INSERT); implementBindOne(DmlType.UPDATE); implementBindOne(DmlType.DELETE); implementBindOneFetch(); if (model.getPrimaryKey() != null) { implementKeyQuery(model.getPrimaryKey()); if ((model.getPrimaryKey().getField().isNested() || !model.getPrimaryKey().getField().getPrimitiveType().isPrimitive()) && model.getPrimaryKey().getAllLeafColumns().size() == 1) { overrideGetMany(); } } for (final QueryModel q : model.getQueries()) { implementQuery(q); } implementQuery(new QueryModel(model, "iterateAllEntities", "")); cw.visitEnd(); classLoader.defineClass(implClassName, cw.toByteArray()); return loadClass(); } private Class<?> loadClass() throws OrmException { try { return Class.forName(implClassName, false, classLoader); } catch (ClassNotFoundException err) { throw new OrmException("Cannot load generated class", err); } } private void init() { superTypeName = Type.getInternalName(JdbcAccess.class); implClassName = model.getEntityTypeClassName() + "_Access_" + model.getMethodName() + "_" + Util.createRandomName(); implTypeName = implClassName.replace('.', '/'); cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); cw.visit(V1_3, ACC_PUBLIC | ACC_FINAL | ACC_SUPER, implTypeName, null, superTypeName, new String[] { model.getAccessInterfaceName().replace('.', '/') }); } private void implementConstructor() { final String consName = "<init>"; final String consDesc = Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.getType(JdbcSchema.class) }); final MethodVisitor mv; mv = cw.visitMethod(ACC_PUBLIC, consName, consDesc, null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitMethodInsn(INVOKESPECIAL, superTypeName, consName, consDesc); mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementGetString(final String methodName, final String returnValue) { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, methodName, Type.getMethodDescriptor(Type.getType(String.class), new Type[] {}), null, null); mv.visitCode(); mv.visitLdcInsn(returnValue); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementGetRelationID() { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "getRelationID", Type.getMethodDescriptor(Type.INT_TYPE, new Type[] {}), null, null); mv.visitCode(); new CodeGenSupport(mv).push(model.getRelationID()); mv.visitInsn(IRETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementMissingGetString(final String methodName, final String why) { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, methodName, Type.getMethodDescriptor(Type.getType(String.class), new Type[] {}), null, null); mv.visitCode(); throwUnsupported(mv, model.getMethodName() + " does not support " + why); mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void throwUnsupported(final MethodVisitor mv, final String message) { final Type eType = Type.getType(UnsupportedOperationException.class); mv.visitTypeInsn(NEW, eType.getInternalName()); mv.visitInsn(DUP); mv.visitLdcInsn(message); mv.visitMethodInsn(INVOKESPECIAL, eType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.getType(String.class) })); mv.visitInsn(ATHROW); } private void implementPrimaryKey() { final KeyModel pk = model.getPrimaryKey(); final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "primaryKey", Type.getMethodDescriptor(Type.getType(Key.class), new Type[] { Type.getType(Object.class) }), null, null); mv.visitCode(); if (pk != null && pk.getField().isNested()) { final ColumnModel pkf = pk.getField(); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, entityType.getInternalName()); mv.visitFieldInsn(GETFIELD, entityType.getInternalName(), pkf.getFieldName(), CodeGenSupport.toType(pkf).getDescriptor()); } else { mv.visitInsn(ACONST_NULL); } mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementGetOne() { final KeyModel pk = model.getPrimaryKey(); final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "get", Type.getMethodDescriptor(Type.getType(Object.class), new Type[] { Type.getType(Key.class) }), null, new String[] { Type.getType(OrmException.class).getInternalName() }); mv.visitCode(); if (pk != null && pk.getField().isNested()) { final Type keyType = CodeGenSupport.toType(pk.getField()); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); mv.visitTypeInsn(CHECKCAST, keyType.getInternalName()); mv.visitMethodInsn(INVOKEVIRTUAL, implTypeName, pk.getName(), Type.getMethodDescriptor(entityType, new Type[] { keyType })); mv.visitInsn(ARETURN); } else { throwUnsupported(mv, model.getMethodName() + " does not support get(Key)"); } mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementNewEntityInstance() { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "newEntityInstance", Type.getMethodDescriptor(Type.getType(Object.class), new Type[] {}), null, null); mv.visitCode(); mv.visitTypeInsn(NEW, entityType.getInternalName()); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, entityType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementBindOne(final DmlType type) { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, type.methodName, Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.getType(PreparedStatement.class), Type.getType(Object.class) }), null, new String[] { Type.getType(SQLException.class).getInternalName() }); mv.visitCode(); if (type != DmlType.INSERT && model.getPrimaryKey() == null) { throwUnsupported(mv, model.getMethodName() + " has no primary key"); mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } mv.visitVarInsn(ALOAD, 2); mv.visitTypeInsn(CHECKCAST, entityType.getInternalName()); mv.visitVarInsn(ASTORE, 2); final CodeGenSupport cgs = new CodeGenSupport(mv); cgs.setEntityType(entityType); for (final ColumnModel col : model.getRowVersionColumns()) { cgs.setFieldReference(col); cgs.fieldSetBegin(); cgs.pushFieldValue(); mv.visitInsn(ICONST_1); mv.visitInsn(IADD); cgs.fieldSetEnd(); } cgs.resetColumnIndex(0); if (type != DmlType.DELETE) { final List<ColumnModel> cols = new ArrayList<ColumnModel>(); cols.addAll(model.getDependentFields()); cols.addAll(model.getRowVersionFields()); for (final ColumnModel field : cols) { doBindOne(mv, cgs, field); } } for (final ColumnModel col : model.getPrimaryKeyColumns()) { cgs.setFieldReference(col); dialect.getSqlTypeInfo(col).generatePreparedStatementSet(cgs); } if (type != DmlType.INSERT) { for (final ColumnModel col : model.getRowVersionColumns()) { cgs.setFieldReference(col); cgs.pushSqlHandle(); cgs.pushColumnIndex(); cgs.pushFieldValue(); mv.visitInsn(ICONST_1); mv.visitInsn(ISUB); cgs.invokePreparedStatementSet("Int"); } } mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void doBindOne(final MethodVisitor mv, final CodeGenSupport cgs, final ColumnModel field) { if (field.isNested() && field.isNotNull()) { for (final ColumnModel c : field.getAllLeafColumns()) { doBindOne(mv, cgs, c); } } else if (field.isNested()) { final int colIdx = cgs.getColumnIndex(); final Label isnull = new Label(); final Label end = new Label(); cgs.setFieldReference(field); cgs.pushFieldValue(); mv.visitJumpInsn(IFNULL, isnull); cgs.resetColumnIndex(colIdx); for (final ColumnModel c : field.getNestedColumns()) { doBindOne(mv, cgs, c); } mv.visitJumpInsn(GOTO, end); mv.visitLabel(isnull); cgs.resetColumnIndex(colIdx); for (final ColumnModel c : field.getAllLeafColumns()) { cgs.setFieldReference(c); dialect.getSqlTypeInfo(c).generatePreparedStatementNull(cgs); } mv.visitLabel(end); } else { cgs.setFieldReference(field); dialect.getSqlTypeInfo(field).generatePreparedStatementSet(cgs); } } private void implementBindOneFetch() { final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "bindOneFetch", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.getType(ResultSet.class), Type.getType(Object.class) }), null, new String[] { Type.getType(SQLException.class).getInternalName() }); mv.visitCode(); mv.visitVarInsn(ALOAD, 2); mv.visitTypeInsn(CHECKCAST, entityType.getInternalName()); mv.visitVarInsn(ASTORE, 2); final CodeGenSupport cgs = new CodeGenSupport(mv); cgs.setEntityType(entityType); if (model.getPrimaryKey() != null && model.getPrimaryKey().getField().isNested()) { final ColumnModel pkf = model.getPrimaryKey().getField(); final Type vType = CodeGenSupport.toType(pkf); final int oldIdx = cgs.getColumnIndex(); cgs.setFieldReference(pkf); cgs.fieldSetBegin(); mv.visitTypeInsn(NEW, vType.getInternalName()); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, vType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); cgs.fieldSetEnd(); cgs.resetColumnIndex(oldIdx); } final List<ColumnModel> cols = new ArrayList<ColumnModel>(); cols.addAll(model.getDependentFields()); cols.addAll(model.getRowVersionFields()); cols.addAll(model.getPrimaryKeyColumns()); for (final ColumnModel field : cols) { doFetchOne(mv, cgs, field, -1); } mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void doFetchOne(final MethodVisitor mv, final CodeGenSupport cgs, final ColumnModel field, final int reportLiveInto) { if (field.isNested()) { int oldIdx = cgs.getColumnIndex(); final Type vType = CodeGenSupport.toType(field); final int livecnt; if (field.isNotNull()) { livecnt = -1; } else { livecnt = cgs.newLocal(); cgs.push(0); mv.visitVarInsn(ISTORE, livecnt); } cgs.setFieldReference(field); cgs.fieldSetBegin(); mv.visitTypeInsn(NEW, vType.getInternalName()); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, vType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] {})); cgs.fieldSetEnd(); cgs.resetColumnIndex(oldIdx); for (final ColumnModel c : field.getNestedColumns()) { doFetchOne(mv, cgs, c, livecnt); } if (livecnt >= 0) { oldIdx = cgs.getColumnIndex(); final Label islive = new Label(); mv.visitVarInsn(ILOAD, livecnt); mv.visitJumpInsn(IFNE, islive); cgs.setFieldReference(field); cgs.fieldSetBegin(); mv.visitInsn(ACONST_NULL); cgs.fieldSetEnd(); if (reportLiveInto >= 0) { final Label end = new Label(); mv.visitJumpInsn(GOTO, end); mv.visitLabel(islive); mv.visitIincInsn(reportLiveInto, 1); mv.visitLabel(end); } else { mv.visitLabel(islive); } cgs.resetColumnIndex(oldIdx); cgs.freeLocal(livecnt); } } else { final int dupTo; if (reportLiveInto >= 0 && CodeGenSupport.toType(field).getSort() == Type.OBJECT) { dupTo = cgs.newLocal(); } else { dupTo = -1; } cgs.setFieldReference(field); cgs.setDupOnFieldSetEnd(dupTo); dialect.getSqlTypeInfo(field).generateResultSetGet(cgs); if (reportLiveInto >= 0) { final Label wasnull = new Label(); if (dupTo >= 0) { mv.visitVarInsn(ALOAD, dupTo); mv.visitJumpInsn(IFNULL, wasnull); cgs.freeLocal(dupTo); } else { cgs.pushSqlHandle(); mv.visitMethodInsn(INVOKEINTERFACE, Type.getType(ResultSet.class).getInternalName(), "wasNull", Type.getMethodDescriptor(Type.BOOLEAN_TYPE, new Type[] {})); mv.visitJumpInsn(IFNE, wasnull); } mv.visitIincInsn(reportLiveInto, 1); mv.visitLabel(wasnull); } } } private void implementKeyQuery(final KeyModel info) { final Type keyType = CodeGenSupport.toType(info.getField()); final StringBuilder query = new StringBuilder(); query.append(model.getSelectSql(dialect, REL_ALIAS)); query.append(" WHERE "); int nth = 1; for (final Iterator<ColumnModel> i = info.getAllLeafColumns().iterator(); i.hasNext();) { final ColumnModel c = i.next(); query.append(REL_ALIAS); query.append('.'); query.append(c.getColumnName()); query.append('='); query.append(dialect.getParameterPlaceHolder(nth++)); if (i.hasNext()) { query.append(" AND "); } } final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, info.getName(), Type.getMethodDescriptor(entityType, new Type[] { keyType }), null, new String[] { Type.getType(OrmException.class).getInternalName() }); mv.visitCode(); final int keyvar = 1, psvar = keyvar + keyType.getSize(); mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn(query.toString()); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "prepareStatement", Type.getMethodDescriptor( Type.getType(PreparedStatement.class), new Type[] { Type.getType(String.class) })); mv.visitVarInsn(ASTORE, psvar); final CodeGenSupport cgs = new CodeGenSupport(mv) { @Override public void pushSqlHandle() { mv.visitVarInsn(ALOAD, psvar); } @Override public void pushFieldValue() { appendGetField(getFieldReference()); } @Override protected void appendGetField(final ColumnModel c) { if (c.getParent() == null) { loadVar(keyType, keyvar); } else { super.appendGetField(c); } } }; for (final ColumnModel c : info.getAllLeafColumns()) { cgs.setFieldReference(c); dialect.getSqlTypeInfo(c).generatePreparedStatementSet(cgs); } mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, psvar); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "queryOne", Type.getMethodDescriptor( Type.getType(Object.class), new Type[] { Type.getType(PreparedStatement.class) })); mv.visitTypeInsn(CHECKCAST, entityType.getInternalName()); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void overrideGetMany() { final KeyModel pk = model.getPrimaryKey(); final StringBuilder query = new StringBuilder(); query.append(model.getSelectSql(dialect, REL_ALIAS)); query.append(" WHERE "); final ColumnModel pkcol = pk.getAllLeafColumns().iterator().next(); query.append(REL_ALIAS); query.append('.'); query.append(pkcol.getColumnName()); query.append(" IN"); final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, "getBySqlIn", Type.getMethodDescriptor(Type.getType(com.google.gwtorm.server.ResultSet.class), new Type[] { Type.getType(Collection.class) }), null, new String[] { Type.getType(OrmException.class).getInternalName() }); mv.visitCode(); final int keyset = 1; final int psvar = 2; final int itrvar = 3; final int colvar = 4; final int keyvar = 5; mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn(query.toString()); mv.visitVarInsn(ALOAD, keyset); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "prepareBySqlIn", Type.getMethodDescriptor(Type.getType(PreparedStatement.class), new Type[] { Type.getType(String.class), Type.getType(Collection.class) })); mv.visitVarInsn(ASTORE, psvar); mv.visitVarInsn(ALOAD, keyset); mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Collection.class), "iterator", Type.getMethodDescriptor(Type.getType(Iterator.class), new Type[] {})); mv.visitVarInsn(ASTORE, itrvar); mv.visitInsn(ICONST_1); mv.visitVarInsn(ISTORE, colvar); final Label endbind = new Label(); final Label again = new Label(); mv.visitLabel(again); mv.visitVarInsn(ALOAD, itrvar); mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Iterator.class), "hasNext", Type.getMethodDescriptor(Type.BOOLEAN_TYPE, new Type[] {})); mv.visitJumpInsn(IFEQ, endbind); mv.visitVarInsn(ALOAD, itrvar); mv.visitMethodInsn(INVOKEINTERFACE, Type.getInternalName(Iterator.class), "next", Type.getMethodDescriptor(Type.getType(Object.class), new Type[] {})); mv.visitTypeInsn(CHECKCAST, CodeGenSupport.toType(pk.getField()).getInternalName()); mv.visitVarInsn(ASTORE, keyvar); final CodeGenSupport cgs = new CodeGenSupport(mv) { @Override public void pushSqlHandle() { mv.visitVarInsn(ALOAD, psvar); } @Override public void pushFieldValue() { appendGetField(getFieldReference()); } @Override public void pushColumnIndex() { mv.visitVarInsn(ILOAD, colvar); } @Override protected void appendGetField(final ColumnModel c) { if (c.getParent() == null) { mv.visitVarInsn(ALOAD, keyvar); } else { super.appendGetField(c); } } }; cgs.setFieldReference(pkcol); dialect.getSqlTypeInfo(pkcol).generatePreparedStatementSet(cgs); mv.visitIincInsn(colvar, 1); mv.visitJumpInsn(GOTO, again); mv.visitLabel(endbind); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, psvar); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "queryList", Type.getMethodDescriptor(Type.getType(com.google.gwtorm.server.ResultSet.class), new Type[] { Type.getType(PreparedStatement.class) })); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } private void implementQuery(final QueryModel info) { final List<ColumnModel> pCols = info.getParameters(); final boolean hasLimitParam = info.hasLimitParameter(); final Type[] pTypes = new Type[pCols.size() + (hasLimitParam ? 1 : 0)]; final int[] pVars = new int[pTypes.length]; int nextVar = 1; for (int i = 0; i < pCols.size(); i++) { pTypes[i] = CodeGenSupport.toType(pCols.get(i)); pVars[i] = nextVar; nextVar += pTypes[i].getSize(); } if (hasLimitParam) { pTypes[pTypes.length - 1] = Type.INT_TYPE; pVars[pTypes.length - 1] = nextVar; nextVar += Type.INT_TYPE.getSize(); } final int psvar = nextVar++; final MethodVisitor mv = cw.visitMethod(ACC_PUBLIC | ACC_FINAL, info.getName(), Type.getMethodDescriptor(Type.getType(com.google.gwtorm.server.ResultSet.class), pTypes), null, new String[] { Type.getType(OrmException.class).getInternalName() }); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitLdcInsn(info.getSelectSql(dialect, REL_ALIAS)); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "prepareStatement", Type.getMethodDescriptor( Type.getType(PreparedStatement.class), new Type[] { Type.getType(String.class) })); mv.visitVarInsn(ASTORE, psvar); final int argIdx[] = new int[] { 0 }; final CodeGenSupport cgs = new CodeGenSupport(mv) { @Override public void pushSqlHandle() { mv.visitVarInsn(ALOAD, psvar); } @Override public void pushFieldValue() { appendGetField(getFieldReference()); } @Override protected void appendGetField(final ColumnModel c) { final int n = argIdx[0]; if (c == pCols.get(n)) { loadVar(pTypes[n], pVars[n]); } else { super.appendGetField(c); } } }; for (final ColumnModel c : pCols) { if (c.isNested()) { for (final ColumnModel n : c.getAllLeafColumns()) { cgs.setFieldReference(n); dialect.getSqlTypeInfo(n).generatePreparedStatementSet(cgs); } } else { cgs.setFieldReference(c); dialect.getSqlTypeInfo(c).generatePreparedStatementSet(cgs); } argIdx[0]++; } if (info.hasLimit()) { if (hasLimitParam || !dialect.selectHasLimit()) { mv.visitVarInsn(ALOAD, psvar); if (hasLimitParam) { mv.visitVarInsn(ILOAD, pVars[pTypes.length - 1]); } else { cgs.push(info.getStaticLimit()); } mv.visitMethodInsn(INVOKEINTERFACE, Type.getType(PreparedStatement.class).getInternalName(), "setMaxRows", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[] { Type.INT_TYPE })); } } mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, psvar); mv.visitMethodInsn(INVOKEVIRTUAL, superTypeName, "queryList", Type.getMethodDescriptor(Type.getType(com.google.gwtorm.server.ResultSet.class), new Type[] { Type.getType(PreparedStatement.class) })); mv.visitInsn(ARETURN); mv.visitMaxs(-1, -1); mv.visitEnd(); } }