@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()));
  }
예제 #2
0
  @Override
  public final Result<R> fetch(int number) {
    // [#1157] This invokes listener.fetchStart(ctx), which has to be called
    // Before listener.resultStart(ctx)
    iterator();

    ResultImpl<R> result = new ResultImpl<R>(ctx.configuration(), fields);
    R record = null;

    ctx.result(result);
    listener.resultStart(ctx);

    for (int i = 0; i < number && ((record = iterator().next()) != null); i++) {
      result.addRecord(record);
    }

    ctx.result(result);
    listener.resultEnd(ctx);

    return result;
  }
예제 #3
0
  /**
   * Default implementation for query execution using a prepared statement. Subclasses may override
   * this method.
   */
  protected int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException {
    int result = 0;
    PreparedStatement stmt = ctx.statement();

    try {
      listener.executeStart(ctx);

      // [#1829] Statement.execute() is preferred over Statement.executeUpdate(), as
      // we might be executing plain SQL and returning results.
      if (!stmt.execute()) {
        result = stmt.getUpdateCount();
        ctx.rows(result);
      }

      listener.executeEnd(ctx);
      return result;
    }

    // [#3011] [#3054] Consume additional exceptions if there are any
    catch (SQLException e) {
      consumeExceptions(ctx.configuration(), stmt, e);
      throw e;
    }
  }
예제 #4
0
  @Override
  protected final int execute(ExecuteContext ctx, ExecuteListener listener) throws SQLException {
    if (returning.isEmpty()) {
      return super.execute(ctx, listener);
    } else {
      int result = 1;
      ResultSet rs;
      switch (ctx.configuration().dialect()) {

          // SQLite can select _rowid_ after the insert
        case SQLITE:
          {
            listener.executeStart(ctx);
            result = ctx.statement().executeUpdate();
            listener.executeEnd(ctx);

            DSLContext create =
                DSL.using(ctx.connection(), SQLDialect.SQLITE, ctx.configuration().settings());
            returned =
                create
                    .select(returning)
                    .from(getInto())
                    .where(rowid().equal(rowid().getDataType().convert(create.lastID())))
                    .fetchInto(getInto());

            return result;
          }

          // Sybase can select @@identity after the insert
          // TODO [#832] Fix this. This might be a driver issue. JDBC
          // Generated keys don't work with jconn3, but they seem to work
          // with jTDS (which is used for Sybase ASE integration)
        case CUBRID:
        case SYBASE:
          {
            listener.executeStart(ctx);
            result = ctx.statement().executeUpdate();
            listener.executeEnd(ctx);

            selectReturning(ctx.configuration(), create(ctx.configuration()).lastID());
            return result;
          }

          // Some dialects can only retrieve "identity" (AUTO_INCREMENT) values
          // Additional values have to be fetched explicitly
          // [#1260] TODO CUBRID supports this, but there's a JDBC bug
        case ASE:
        case DERBY:
        case H2:
        case INGRES:
        case MYSQL:
        case SQLSERVER:
          {
            listener.executeStart(ctx);
            result = ctx.statement().executeUpdate();
            listener.executeEnd(ctx);

            rs = ctx.statement().getGeneratedKeys();

            try {
              List<Object> list = new ArrayList<Object>();

              // Some JDBC drivers seem to illegally return null
              // from getGeneratedKeys() sometimes
              if (rs != null) {
                while (rs.next()) {
                  list.add(rs.getObject(1));
                }
              }

              selectReturning(ctx.configuration(), list.toArray());
              return result;
            } finally {
              JDBCUtils.safeClose(rs);
            }
          }

          // Firebird and Postgres can execute the INSERT .. RETURNING
          // clause like a select clause. JDBC support is not implemented
          // in the Postgres JDBC driver
        case FIREBIRD:
        case POSTGRES:
          {
            listener.executeStart(ctx);
            rs = ctx.statement().executeQuery();
            listener.executeEnd(ctx);

            break;
          }

          // These dialects have full JDBC support
        case DB2:
        case HSQLDB:
        case ORACLE:
        default:
          {
            listener.executeStart(ctx);
            result = ctx.statement().executeUpdate();
            listener.executeEnd(ctx);

            rs = ctx.statement().getGeneratedKeys();
            break;
          }
      }

      ExecuteContext ctx2 = new DefaultExecuteContext(ctx.configuration());
      ExecuteListener listener2 = new ExecuteListeners(ctx2);

      ctx2.resultSet(rs);
      returned =
          new CursorImpl<R>(ctx2, listener2, fieldArray(returning), null, true, false)
              .fetch()
              .into(getInto());
      return result;
    }
  }
예제 #5
0
  @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;
          }
      }
    }
  }