ruby-plsql 0.9.0 → 0.9.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e240a454b5016fb465baaff47830601ea5f06f9a0f4ed7f2e032e2e8027c8841
4
- data.tar.gz: 8209b0f8b037838e7be37578a396b8652855540abd6a0c2cbf226adfaf7a598e
3
+ metadata.gz: 8ce42b7f40a83d55130a51e1acae222dbb1361a7d4a43b712873e2cddae24571
4
+ data.tar.gz: 7cd295463301ff322ed0312cabd73f08337068a8b3b3c57e724a5dae8efb51a0
5
5
  SHA512:
6
- metadata.gz: af3ba3c7a782369e6e4f94afe467194f155fc961dc80e946ebbbaec07f48244169d33f1c0c387d6710752b7590f70c9cc5fb84bc21f8687b8c520d32ed09f557
7
- data.tar.gz: 2fe1c1fa55a48cc547a3f34f371aba37147c4d3c8efc2c34d104b42b8e250251f6d233d65c6fedba42855774ccf559d6aed4164f341823b5c6fbbbb605acb047
6
+ metadata.gz: '08dabe0856244a3b1e487df17664d996a204f026ce6c19c50dec721bcc42be7936ce41b90ddecfc7d2b798351e624df068602d8da4c1e091e1096f534d8b96c6'
7
+ data.tar.gz: 5b25be049a7575a74911028db9b82986a692af4aa895d1561e1de3600bcfd418429c969bb45832536782ef84c70cf60bb8549207470d0cac962203666f7c035d
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Build Status](https://travis-ci.com/rsim/ruby-plsql.svg?branch=master)](https://travis-ci.com/rsim/ruby-plsql)
1
+ [![Test](https://github.com/rsim/ruby-plsql/actions/workflows/test.yml/badge.svg)](https://github.com/rsim/ruby-plsql/actions/workflows/test.yml)
2
2
 
3
3
  ruby-plsql
4
4
  ==========
@@ -120,6 +120,22 @@ plsql.activerecord_class = ActiveRecord::Base
120
120
  and then you do not need to specify plsql.connection (this is also safer when ActiveRecord reestablishes connection to database).
121
121
 
122
122
 
123
+ ### JRuby JDBC connection:
124
+
125
+ When using JRuby, the `connect!` method with `:host` and `:database` options uses the thin-style service name syntax by default:
126
+
127
+ ```ruby
128
+ # Connects using service name syntax: jdbc:oracle:thin:@//localhost:1521/MYSERVICENAME
129
+ plsql.connect! username: "hr", password: "hr", host: "localhost", database: "MYSERVICENAME"
130
+ ```
131
+
132
+ If you need to connect using the legacy SID syntax (for Oracle databases older than 12c), prefix the database name with a colon:
133
+
134
+ ```ruby
135
+ # Connects using SID syntax: jdbc:oracle:thin:@localhost:1521:MYSID
136
+ plsql.connect! username: "hr", password: "hr", host: "localhost", database: ":MYSID"
137
+ ```
138
+
123
139
  ### Cheat Sheet:
124
140
 
125
141
  You may have a look at this [Cheat Sheet](http://cheatography.com/jgebal/cheat-sheets/ruby-plsql-cheat-sheet/) for instructions on how to use ruby-plsql
@@ -135,10 +151,10 @@ or include gem in Gemfile if using bundler.
135
151
 
136
152
  In addition install either ruby-oci8 (for MRI/YARV) or copy Oracle JDBC driver to $JRUBY_HOME/lib (for JRuby).
137
153
 
138
- If you are using MRI Ruby implementation then you need to install ruby-oci8 gem (version 2.0.x or 2.1.x)
154
+ If you are using MRI Ruby implementation then you need to install ruby-oci8 gem (version 2.1 or higher)
139
155
  as well as Oracle client, e.g. [Oracle Instant Client](http://www.oracle.com/technetwork/database/features/instant-client/index-097480.html).
140
156
 
141
- If you are using JRuby then you need to download latest [Oracle JDBC driver](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-112010-090769.html) - either ojdbc7.jar for Java 8 and 7, ojdbc6.jar for Java 6, 7, 8 or ojdbc5.jar for Java 5. You can refer [the support matrix](http://www.oracle.com/technetwork/database/enterprise-edition/jdbc-faq-090281.html#01_03) for details.
157
+ If you are using JRuby then you need to download the appropriate [Oracle JDBC driver](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html) for your Java version - ojdbc17.jar for Java 17+, ojdbc11.jar for Java 11+, ojdbc8.jar for Java 8+, ojdbc7.jar for Java 7, ojdbc6.jar for Java 6, or ojdbc5.jar for Java 5.
142
158
 
143
159
  And copy this file to one of these locations. JDBC driver will be searched in this order:
144
160
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.0
1
+ 0.9.9
@@ -1,23 +1,26 @@
1
+ ojdbc_jars = []
2
+
1
3
  begin
2
4
  require "java"
3
5
  require "jruby"
4
6
 
5
- # ojdbc6.jar or ojdbc5.jar file should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
7
+ # Oracle JDBC driver jar should be in JRUBY_HOME/lib or should be in ENV['PATH'] or load path
6
8
 
7
9
  java_version = java.lang.System.getProperty("java.version")
8
- ojdbc_jars = if java_version =~ /^1.5/
9
- %w(ojdbc5.jar)
10
- elsif java_version =~ /^1.6/
11
- %w(ojdbc6.jar)
12
- elsif java_version >= "1.7"
13
- # Oracle 11g client ojdbc6.jar is also compatible with Java 1.7
14
- # Oracle 12c client provides new ojdbc7.jar
15
- %w(ojdbc7.jar ojdbc6.jar)
10
+ java_major = if java_version =~ /^1\.(\d+)/
11
+ $1.to_i
16
12
  else
17
- []
13
+ java_version.to_i
18
14
  end
19
15
 
20
- if ENV_JAVA["java.class.path"] !~ Regexp.new(ojdbc_jars.join("|"))
16
+ ojdbc_jars << "ojdbc17.jar" if java_major >= 17
17
+ ojdbc_jars << "ojdbc11.jar" if java_major >= 11
18
+ ojdbc_jars << "ojdbc8.jar" if java_major >= 8
19
+ ojdbc_jars << "ojdbc7.jar" if java_major >= 7
20
+ ojdbc_jars << "ojdbc6.jar" if java_major >= 6
21
+ ojdbc_jars << "ojdbc5.jar" if java_major == 5
22
+
23
+ if ENV_JAVA["java.class.path"] !~ Regexp.union(ojdbc_jars)
21
24
  # On Unix environment variable should be PATH, on Windows it is sometimes Path
22
25
  env_path = (ENV["PATH"] || ENV["Path"] || "").split(File::PATH_SEPARATOR)
23
26
  # Look for JDBC driver at first in lib subdirectory (application specific JDBC file version)
@@ -25,7 +28,7 @@ begin
25
28
  ["./lib"].concat($LOAD_PATH).concat(env_path).detect do |dir|
26
29
  # check any compatible JDBC driver in the priority order
27
30
  ojdbc_jars.any? do |ojdbc_jar|
28
- if File.exists?(file_path = File.join(dir, ojdbc_jar))
31
+ if File.exist?(file_path = File.join(dir, ojdbc_jar))
29
32
  require file_path
30
33
  true
31
34
  end
@@ -33,29 +36,66 @@ begin
33
36
  end
34
37
  end
35
38
 
36
- java.sql.DriverManager.registerDriver Java::oracle.jdbc.OracleDriver.new
37
-
38
39
  # set tns_admin property from TNS_ADMIN environment variable
39
40
  if !java.lang.System.get_property("oracle.net.tns_admin") && ENV["TNS_ADMIN"]
40
41
  java.lang.System.set_property("oracle.net.tns_admin", ENV["TNS_ADMIN"])
41
42
  end
42
43
 
43
- rescue LoadError, NameError
44
+ rescue LoadError
44
45
  # JDBC driver is unavailable.
45
46
  raise LoadError, "ERROR: ruby-plsql could not load Oracle JDBC driver. Please install #{ojdbc_jars.empty? ? "Oracle JDBC" : ojdbc_jars.join(' or ') } library."
46
47
  end
47
48
 
48
49
  module PLSQL
49
50
  class JDBCConnection < Connection # :nodoc:
51
+ begin
52
+ ORACLE_DRIVER = Java::oracle.jdbc.OracleDriver.new
53
+ java.sql.DriverManager.registerDriver ORACLE_DRIVER
54
+ rescue NameError
55
+ raise LoadError, "ERROR: ruby-plsql could not load Oracle JDBC driver. " \
56
+ "Please install the appropriate Oracle JDBC driver. " \
57
+ "See https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html"
58
+ end
59
+
50
60
  def self.create_raw(params)
61
+ url = jdbc_connection_url(params)
62
+ conn = begin
63
+ java.sql.DriverManager.getConnection(url, params[:username], params[:password])
64
+ rescue Java::JavaSql::SQLException => e
65
+ raise unless e.message =~ /no suitable driver/i
66
+ # bypass DriverManager to work in cases where ojdbc*.jar
67
+ # is added to the load path at runtime and not on the
68
+ # system classpath
69
+ ORACLE_DRIVER.connect(url, java.util.Properties.new.tap do |props|
70
+ props.setProperty("user", params[:username])
71
+ props.setProperty("password", params[:password])
72
+ end)
73
+ end
74
+ conn.setAutoCommit(false)
75
+ new(conn)
76
+ end
77
+
78
+ def self.jdbc_connection_url(params)
51
79
  database = params[:database]
52
- url = if ENV["TNS_ADMIN"] && database && !params[:host] && !params[:url]
80
+ if ENV["TNS_ADMIN"] && database && database !~ %r{\A[:/]} && !params[:host] && !params[:url]
53
81
  "jdbc:oracle:thin:@#{database}"
54
82
  else
55
- database = ":#{database}" unless database.match(/^(\:|\/)/)
56
- params[:url] || "jdbc:oracle:thin:@#{params[:host] || 'localhost'}:#{params[:port] || 1521}#{database}"
83
+ return params[:url] if params[:url]
84
+
85
+ raise ArgumentError, "database or url option is required" if database.nil? || database.empty?
86
+
87
+ host = params[:host] || "localhost"
88
+ port = params[:port] || 1521
89
+
90
+ if database =~ /^:/
91
+ # SID syntax: jdbc:oracle:thin:@host:port:SID
92
+ "jdbc:oracle:thin:@#{host}:#{port}#{database}"
93
+ else
94
+ # service name syntax: jdbc:oracle:thin:@//host:port/service_name
95
+ database = "/#{database}" unless database =~ /^\//
96
+ "jdbc:oracle:thin:@//#{host}:#{port}#{database}"
97
+ end
57
98
  end
58
- new(java.sql.DriverManager.getConnection(url, params[:username], params[:password]))
59
99
  end
60
100
 
61
101
  def set_time_zone(time_zone = nil)
@@ -14,13 +14,9 @@ rescue LoadError
14
14
  raise LoadError, "ERROR: ruby-plsql could not load ruby-oci8 library. #{msg}"
15
15
  end
16
16
 
17
- require "plsql/oci8_patches"
18
-
19
17
  # check ruby-oci8 version
20
- required_oci8_version = [2, 0, 3]
21
- oci8_version_ints = OCI8::VERSION.scan(/\d+/).map { |s| s.to_i }
22
- if (oci8_version_ints <=> required_oci8_version) < 0
23
- raise LoadError, "ERROR: ruby-oci8 version #{OCI8::VERSION} is too old. Please install ruby-oci8 version #{required_oci8_version.join('.')} or later."
18
+ if Gem::Version.new(OCI8::VERSION) < Gem::Version.new("2.1.0")
19
+ raise LoadError, "ERROR: ruby-oci8 version #{OCI8::VERSION} is too old. Please install ruby-oci8 version 2.1.0 or later."
24
20
  end
25
21
 
26
22
  module PLSQL
@@ -361,7 +361,7 @@ module PLSQL
361
361
  WHERE t.OWNER = :owner AND t.type_name = :type_name AND t.package_name = :package_name
362
362
  AND ta.OWNER = t.owner AND ta.TYPE_NAME = t.TYPE_NAME AND ta.PACKAGE_NAME = t.PACKAGE_NAME
363
363
  ORDER BY attr_no",
364
- @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname]) do |r|
364
+ argument_metadata[:type_owner], argument_metadata[:type_name], argument_metadata[:type_subname]) do |r|
365
365
 
366
366
  attr_no, attr_name, attr_type_owner, attr_type_name, attr_type_package, attr_length, attr_precision, attr_scale, attr_char_used = r
367
367
 
@@ -391,12 +391,15 @@ module PLSQL
391
391
  when "TABLE", "VIEW"
392
392
  @schema.select_all(
393
393
  "SELECT column_id, column_name, data_type, data_length, data_precision, data_scale, char_length, char_used
394
- FROM ALL_TAB_COLS WHERE OWNER = :owner AND TABLE_NAME = :type_name
394
+ FROM ALL_TAB_COLUMNS WHERE OWNER = :owner AND TABLE_NAME = :type_name
395
395
  ORDER BY column_id",
396
- @schema_name, argument_metadata[:type_name]) do |r|
396
+ argument_metadata[:type_owner], argument_metadata[:type_name]) do |r|
397
397
 
398
398
  col_no, col_name, col_type_name, col_length, col_precision, col_scale, col_char_length, col_char_used = r
399
399
 
400
+ # remove precision (n) from data_type (returned for TIMESTAMPs and INTERVALs)
401
+ col_type_name = col_type_name.sub(/\(\d+\)/, "")
402
+
400
403
  fields[col_name.downcase.to_sym] = {
401
404
  position: col_no.to_i,
402
405
  data_type: col_type_name,
@@ -426,7 +429,7 @@ module PLSQL
426
429
  "SELECT elem_type_owner, elem_type_name, elem_type_package, length, precision, scale, char_used, index_by
427
430
  FROM ALL_PLSQL_COLL_TYPES t
428
431
  WHERE t.OWNER = :owner AND t.TYPE_NAME = :type_name AND t.PACKAGE_NAME = :package_name",
429
- @schema_name, argument_metadata[:type_name], argument_metadata[:type_subname])
432
+ argument_metadata[:type_owner], argument_metadata[:type_name], argument_metadata[:type_subname])
430
433
 
431
434
  elem_type_owner, elem_type_name, elem_type_package, elem_length, elem_precision, elem_scale, elem_char_used, index_by = r
432
435
 
@@ -460,13 +463,30 @@ module PLSQL
460
463
 
461
464
  if elem_type_package != nil
462
465
  element_metadata[:fields] = get_field_definitions(element_metadata)
466
+ elsif elem_type_name && elem_type_name =~ /\A(.+)%ROWTYPE\z/
467
+ # TABLE OF table%ROWTYPE: Oracle stores elem_type_name as "TABLE_NAME%ROWTYPE"
468
+ rowtype_table_name = $1
469
+ check_owner = elem_type_owner || @schema_name
470
+ object_type_row = @schema.select_first(
471
+ "SELECT object_type FROM ALL_OBJECTS WHERE owner = :owner AND object_name = :name AND object_type IN ('TABLE', 'VIEW')",
472
+ check_owner, rowtype_table_name)
473
+ if object_type_row
474
+ element_metadata[:type_owner] ||= check_owner
475
+ element_metadata[:type_name] = rowtype_table_name
476
+ element_metadata[:sql_type_name] = build_sql_type_name(check_owner, nil, rowtype_table_name)
477
+ element_metadata[:data_type] = "PL/SQL RECORD"
478
+ element_metadata[:type_object_type] = object_type_row[0]
479
+ element_metadata[:fields] = get_field_definitions(element_metadata)
480
+ else
481
+ raise ArgumentError, "Could not resolve #{check_owner}.#{rowtype_table_name} to a table or view for #{elem_type_name}"
482
+ end
463
483
  end
464
484
  when "TYPE"
465
485
  r = @schema.select_first(
466
486
  "SELECT elem_type_owner, elem_type_name, length, precision, scale, char_used
467
487
  FROM ALL_COLL_TYPES t
468
488
  WHERE t.owner = :owner AND t.TYPE_NAME = :type_name",
469
- @schema_name, argument_metadata[:type_name]
489
+ argument_metadata[:type_owner], argument_metadata[:type_name]
470
490
  )
471
491
  elem_type_owner, elem_type_name, elem_length, elem_precision, elem_scale, elem_char_used = r
472
492
 
data/lib/plsql/schema.rb CHANGED
@@ -41,7 +41,7 @@ module PLSQL
41
41
  # or
42
42
  #
43
43
  # plsql.connection = java.sql.DriverManager.getConnection(
44
- # "jdbc:oracle:thin:@#{database_host}:#{database_port}/#{database_service_name}",
44
+ # "jdbc:oracle:thin:@//#{database_host}:#{database_port}/#{database_service_name}",
45
45
  # database_user, database_password)
46
46
  #
47
47
  def connection=(conn)
@@ -99,12 +99,15 @@ module PLSQL
99
99
  @original_schema.default_timezone
100
100
  else
101
101
  @default_timezone ||
102
- # Use ActiveRecord default_timezone when ActiveRecord connection is used,
103
- # preferring the connection's activerecord_class so a subclass override
104
- # (available in AR < 8.0) is honored before falling back to the
105
- # module-level accessor (AR 7.0+; the only one in AR 8.0+).
106
- (@connection && (ar_class = @connection.activerecord_class) &&
107
- (ar_class.respond_to?(:default_timezone) ? ar_class.default_timezone : ActiveRecord.default_timezone)) ||
102
+ # Use ActiveRecord default_timezone when ActiveRecord connection is used.
103
+ # Prefer the module-level accessor (AR 7.0+; the only one in AR 8.0+) so
104
+ # that AR 7.0/7.1's deprecation warning for ActiveRecord::Base.default_timezone
105
+ # is not emitted. Fall back to the per-class accessor only on pre-7.0 AR,
106
+ # where ActiveRecord.default_timezone does not exist.
107
+ (@connection && @connection.activerecord_class &&
108
+ (ActiveRecord.respond_to?(:default_timezone) ?
109
+ ActiveRecord.default_timezone :
110
+ @connection.activerecord_class.default_timezone)) ||
108
111
  # default to local timezone
109
112
  :local
110
113
  end
@@ -9,7 +9,8 @@ module PLSQL
9
9
  AND type = 'PACKAGE'
10
10
  AND UPPER(text) LIKE :variable_name",
11
11
  override_schema_name || schema.schema_name, package, "%#{variable_upcase}%").each do |row|
