JDBC Databases offer a fairly uniform interface that does not change much based on the sub adapter.
Call the DATABASE_SETUP proc directly after initialization, so the object always uses sub adapter specific code. Also, raise an error immediately if the connection doesn’t have a uri, since JDBC requires one.
# File lib/sequel/adapters/jdbc.rb, line 158 158: def initialize(opts) 159: super 160: @connection_prepared_statements = {} 161: @connection_prepared_statements_mutex = Mutex.new 162: @convert_types = typecast_value_boolean(@opts.fetch(:convert_types, true)) 163: raise(Error, "No connection string specified") unless uri 164: 165: resolved_uri = jndi? ? get_uri_from_jndi : uri 166: 167: if match = /\Ajdbc:([^:]+)/.match(resolved_uri) and prok = DATABASE_SETUP[match[1].to_sym] 168: @driver = prok.call(self) 169: end 170: end
Execute the given stored procedure with the give name. If a block is given, the stored procedure should return rows.
# File lib/sequel/adapters/jdbc.rb, line 174 174: def call_sproc(name, opts = {}) 175: args = opts[:args] || [] 176: sql = "{call #{name}(#{args.map{'?'}.join(',')})}" 177: synchronize(opts[:server]) do |conn| 178: cps = conn.prepareCall(sql) 179: 180: i = 0 181: args.each{|arg| set_ps_arg(cps, arg, i+=1)} 182: 183: begin 184: if block_given? 185: yield log_yield(sql){cps.executeQuery} 186: else 187: case opts[:type] 188: when :insert 189: log_yield(sql){cps.executeUpdate} 190: last_insert_id(conn, opts) 191: else 192: log_yield(sql){cps.executeUpdate} 193: end 194: end 195: rescue NativeException, JavaSQL::SQLException => e 196: raise_error(e) 197: ensure 198: cps.close 199: end 200: end 201: end
Connect to the database using JavaSQL::DriverManager.getConnection.
# File lib/sequel/adapters/jdbc.rb, line 204 204: def connect(server) 205: opts = server_opts(server) 206: conn = if jndi? 207: get_connection_from_jndi 208: else 209: args = [uri(opts)] 210: args.concat([opts[:user], opts[:password]]) if opts[:user] && opts[:password] 211: begin 212: JavaSQL::DriverManager.setLoginTimeout(opts[:login_timeout]) if opts[:login_timeout] 213: JavaSQL::DriverManager.getConnection(*args) 214: rescue JavaSQL::SQLException, NativeException, StandardError => e 215: raise e unless driver 216: # If the DriverManager can't get the connection - use the connect 217: # method of the driver. (This happens under Tomcat for instance) 218: props = java.util.Properties.new 219: if opts && opts[:user] && opts[:password] 220: props.setProperty("user", opts[:user]) 221: props.setProperty("password", opts[:password]) 222: end 223: opts[:jdbc_properties].each{|k,v| props.setProperty(k.to_s, v)} if opts[:jdbc_properties] 224: begin 225: driver.new.connect(args[0], props) 226: raise(Sequel::DatabaseError, 'driver.new.connect returned nil: probably bad JDBC connection string') unless c 227: c 228: rescue JavaSQL::SQLException, NativeException, StandardError => e2 229: e.message << "\n#{e2.class.name}: #{e2.message}" 230: raise e 231: end 232: end 233: end 234: setup_connection(conn) 235: end
Execute the given SQL. If a block is given, if should be a SELECT statement or something else that returns rows.
# File lib/sequel/adapters/jdbc.rb, line 239 239: def execute(sql, opts={}, &block) 240: return call_sproc(sql, opts, &block) if opts[:sproc] 241: return execute_prepared_statement(sql, opts, &block) if [Symbol, Dataset].any?{|c| sql.is_a?(c)} 242: synchronize(opts[:server]) do |conn| 243: statement(conn) do |stmt| 244: if block 245: yield log_yield(sql){stmt.executeQuery(sql)} 246: else 247: case opts[:type] 248: when :ddl 249: log_yield(sql){stmt.execute(sql)} 250: when :insert 251: log_yield(sql) do 252: if requires_return_generated_keys? 253: stmt.executeUpdate(sql, JavaSQL::Statement.RETURN_GENERATED_KEYS) 254: else 255: stmt.executeUpdate(sql) 256: end 257: end 258: last_insert_id(conn, opts.merge(:stmt=>stmt)) 259: else 260: log_yield(sql){stmt.executeUpdate(sql)} 261: end 262: end 263: end 264: end 265: end
Execute the given DDL SQL, which should not return any values or rows.
# File lib/sequel/adapters/jdbc.rb, line 270 270: def execute_ddl(sql, opts={}) 271: execute(sql, {:type=>:ddl}.merge(opts)) 272: end
Execute the given INSERT SQL, returning the last inserted row id.
# File lib/sequel/adapters/jdbc.rb, line 276 276: def execute_insert(sql, opts={}) 277: execute(sql, {:type=>:insert}.merge(opts)) 278: end
Use the JDBC metadata to get the index information for the table.
# File lib/sequel/adapters/jdbc.rb, line 281 281: def indexes(table, opts={}) 282: m = output_identifier_meth 283: im = input_identifier_meth 284: schema, table = schema_and_table(table) 285: schema ||= opts[:schema] 286: schema = im.call(schema) if schema 287: table = im.call(table) 288: indexes = {} 289: metadata(:getIndexInfo, nil, schema, table, false, true) do |r| 290: next unless name = r[:column_name] 291: next if respond_to?(:primary_key_index_re, true) and r[:index_name] =~ primary_key_index_re 292: i = indexes[m.call(r[:index_name])] ||= {:columns=>[], :unique=>[false, 0].include?(r[:non_unique])} 293: i[:columns] << m.call(name) 294: end 295: indexes 296: end
Whether or not JNDI is being used for this connection.
# File lib/sequel/adapters/jdbc.rb, line 299 299: def jndi? 300: !!(uri =~ JNDI_URI_REGEXP) 301: end
All tables in this database
# File lib/sequel/adapters/jdbc.rb, line 304 304: def tables(opts={}) 305: get_tables('TABLE', opts) 306: end
The uri for this connection. You can specify the uri using the :uri, :url, or :database options. You don’t need to worry about this if you use Sequel.connect with the JDBC connectrion strings.
# File lib/sequel/adapters/jdbc.rb, line 312 312: def uri(opts={}) 313: opts = @opts.merge(opts) 314: ur = opts[:uri] || opts[:url] || opts[:database] 315: ur =~ /^\Ajdbc:/ ? ur : "jdbc:#{ur}" 316: end
All views in this database
# File lib/sequel/adapters/jdbc.rb, line 319 319: def views(opts={}) 320: get_tables('VIEW', opts) 321: end
Yield the native prepared statements hash for the given connection to the block in a thread-safe manner.
# File lib/sequel/adapters/jdbc.rb, line 327 327: def cps_sync(conn, &block) 328: @connection_prepared_statements_mutex.synchronize{yield(@connection_prepared_statements[conn] ||= {})} 329: end
Close given adapter connections, and delete any related prepared statements.
# File lib/sequel/adapters/jdbc.rb, line 332 332: def disconnect_connection(c) 333: @connection_prepared_statements_mutex.synchronize{@connection_prepared_statements.delete(c)} 334: c.close 335: end
Raise a disconnect error if the SQL state of the cause of the exception indicates so.
# File lib/sequel/adapters/jdbc.rb, line 338 338: def disconnect_error?(exception, opts) 339: cause = exception.respond_to?(:cause) ? exception.cause : exception 340: super || (cause.respond_to?(:getSQLState) && cause.getSQLState =~ /^08/) 341: end
Execute the prepared statement. If the provided name is a dataset, use that as the prepared statement, otherwise use it as a key to look it up in the prepared_statements hash. If the connection we are using has already prepared an identical statement, use that statement instead of creating another. Otherwise, prepare a new statement for the connection, bind the variables, and execute it.
# File lib/sequel/adapters/jdbc.rb, line 350 350: def execute_prepared_statement(name, opts={}) 351: args = opts[:arguments] 352: if Dataset === name 353: ps = name 354: name = ps.prepared_statement_name 355: else 356: ps = prepared_statement(name) 357: end 358: sql = ps.prepared_sql 359: synchronize(opts[:server]) do |conn| 360: if name and cps = cps_sync(conn){|cpsh| cpsh[name]} and cps[0] == sql 361: cps = cps[1] 362: else 363: log_yield("CLOSE #{name}"){cps[1].close} if cps 364: cps = log_yield("PREPARE#{" #{name}:" if name} #{sql}"){conn.prepareStatement(sql)} 365: cps_sync(conn){|cpsh| cpsh[name] = [sql, cps]} if name 366: end 367: i = 0 368: args.each{|arg| set_ps_arg(cps, arg, i+=1)} 369: msg = "EXECUTE#{" #{name}" if name}" 370: if ps.log_sql 371: msg << " (" 372: msg << sql 373: msg << ")" 374: end 375: begin 376: if block_given? 377: yield log_yield(msg, args){cps.executeQuery} 378: else 379: case opts[:type] 380: when :ddl 381: log_yield(msg, args){cps.execute} 382: when :insert 383: log_yield(msg, args){cps.executeUpdate} 384: last_insert_id(conn, opts.merge(:prepared=>true)) 385: else 386: log_yield(msg, args){cps.executeUpdate} 387: end 388: end 389: rescue NativeException, JavaSQL::SQLException => e 390: raise_error(e) 391: ensure 392: cps.close unless name 393: end 394: end 395: end
Gets the connection from JNDI.
# File lib/sequel/adapters/jdbc.rb, line 398 398: def get_connection_from_jndi 399: jndi_name = JNDI_URI_REGEXP.match(uri)[1] 400: JavaxNaming::InitialContext.new.lookup(jndi_name).connection 401: end
Backbone of the tables and views support.
# File lib/sequel/adapters/jdbc.rb, line 412 412: def get_tables(type, opts) 413: ts = [] 414: m = output_identifier_meth 415: metadata(:getTables, nil, nil, nil, [type].to_java(:string)){|h| ts << m.call(h[:table_name])} 416: ts 417: end
Gets the JDBC connection uri from the JNDI resource.
# File lib/sequel/adapters/jdbc.rb, line 404 404: def get_uri_from_jndi 405: conn = get_connection_from_jndi 406: conn.meta_data.url 407: ensure 408: conn.close if conn 409: end
Support Date objects used in bound variables
# File lib/sequel/adapters/jdbc.rb, line 420 420: def java_sql_date(date) 421: java.sql.Date.new(Time.local(date.year, date.month, date.day).to_i * 1000) 422: end
Support DateTime objects used in bound variables
# File lib/sequel/adapters/jdbc.rb, line 425 425: def java_sql_datetime(datetime) 426: ts = java.sql.Timestamp.new(Time.local(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec).to_i * 1000) 427: ts.setNanos((datetime.sec_fraction * (RUBY_VERSION >= '1.9.0' ? 1000000000 : 86400000000000)).to_i) 428: ts 429: end
Support fractional seconds for Time objects used in bound variables
# File lib/sequel/adapters/jdbc.rb, line 432 432: def java_sql_timestamp(time) 433: ts = java.sql.Timestamp.new(time.to_i * 1000) 434: ts.setNanos(RUBY_VERSION >= '1.9.0' ? time.nsec : time.usec * 1000) 435: ts 436: end
Alias the generic JDBC versions so they can be called directly later
Alias the generic JDBC version so it can be called directly later
By default, there is no support for determining the last inserted id, so return nil. This method should be overridden in sub adapters.
# File lib/sequel/adapters/jdbc.rb, line 447 447: def last_insert_id(conn, opts) 448: nil 449: end
Log the given SQL and then execute it on the connection, used by the transaction code.
# File lib/sequel/adapters/jdbc.rb, line 440 440: def log_connection_execute(conn, sql) 441: statement(conn){|s| log_yield(sql){s.execute(sql)}} 442: end
Yield the metadata for this database
# File lib/sequel/adapters/jdbc.rb, line 452 452: def metadata(*args, &block) 453: synchronize do |c| 454: result = c.getMetaData.send(*args) 455: begin 456: metadata_dataset.send(:process_result_set, result, &block) 457: ensure 458: result.close 459: end 460: end 461: end
This method determines whether or not to add Statement.RETURN_GENERATED_KEYS as an argument when inserting rows. Sub-adapters that require this should override this method.
# File lib/sequel/adapters/jdbc.rb, line 546 546: def requires_return_generated_keys? 547: false 548: end
Parse the table schema for the given table.
# File lib/sequel/adapters/jdbc.rb, line 503 503: def schema_parse_table(table, opts={}) 504: m = output_identifier_meth(opts[:dataset]) 505: im = input_identifier_meth(opts[:dataset]) 506: ds = dataset 507: schema, table = schema_and_table(table) 508: schema ||= opts[:schema] 509: schema = im.call(schema) if schema 510: table = im.call(table) 511: pks, ts = [], [] 512: metadata(:getPrimaryKeys, nil, schema, table) do |h| 513: next if schema_parse_table_skip?(h, schema) 514: pks << h[:column_name] 515: end 516: metadata(:getColumns, nil, schema, table, nil) do |h| 517: next if schema_parse_table_skip?(h, schema) 518: s = {:type=>schema_column_type(h[:type_name]), :db_type=>h[:type_name], :default=>(h[:column_def] == '' ? nil : h[:column_def]), :allow_null=>(h[:nullable] != 0), :primary_key=>pks.include?(h[:column_name]), :column_size=>h[:column_size], :scale=>h[:decimal_digits]} 519: if s[:db_type] =~ DECIMAL_TYPE_RE && s[:scale] == 0 520: s[:type] = :integer 521: end 522: ts << [m.call(h[:column_name]), s] 523: end 524: ts 525: end
Whether schema_parse_table should skip the given row when parsing the schema.
# File lib/sequel/adapters/jdbc.rb, line 529 529: def schema_parse_table_skip?(h, schema) 530: h[:table_schem] == 'INFORMATION_SCHEMA' 531: end
Java being java, you need to specify the type of each argument for the prepared statement, and bind it individually. This guesses which JDBC method to use, and hopefully JRuby will convert things properly for us.
# File lib/sequel/adapters/jdbc.rb, line 467 467: def set_ps_arg(cps, arg, i) 468: case arg 469: when Integer 470: cps.setLong(i, arg) 471: when Sequel::SQL::Blob 472: cps.setBytes(i, arg.to_java_bytes) 473: when String 474: cps.setString(i, arg) 475: when Float 476: cps.setDouble(i, arg) 477: when TrueClass, FalseClass 478: cps.setBoolean(i, arg) 479: when NilClass 480: cps.setString(i, nil) 481: when DateTime 482: cps.setTimestamp(i, java_sql_datetime(arg)) 483: when Date 484: cps.setDate(i, java_sql_date(arg)) 485: when Time 486: cps.setTimestamp(i, java_sql_timestamp(arg)) 487: when Java::JavaSql::Timestamp 488: cps.setTimestamp(i, arg) 489: when Java::JavaSql::Date 490: cps.setDate(i, arg) 491: else 492: cps.setObject(i, arg) 493: end 494: end
Return the connection. Used to do configuration on the connection object before adding it to the connection pool.
# File lib/sequel/adapters/jdbc.rb, line 498 498: def setup_connection(conn) 499: conn 500: end
Yield a new statement object, and ensure that it is closed before returning.
# File lib/sequel/adapters/jdbc.rb, line 534 534: def statement(conn) 535: stmt = conn.createStatement 536: yield stmt 537: rescue NativeException, JavaSQL::SQLException => e 538: raise_error(e) 539: ensure 540: stmt.close if stmt 541: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.