Example #1
0
  /**
   * @param args
   * @return
   */
  @JRubyMethod(optional = 1, rest = true)
  public IRubyObject execute_non_query(IRubyObject[] args) {
    Ruby runtime = getRuntime();
    Connection connection_instance = (Connection) api.getInstanceVariable(this, "@connection");
    java.sql.Connection conn = connection_instance.getInternalConnection();
    checkConnectionNotClosed(conn);

    IRubyObject insert_key = runtime.getNil();
    RubyClass resultClass = Result.createResultClass(runtime, driver);
    // affectedCount == 1 means 1 updated row
    // or 1 row in result set that represents returned key (insert...returning),
    // other values represents number of updated rows
    int affectedCount = 0;
    PreparedStatement sqlStatement = null;
    // if usePreparedStatement returns false
    Statement sqlSimpleStatement = null;
    java.sql.ResultSet keys = null;

    // String sqlText = prepareSqlTextForPs(api.getInstanceVariable(recv,
    // "@text").asJavaString(), recv, args);
    String doSqlText =
        api.convertToRubyString(api.getInstanceVariable(this, "@text")).getUnicodeValue();
    String sqlText = prepareSqlTextForPs(doSqlText, args);

    // additional callback for driver specific SQL statement changes
    sqlText = driver.prepareSqlTextForPs(sqlText, args);

    boolean usePS = usePreparedStatement(sqlText, args);
    boolean hasReturnParam = false;

    try {
      if (usePS) {
        if (driver.supportsConnectionPrepareStatementMethodWithGKFlag()) {
          sqlStatement =
              conn.prepareStatement(
                  sqlText,
                  driver.supportsJdbcGeneratedKeys()
                      ? Statement.RETURN_GENERATED_KEYS
                      : Statement.NO_GENERATED_KEYS);
        } else {
          // If java.sql.PreparedStatement#getGeneratedKeys() is not supported,
          // then it is important to call java.sql.Connection#prepareStatement(String)
          // -- with just a single parameter -- rather java.sql.Connection#
          // prepareStatement(String, int) (and passing in Statement.NO_GENERATED_KEYS).
          // Some less-than-complete JDBC drivers do not implement all of
          // the overloaded prepareStatement methods: the main culprit
          // being SQLiteJDBC which currently throws an ugly (and cryptic)
          // "NYI" SQLException if Connection#prepareStatement(String, int)
          // is called.
          sqlStatement = conn.prepareStatement(sqlText);
        }

        hasReturnParam = prepareStatementFromArgs(sqlText, sqlStatement, args);
      } else {
        sqlSimpleStatement = conn.createStatement();
      }

      long startTime = System.currentTimeMillis();
      if (usePS) {
        boolean hasResult = sqlStatement.execute();
        if (hasResult) {
          keys = sqlStatement.getResultSet();
        } else {
          affectedCount = sqlStatement.getUpdateCount();
        }
      } else {
        sqlSimpleStatement.execute(sqlText);
      }
      long endTime = System.currentTimeMillis();

      if (usePS) debug(driver.statementToString(sqlStatement), Long.valueOf(endTime - startTime));
      else debug(sqlText, Long.valueOf(endTime - startTime));

      if (usePS && keys == null) {
        if (driver.supportsJdbcGeneratedKeys()) {
          // Derby, H2, and MySQL all support getGeneratedKeys(), but only
          // to varying extents.
          //
          // However, javaConn.getMetaData().supportsGetGeneratedKeys()
          // currently returns FALSE for the Derby driver, as its support
          // is limited. As such, we use supportsJdbcGeneratedKeys() from
          // our own driver definition.
          //
          // See http://issues.apache.org/jira/browse/DERBY-242
          // See http://issues.apache.org/jira/browse/DERBY-2631
          // (Derby only supplies getGeneratedKeys() for auto-incremented
          // columns)
          //

          // apparently the prepared statements always provide the
          // generated keys
          keys = sqlStatement.getGeneratedKeys();

        } else if (hasReturnParam) {
          // Used in Oracle for INSERT ... RETURNING ... INTO ... statements
          insert_key = runtime.newFixnum(driver.getPreparedStatementReturnParam(sqlStatement));
        } else {
          // If there is no support, then a custom method can be defined
          // to return a ResultSet with keys
          keys = driver.getGeneratedKeys(conn);
        }
      }
      if (usePS && keys != null) {
        insert_key = unmarshal_id_result(keys);
        if (insert_key != runtime.getNil()) affectedCount = (affectedCount > 0) ? affectedCount : 1;
      }

    } catch (SQLException sqle) {
      throw Errors.newQueryError(runtime, driver, sqle, usePS ? sqlStatement : sqlSimpleStatement);
    } finally {
      if (usePS) {
        JDBCUtil.close(keys, sqlStatement);
      } else {
        JDBCUtil.close(keys, sqlSimpleStatement);
      }
      keys = null;
      sqlStatement = null;
      sqlSimpleStatement = null;
    }

    IRubyObject affected_rows = runtime.newFixnum(affectedCount);

    return api.callMethod(resultClass, "new", new IRubyObject[] {this, affected_rows, insert_key});
  }