12
- if row[0] =~ /^\s*#{variable_upcase}\s+(CONSTANT\s+)?([A-Z0-9_. %]+(\([\w\s,]+\))?)\s*(NOT\s+NULL)?\s*((:=|DEFAULT).*)?;\s*(--.*)?$/i
12
+ if row[0] =~ /^\s*#{variable_upcase}\s+(CONSTANT\s+)?([A-Z0-9_. %]+(\([\w\s,]+\))?)\s*(NOT\s+NULL)?\s*((:=|DEFAULT).*)?;\s*(--.*)?$/i ||
13
+ row[0] =~ /^\s*#{variable_upcase}\s+(CONSTANT\s+)?([A-Z0-9_. %]+(\([\w\s,]+\))?)\s*(NOT\s+NULL)?\s*(:=|DEFAULT)\s*$/i
13
14
  return new(schema, variable, package, $2.strip, override_schema_name)
14
15
  end
15
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-plsql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Raimonds Simanovskis
@@ -72,7 +72,7 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '2.1'
75
- type: :development
75
+ type: :runtime
76
76
  prerelease: false
77
77
  version_requirements: !ruby/object:Gem::Requirement
78
78
  requirements:
@@ -96,7 +96,6 @@ files:
96
96
  - lib/plsql/connection.rb
