Package do_oracle

Source Code of do_oracle.OracleDriverDefinition

package do_oracle;

import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URI;

import java.sql.Connection;
import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import oracle.jdbc.OraclePreparedStatement;
import oracle.jdbc.OracleTypes;

import java.util.Properties;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jruby.Ruby;
import org.jruby.runtime.builtin.IRubyObject;
import org.jruby.RubyString;

import data_objects.RubyType;
import data_objects.drivers.AbstractDriverDefinition;
import data_objects.util.JDBCUtil;

public class OracleDriverDefinition extends AbstractDriverDefinition {

    public final static String URI_SCHEME = "oracle";
    // . will be replaced with : in Connection.java before connection
    public final static String JDBC_URI_SCHEME = "oracle.thin";
    public final static String RUBY_MODULE_NAME = "Oracle";
    public final static String JDBC_DRIVER = "oracle.jdbc.OracleDriver";

    /**
     *
     */
    public OracleDriverDefinition() {
        super(URI_SCHEME, JDBC_URI_SCHEME, RUBY_MODULE_NAME, JDBC_DRIVER);
    }

    /**
     *
     * @param type
     * @param precision
     * @param scale
     * @return
     */
    @Override
    public RubyType jdbcTypeToRubyType(int type, int precision, int scale) {
        RubyType primitiveType;
        switch (type) {
        case OracleTypes.DATE:
            primitiveType = RubyType.TIME;
            break;
        case OracleTypes.TIMESTAMP:
        case OracleTypes.TIMESTAMPTZ:
        case OracleTypes.TIMESTAMPLTZ:
            primitiveType = RubyType.TIME;
            break;
        case OracleTypes.NUMBER:
            if (precision == 1 && scale == 0)
                primitiveType = RubyType.TRUE_CLASS;
            else if (precision > 1 && scale == 0)
                primitiveType = RubyType.INTEGER;
            else
                primitiveType = RubyType.BIG_DECIMAL;
            break;
        case OracleTypes.BINARY_FLOAT:
        case OracleTypes.BINARY_DOUBLE:
            primitiveType = RubyType.FLOAT;
            break;
        default:
            return super.jdbcTypeToRubyType(type, precision, scale);
        }
        return primitiveType;
    }

    /**
     *
     * @param runtime
     * @param rs
     * @param col
     * @param type
     * @return
     * @throws SQLException
     * @throws IOException
     */
    @Override
    public IRubyObject getTypecastResultSetValue(Ruby runtime,
            ResultSet rs, int col, RubyType type) throws SQLException,
            IOException {
        switch (type) {
        case TIME:
            switch (rs.getMetaData().getColumnType(col)) {
            case OracleTypes.DATE:
            case OracleTypes.TIMESTAMP:
            case OracleTypes.TIMESTAMPTZ:
            case OracleTypes.TIMESTAMPLTZ:
                java.sql.Timestamp dt = rs.getTimestamp(col);
                if (dt == null) {
                    return runtime.getNil();
                }
                return prepareRubyTimeFromSqlTime(runtime, sqlTimestampToDateTime(dt));
            default:
                String str = rs.getString(col);
                if (str == null) {
                    return runtime.getNil();
                }
                RubyString return_str = newUnicodeString(runtime, str);
                return_str.setTaint(true);
                return return_str;
            }
        default:
            return super.getTypecastResultSetValue(runtime, rs, col, type);
        }
    }

    /**
     *
     * @param ps
     * @param arg
     * @param idx
     * @throws SQLException
     */
    @Override
    public void setPreparedStatementParam(PreparedStatement ps,
            IRubyObject arg, int idx) throws SQLException {
        switch (RubyType.inferRubyType(arg)) {
        case NIL:
            ps.setNull(idx, Types.NULL);
            break;
        default:
            super.setPreparedStatementParam(ps, arg, idx);
        }
    }

    /**
     *
     * @param sqlText
     * @param ps
     * @param idx
     * @return
     * @throws SQLException
     */
    @Override
    public boolean registerPreparedStatementReturnParam(String sqlText, PreparedStatement ps, int idx) throws SQLException {
        OraclePreparedStatement ops = (OraclePreparedStatement) ps;
        Pattern p = Pattern.compile("^\\s*INSERT.+RETURNING.+INTO\\s+", Pattern.CASE_INSENSITIVE);
        Matcher m = p.matcher(sqlText);
        if (m.find()) {
            ops.registerReturnParameter(idx, Types.BIGINT);
            return true;
        }
        return false;
    }

    /**
     *
     * @param ps
     * @return
     * @throws SQLException
     */
    @Override
    public long getPreparedStatementReturnParam(PreparedStatement ps) throws SQLException {
        OraclePreparedStatement ops = (OraclePreparedStatement) ps;
        ResultSet rs = ops.getReturnResultSet();
        try {
            if (rs.next()) {
                // Assuming that primary key will not be larger as long max value
                return rs.getLong(1);
            }
            return 0;
        } finally {
            JDBCUtil.close(rs);
        }
    }

