private final int[] executePrepared() { ExecuteContext ctx = new DefaultExecuteContext(configuration, new Query[] {query}); ExecuteListener listener = new ExecuteListeners(ctx); Connection connection = ctx.connection(); // [#1371] fetch bind variables to restore them again, later DataType<?>[] paramTypes = dataTypes(query.getParams().values().toArray(new Field[0])); try { listener.renderStart(ctx); // [#1520] TODO: Should the number of bind values be checked, here? ctx.sql(create.render(query)); listener.renderEnd(ctx); listener.prepareStart(ctx); ctx.statement(connection.prepareStatement(ctx.sql())); listener.prepareEnd(ctx); for (Object[] bindValues : allBindValues) { listener.bindStart(ctx); // [#1371] [#2139] Don't bind variables directly onto statement, bind them through the // collected params // list to preserve type information // [#3547] The original query may have no Params specified - e.g. when it was // constructed with // plain SQL. In that case, infer the bind value type directly from the bind // value List<Field<?>> params = (paramTypes.length > 0) ? fields(bindValues, paramTypes) : fields(bindValues); visitAll(new DefaultBindContext(configuration, ctx.statement()), params); listener.bindEnd(ctx); ctx.statement().addBatch(); } try { listener.executeStart(ctx); int[] result = ctx.statement().executeBatch(); int[] batchRows = ctx.batchRows(); for (int i = 0; i < batchRows.length && i < result.length; i++) batchRows[i] = result[i]; listener.executeEnd(ctx); return result; } finally { consumeWarnings(ctx, listener); } } catch (RuntimeException e) { ctx.exception(e); listener.exception(ctx); throw ctx.exception(); } catch (SQLException e) { ctx.sqlException(e); listener.exception(ctx); throw ctx.exception(); } finally { Utils.safeClose(listener, ctx); } }