Example #2
0
File: Command.java Project: gryn/do
  @JRubyMethod(optional = 1, rest = true)
  public static IRubyObject execute_non_query(IRubyObject recv, IRubyObject[] args) {
    Ruby runtime = recv.getRuntime();
    IRubyObject connection_instance = api.getInstanceVariable(recv, "@connection");
    IRubyObject wrapped_jdbc_connection =
        api.getInstanceVariable(connection_instance, "@connection");
    if (wrapped_jdbc_connection.isNil()) {
      throw DataObjectsUtils.newDriverError(
          runtime, errorName, "This connection has already been closed.");
    }
    java.sql.Connection conn = getConnection(wrapped_jdbc_connection);

    IRubyObject insert_key = runtime.getNil();
    RubyClass resultClass = Result.createResultClass(runtime, moduleName, errorName, driver);
    // affectedCount == 1 means 1 updated row
    // or 1 row in result set that represents returned key (insert...returning),
    // other values represents numer of updated rows
    int affectedCount = 0;
    PreparedStatement sqlStatement = null;
    java.sql.ResultSet keys = null;

    // String sqlText = prepareSqlTextForPs(api.getInstanceVariable(recv, "@text").asJavaString(),
    // recv, args);
    String doSqlText =
        api.convertToRubyString(api.getInstanceVariable(recv, "@text")).getUnicodeValue();
    String sqlText = prepareSqlTextForPs(doSqlText, recv, args);

    try {
      if (driver.supportsConnectionPrepareStatementMethodWithGKFlag()) {
        sqlStatement =
            conn.prepareStatement(
                sqlText,
                driver.supportsJdbcGeneratedKeys()
                    ? Statement.RETURN_GENERATED_KEYS
                    : Statement.NO_GENERATED_KEYS);
      } else {
        // If java.sql.PreparedStatement#getGeneratedKeys() is not supported,
        // then it is important to call java.sql.Connection#prepareStatement(String)
        // -- with just a single parameter -- rather java.sql.Connection#
        // prepareStatement(String, int) (and passing in Statement.NO_GENERATED_KEYS).
        // Some less-than-complete JDBC drivers do not implement all of
        // the overloaded prepareStatement methods: the main culprit
        // being SQLiteJDBC which currently throws an ugly (and cryptic)
        // "NYI" SQLException if Connection#prepareStatement(String, int)
        // is called.
        sqlStatement = conn.prepareStatement(sqlText);
      }

      prepareStatementFromArgs(sqlStatement, recv, args);

      // javaConn.setAutoCommit(true); // hangs with autocommit set to false
      // sqlStatement.setMaxRows();
      long startTime = System.currentTimeMillis();
      try {
        if (sqlText.contains("RETURNING")) {
          keys = sqlStatement.executeQuery();
        } else {
          affectedCount = sqlStatement.executeUpdate();
        }
      } catch (SQLException sqle) {
        // This is to handle the edge case of SELECT sleep(1):
        // an executeUpdate() will throw a SQLException if a SELECT
        // is passed, so we try the same query again with execute()
        affectedCount = 0;
        sqlStatement.execute();
      }
      long endTime = System.currentTimeMillis();

      debug(recv.getRuntime(), driver.toString(sqlStatement), Long.valueOf(endTime - startTime));

      if (keys == null) {
        if (driver.supportsJdbcGeneratedKeys()) {
          // Derby, H2, and MySQL all support getGeneratedKeys(), but only
          // to varying extents.
          //
          // However, javaConn.getMetaData().supportsGetGeneratedKeys()
          // currently returns FALSE for the Derby driver, as its support
          // is limited. As such, we use supportsJdbcGeneratedKeys() from
          // our own driver definition.
          //
          // See http://issues.apache.org/jira/browse/DERBY-242
          // See http://issues.apache.org/jira/browse/DERBY-2631
          // (Derby only supplies getGeneratedKeys() for auto-incremented
          // columns)
          //

          // apparently the prepared statements always provide the
          // generated keys
          keys = sqlStatement.getGeneratedKeys();

        } else {
          // If there is no support, then a custom method can be defined
          // to return a ResultSet with keys
          keys = driver.getGeneratedKeys(conn);
        }
      }
      if (keys != null) {
        insert_key = unmarshal_id_result(runtime, keys);
        affectedCount = (affectedCount > 0) ? affectedCount : 1;
      }

      // not needed as it will be closed in the finally clause
      //            sqlStatement.close();
      //            sqlStatement = null;
    } catch (SQLException sqle) {
      // TODO: log
      // sqle.printStackTrace();
      throw newQueryError(runtime, sqle, sqlStatement);
    } finally {
      if (sqlStatement != null) {
        try {
          sqlStatement.close();
        } catch (SQLException sqle2) {
        }
      }
    }

    // return nil if no updates are made
    if (affectedCount <= 0) {
      return runtime.getNil();
    }

    IRubyObject affected_rows = runtime.newFixnum(affectedCount);

    IRubyObject result =
        api.callMethod(resultClass, "new", new IRubyObject[] {recv, affected_rows, insert_key});
    return result;
  }