97
97
  - lib/plsql/helpers.rb
98
98
  - lib/plsql/jdbc_connection.rb
99
- - lib/plsql/oci8_patches.rb
100
99
  - lib/plsql/oci_connection.rb
101
100
  - lib/plsql/package.rb
102
101
  - lib/plsql/procedure.rb
@@ -1,25 +0,0 @@
1
- # apply TIMESTAMP fractional seconds patch to ruby-oci8 2.0.3
2
- # see http://rubyforge.org/forum/forum.php?thread_id=46576&forum_id=1078
3
- if OCI8::VERSION == "2.0.3" &&
4
- !OCI8::BindType::Util.method_defined?(:datetime_to_array_without_timestamp_patch)
5
-
6
- OCI8::BindType::Util.module_eval do
7
- alias :datetime_to_array_without_timestamp_patch :datetime_to_array
8
- def datetime_to_array(val, full)
9
- result = datetime_to_array_without_timestamp_patch(val, full)
10
- if result && result[6] == 0
11
- if val.respond_to? :nsec
12
- fsec = val.nsec
13
- elsif val.respond_to? :usec
14
- fsec = val.usec * 1000
15
- else
16
- fsec = 0
17
- end
18
- result[6] = fsec
19
- end
20
- result
21
- end
22
- private :datetime_to_array_without_timestamp_patch, :datetime_to_array
23
- end
24
-
25
- end