    /**
     *
     * @param sqlText
     * @param args
     * @return
     */
    @Override
    public String prepareSqlTextForPs(String sqlText, IRubyObject[] args) {
        String newSqlText = sqlText.replaceFirst(":insert_id", "?");
        return newSqlText;
    }

    /**
     *
     * @return
     */
    @Override
    public boolean supportsJdbcGeneratedKeys()
    {
        return false;
    }

    /**
     *
     * @return
     */
    @Override
    public boolean supportsJdbcScrollableResultSets() {
        // when set to true then getDouble and getBigDecimal is failing on BINARY_DOUBLE and BINARY_FLOAT columns
        return false;
    }

    /**
     *
     * @return
     */
    @Override
    public boolean supportsConnectionEncodings()
    {
        return false;
    }

    /**
     *
     * @return
     */
    @Override
    public Properties getDefaultConnectionProperties() {
        Properties props = new Properties();
        // Set prefetch rows to 100 to increase fetching performance SELECTs with many rows
        props.put("defaultRowPrefetch", "100");
        // TODO: should clarify if this is needed for faster performance
        // props.put("SetFloatAndDoubleUseBinary", "true");
        return props;
    }

    /**
     *
     * @param connectionUri
     * @return
     */
    @Override
    public String getJdbcUri(URI connectionUri) {
      String jdbcUri = connectionUri.toString();
      if (jdbcUri.contains("@")) {
          jdbcUri = connectionUri.toString().replaceFirst("://.*@", "://");
      }

      // Replace . with : in scheme name - necessary for Oracle scheme oracle:thin
      // : cannot be used in JDBC_URI_SCHEME as then it is identified as opaque URI
      jdbcUri = jdbcUri.replaceFirst("^([a-z]+)(\\.)", "$1:");

      // Replace :// with :@// as @ is required in Oracle JDBC connect string
      jdbcUri = jdbcUri.replaceFirst("://", ":@//");

      // Remove options after ?
      jdbcUri = jdbcUri.replaceFirst("\\?.*$", "");

      if (!jdbcUri.startsWith("jdbc:")) {
          jdbcUri = "jdbc:" + jdbcUri;
      }
      return jdbcUri;
    }

    /**
     *
     * @param doConn
     * @param conn
     * @param query
     * @throws SQLException
     */
    @Override
    public void afterConnectionCallback(IRubyObject doConn, Connection conn, Map<String, String> query)
            throws SQLException {
        exec(conn, "alter session set nls_date_format = 'YYYY-MM-DD HH24:MI:SS'");
        exec(conn, "alter session set nls_timestamp_format = 'YYYY-MM-DD HH24:MI:SS.FF'");
        exec(conn, "alter session set nls_timestamp_tz_format = 'YYYY-MM-DD HH24:MI:SS.FF TZH:TZM'");
        String time_zone = null;
        if (query != null)
            time_zone = query.get("time_zone");
        if (time_zone == null)
            time_zone = System.getenv("TZ");
        if (time_zone != null)
            exec(conn, "alter session set time_zone = '"+time_zone+"'");
    }

    /**
     *
     * @param s
     * @return
     */
    @Override
    public String statementToString(Statement s) {
        // String sqlText = ((oracle.jdbc.driver.OraclePreparedStatement) s).getOriginalSql();
        // in ojdbc5 need to retrieve statement field at first
        Statement s2 = (Statement) getFieldValue(s, "statement");
        if (s2 == null)
            s2 = s;
        String sqlText = (String) getFieldValue(getFieldValue(s2, "sqlObject"), "originalSql");
        // ParameterMetaData md = ps.getParameterMetaData();
        return sqlText;
    }

    /**
     *
     * @param obj
     * @param field
     * @return
     */
    private Object getFieldValue(Object obj, String field) {
        Class c = obj.getClass();
        while (c != null) {
            try {
                Field f = c.getDeclaredField(field);
                f.setAccessible(true);
                return f.get(obj);
            } catch (NoSuchFieldException e) {
                c = c.getSuperclass();
            } catch (IllegalAccessException e) {
                return null;
            }
        }
        return null;
    }

    /**
     *  For execution of session initialization SQL statements
     *
     * @param conn
     * @param sql
     * @throws SQLException
     */
    private void exec(Connection conn, String sql)
            throws SQLException {
        Statement s = null;
        try {
            s = conn.createStatement();
            s.execute(sql);
        } finally {
            JDBCUtil.close(s);
        }
    }

}
TOP

Related Classes of do_oracle.OracleDriverDefinition

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.