@Override protected final void prepare(ExecuteContext ctx) throws SQLException { // [#1296] These dialects do not implement FOR UPDATE. But the same // effect can be achieved using ResultSet.CONCUR_UPDATABLE if (isForUpdate() && asList(CUBRID, SQLSERVER).contains(ctx.getDialect())) { ctx.statement( ctx.getConnection().prepareStatement(ctx.sql(), TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE)); } // Regular behaviour else { ctx.statement(ctx.getConnection().prepareStatement(ctx.sql())); } // [#1263] Allow for negative fetch sizes to support some non-standard // MySQL feature, where Integer.MIN_VALUE is used if (size != 0) { if (log.isDebugEnabled()) log.debug("Setting fetch size", size); ctx.statement().setFetchSize(size); } // [#1854] Set the max number of rows for this result query if (maxRows != 0) { ctx.statement().setMaxRows(maxRows); } }
private void checkSQL(ExecuteContext ctx, boolean patched) { assertTrue(ctx.batchSQL()[0].toLowerCase().contains("select")); assertTrue(ctx.sql().toLowerCase().contains("select")); assertEquals(ctx.sql(), ctx.batchSQL()[0]); if (patched) { assertTrue(ctx.sql().toLowerCase().contains("as my_field")); } }
@Override public void renderEnd(ExecuteContext ctx) { renderEnd = ++callbackCount; checkBase(ctx); checkSQL(ctx, false); assertNull(ctx.statement()); ctx.sql(ctx.sql().replaceFirst("(?i:values\\s+)", "values ")); checkSQL(ctx, true); }
@Override public void renderEnd(ExecuteContext ctx) { renderEnd = ++callbackCount; checkBase(ctx); checkSQL(ctx, false); assertNull(ctx.statement()); assertNull(ctx.resultSet()); assertNull(ctx.record()); assertNull(ctx.result()); ctx.sql(ctx.sql().replaceFirst("(?i:from)", "as my_field from")); checkSQL(ctx, true); }
@Override public void renderStart(ExecuteContext ctx) { renderStart.add(++callbackCount); checkBase(ctx); checkStatement(ctx, false); checkSQL(ctx, false); assertNull(ctx.sql()); }
@Override public void renderStart(ExecuteContext ctx) { renderStart = ++callbackCount; checkBase(ctx); assertNull(ctx.batchSQL()[0]); assertNull(ctx.sql()); assertNull(ctx.statement()); }
@Override public void exception(ExecuteContext ctx) { SQLDialect dialect = ctx.configuration().dialect(); SQLExceptionTranslator translator = (dialect != null) ? new SQLErrorCodeSQLExceptionTranslator(dialect.name()) : new SQLStateSQLExceptionTranslator(); ctx.exception(translator.translate("jOOQ", ctx.sql(), ctx.sqlException())); }
@Override public void start(ExecuteContext ctx) { start = ++callbackCount; checkBase(ctx); assertNull(ctx.batchSQL()[0]); assertNull(ctx.sql()); assertNull(ctx.statement()); assertNull(ctx.resultSet()); assertNull(ctx.record()); assertNull(ctx.result()); }
@Override protected final void prepare(ExecuteContext ctx) throws SQLException { Connection connection = ctx.connection(); // Just in case, always set Sybase ASE statement mode to return // Generated keys if client code wants to SELECT @@identity afterwards if (ctx.configuration().dialect() == SQLDialect.ASE) { ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS)); return; } // Normal statement preparing if no values should be returned else if (returning.isEmpty()) { super.prepare(ctx); return; } // Values should be returned from the INSERT else { switch (ctx.configuration().dialect()) { // Postgres uses the RETURNING clause in SQL case FIREBIRD: case POSTGRES: // SQLite will select last_insert_rowid() after the INSER case SQLITE: // Sybase will select @@identity after the INSERT case CUBRID: case SYBASE: super.prepare(ctx); return; // Some dialects can only return AUTO_INCREMENT values // Other values have to be fetched in a second step // [#1260] TODO CUBRID supports this, but there's a JDBC bug case ASE: case DERBY: case H2: case INGRES: case MYSQL: case SQLSERVER: ctx.statement(connection.prepareStatement(ctx.sql(), Statement.RETURN_GENERATED_KEYS)); return; // The default is to return all requested fields directly case DB2: case HSQLDB: case ORACLE: default: { List<String> names = new ArrayList<String>(); for (Field<?> field : returning) { names.add(field.getName()); } ctx.statement( connection.prepareStatement(ctx.sql(), names.toArray(new String[names.size()]))); return; } } } }
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); } }
@Override public void renderEnd(ExecuteContext ctx) { throw new QueryCollectorSignal(ctx.sql(), ctx.query()); }
/** Default implementation for preparing a statement. Subclasses may override this method. */ protected void prepare(ExecuteContext ctx) throws SQLException { ctx.statement(ctx.connection().prepareStatement(ctx.sql())); }
@Override public final int execute() { if (isExecutable()) { // Get the attached configuration of this query Configuration c = configuration(); // [#1191] The following triggers a start event on all listeners. // This may be used to provide jOOQ with a JDBC connection, // in case this Query / Configuration was previously // deserialised ExecuteContext ctx = new DefaultExecuteContext(c, this); ExecuteListener listener = new ExecuteListeners(ctx); int result = 0; try { if (ctx.connection() == null) { throw new DetachedException("Cannot execute query. No Connection configured"); } // [#385] If a statement was previously kept open if (keepStatement() && statement != null) { ctx.sql(sql); ctx.statement(statement); } // [#385] First time statement preparing else { listener.renderStart(ctx); ctx.sql(getSQL0(ctx)); listener.renderEnd(ctx); sql = ctx.sql(); listener.prepareStart(ctx); prepare(ctx); listener.prepareEnd(ctx); statement = ctx.statement(); } // [#1856] Set the query timeout onto the Statement if (timeout != 0) { ctx.statement().setQueryTimeout(timeout); } if ( // [#1145] Bind variables only for true prepared statements // [#2414] Even if parameters are inlined here, child // QueryParts may override this behaviour! executePreparedStatements(c.settings()) && // [#1520] Renderers may enforce static statements, too !Boolean.TRUE.equals(ctx.data(DATA_FORCE_STATIC_STATEMENT))) { listener.bindStart(ctx); using(c).bindContext(ctx.statement()).visit(this); listener.bindEnd(ctx); } result = execute(ctx, listener); return result; } catch (SQLException e) { ctx.sqlException(e); listener.exception(ctx); throw ctx.exception(); } finally { // [#2385] Successful fetchLazy() needs to keep open resources if (!keepResultSet() || ctx.exception() != null) { Utils.safeClose(listener, ctx, keepStatement()); } if (!keepStatement()) { statement = null; sql = null; } } } else { if (log.isDebugEnabled()) { log.debug("Query is not executable", this); } return 0; } }