ruby-plsql 0.5.3 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/stale.yml +37 -0
- data/.github/workflows/rubocop.yml +37 -0
- data/.github/workflows/test.yml +69 -0
- data/.rubocop.yml +147 -0
- data/.travis.yml +88 -0
- data/.travis/oracle/download.sh +15 -0
- data/.travis/oracle/install.sh +32 -0
- data/.travis/setup_accounts.sh +9 -0
- data/Gemfile +17 -9
- data/History.txt +76 -0
- data/README.md +29 -6
- data/Rakefile +31 -26
- data/VERSION +1 -1
- data/Vagrantfile +4 -4
- data/ci/network/admin/tnsnames.ora +7 -0
- data/ci/setup_accounts.sh +9 -0
- data/gemfiles/Gemfile.activerecord-5.0 +21 -0
- data/gemfiles/Gemfile.activerecord-5.1 +21 -0
- data/gemfiles/Gemfile.activerecord-5.2 +21 -0
- data/gemfiles/Gemfile.activerecord-6.0 +21 -0
- data/gemfiles/Gemfile.activerecord-6.1 +21 -0
- data/gemfiles/Gemfile.activerecord-main +21 -0
- data/lib/plsql/connection.rb +19 -22
- data/lib/plsql/helpers.rb +1 -3
- data/lib/plsql/jdbc_connection.rb +70 -68
- data/lib/plsql/oci8_patches.rb +2 -2
- data/lib/plsql/oci_connection.rb +62 -77
- data/lib/plsql/package.rb +61 -46
- data/lib/plsql/procedure.rb +358 -78
- data/lib/plsql/procedure_call.rb +508 -463
- data/lib/plsql/schema.rb +96 -101
- data/lib/plsql/sequence.rb +10 -13
- data/lib/plsql/sql_statements.rb +9 -11
- data/lib/plsql/table.rb +60 -63
- data/lib/plsql/type.rb +71 -76
- data/lib/plsql/variable.rb +90 -94
- data/lib/plsql/version.rb +1 -1
- data/lib/plsql/view.rb +16 -19
- data/ruby-plsql.gemspec +55 -35
- data/spec/plsql/connection_spec.rb +72 -66
- data/spec/plsql/package_spec.rb +63 -14
- data/spec/plsql/procedure_spec.rb +603 -261
- data/spec/plsql/schema_spec.rb +47 -23
- data/spec/plsql/sequence_spec.rb +2 -2
- data/spec/plsql/sql_statements_spec.rb +6 -6
- data/spec/plsql/table_spec.rb +84 -79
- data/spec/plsql/type_spec.rb +24 -30
- data/spec/plsql/variable_spec.rb +80 -88
- data/spec/plsql/version_spec.rb +4 -4
- data/spec/plsql/view_spec.rb +42 -42
- data/spec/spec_helper.rb +38 -35
- data/spec/support/create_arunit_user.sql +2 -0
- data/spec/support/custom_config.rb.sample +14 -0
- data/spec/support/test_db.rb +12 -13
- data/spec/support/unlock_and_setup_hr_user.sql +2 -0
- metadata +111 -34
data/lib/plsql/schema.rb
CHANGED
@@ -13,13 +13,13 @@ module PLSQL
|
|
13
13
|
@@schemas[connection_alias] = self.new
|
14
14
|
end
|
15
15
|
end
|
16
|
-
|
17
16
|
end
|
18
17
|
|
19
18
|
def initialize(raw_conn = nil, schema = nil, original_schema = nil) #:nodoc:
|
20
19
|
self.connection = raw_conn
|
21
20
|
@schema_name = schema ? schema.to_s.upcase : nil
|
22
21
|
@original_schema = original_schema
|
22
|
+
@dbms_output_stream = nil
|
23
23
|
end
|
24
24
|
|
25
25
|
# Returns connection wrapper object (this is not raw OCI8 or JDBC connection!)
|
@@ -35,7 +35,7 @@ module PLSQL
|
|
35
35
|
end
|
36
36
|
|
37
37
|
# Set connection to OCI8 or JDBC connection:
|
38
|
-
#
|
38
|
+
#
|
39
39
|
# plsql.connection = OCI8.new(database_user, database_password, database_name)
|
40
40
|
#
|
41
41
|
# or
|
@@ -90,7 +90,7 @@ module PLSQL
|
|
90
90
|
# Current Oracle schema name
|
91
91
|
def schema_name
|
92
92
|
return nil unless connection
|
93
|
-
@schema_name ||= select_first("SELECT SYS_CONTEXT('userenv','
|
93
|
+
@schema_name ||= select_first("SELECT SYS_CONTEXT('userenv','current_schema') FROM dual")[0]
|
94
94
|
end
|
95
95
|
|
96
96
|
# Default timezone to which database values will be converted - :utc or :local
|
@@ -131,9 +131,9 @@ module PLSQL
|
|
131
131
|
end
|
132
132
|
|
133
133
|
# Seet DBMS_OUTPUT buffer size (default is 20_000). Example:
|
134
|
-
#
|
134
|
+
#
|
135
135
|
# plsql.dbms_output_buffer_size = 100_000
|
136
|
-
#
|
136
|
+
#
|
137
137
|
def dbms_output_buffer_size=(value)
|
138
138
|
@dbms_output_buffer_size = value
|
139
139
|
end
|
@@ -142,9 +142,9 @@ module PLSQL
|
|
142
142
|
DBMS_OUTPUT_MAX_LINES = 2147483647
|
143
143
|
|
144
144
|
# Specify IO stream where to log DBMS_OUTPUT from PL/SQL procedures. Example:
|
145
|
-
#
|
145
|
+
#
|
146
146
|
# plsql.dbms_output_stream = STDOUT
|
147
|
-
#
|
147
|
+
#
|
148
148
|
def dbms_output_stream=(stream)
|
149
149
|
@dbms_output_stream = stream
|
150
150
|
if @dbms_output_stream.nil? && @connection
|
@@ -163,118 +163,113 @@ module PLSQL
|
|
163
163
|
|
164
164
|
private
|
165
165
|
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
166
|
+
def reset_instance_variables
|
167
|
+
if @connection
|
168
|
+
@schema_objects = {}
|
169
|
+
else
|
170
|
+
@schema_objects = nil
|
171
|
+
end
|
172
|
+
@schema_name = nil
|
173
|
+
@default_timezone = nil
|
171
174
|
end
|
172
|
-
@schema_name = nil
|
173
|
-
@default_timezone = nil
|
174
|
-
end
|
175
175
|
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
176
|
+
def method_missing(method, *args, &block)
|
177
|
+
raise ArgumentError, "No database connection" unless connection
|
178
|
+
# search in database if not in cache at first
|
179
|
+
object = (@schema_objects[method] ||= find_database_object(method) || find_other_schema(method) ||
|
180
|
+
find_public_synonym(method) || find_standard_procedure(method))
|
181
181
|
|
182
|
-
|
182
|
+
raise ArgumentError, "No database object '#{method.to_s.upcase}' found" unless object
|
183
183
|
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
184
|
+
if object.is_a?(Procedure)
|
185
|
+
object.exec(*args, &block)
|
186
|
+
elsif object.is_a?(Type) && !args.empty?
|
187
|
+
object.new(*args, &block)
|
188
|
+
else
|
189
|
+
object
|
190
|
+
end
|
190
191
|
end
|
191
|
-
end
|
192
192
|
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
"SELECT o.object_type, o.object_id
|
198
|
-
(CASE WHEN o.object_type = 'PACKAGE'
|
199
|
-
THEN (SELECT ob.status FROM all_objects ob
|
200
|
-
WHERE ob.owner = o.owner AND ob.object_name = o.object_name AND ob.object_type = 'PACKAGE BODY')
|
201
|
-
ELSE NULL END) body_status
|
193
|
+
def find_database_object(name, override_schema_name = nil)
|
194
|
+
object_schema_name = override_schema_name || schema_name
|
195
|
+
object_name = name.to_s.upcase
|
196
|
+
if row = select_first(
|
197
|
+
"SELECT o.object_type, o.object_id
|
202
198
|
FROM all_objects o
|
203
199
|
WHERE owner = :owner AND object_name = :object_name
|
204
200
|
AND object_type IN ('PROCEDURE','FUNCTION','PACKAGE','TABLE','VIEW','SEQUENCE','TYPE','SYNONYM')",
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
201
|
+
object_schema_name, object_name)
|
202
|
+
object_type, object_id = row
|
203
|
+
case object_type
|
204
|
+
when "PROCEDURE", "FUNCTION"
|
205
|
+
if (connection.database_version <=> [11, 1, 0, 0]) >= 0
|
206
|
+
if row = select_first(
|
207
|
+
"SELECT p.object_id FROM all_procedures p
|
208
|
+
WHERE p.owner = :owner
|
209
|
+
AND p.object_name = :object_name
|
210
|
+
AND p.object_type = :object_type",
|
211
|
+
object_schema_name, object_name, object_type)
|
212
|
+
object_id = row[0]
|
213
|
+
else
|
214
|
+
raise ArgumentError, "Database object '#{object_schema_name}.#{object_name}' is not in valid status\n#{
|
215
|
+
_errors(object_schema_name, object_name, object_type)}"
|
216
|
+
end
|
217
|
+
end
|
218
|
+
Procedure.new(self, name, nil, override_schema_name, object_id)
|
219
|
+
when "PACKAGE"
|
220
|
+
Package.new(self, name, override_schema_name)
|
221
|
+
when "TABLE"
|
222
|
+
Table.new(self, name, override_schema_name)
|
223
|
+
when "VIEW"
|
224
|
+
View.new(self, name, override_schema_name)
|
225
|
+
when "SEQUENCE"
|
226
|
+
Sequence.new(self, name, override_schema_name)
|
227
|
+
when "TYPE"
|
228
|
+
Type.new(self, name, override_schema_name)
|
229
|
+
when "SYNONYM"
|
230
|
+
target_schema_name, target_object_name = @connection.describe_synonym(object_schema_name, object_name)
|
231
|
+
find_database_object(target_object_name, target_schema_name)
|
221
232
|
end
|
222
|
-
Procedure.new(self, name, nil, override_schema_name, object_id)
|
223
|
-
when 'PACKAGE'
|
224
|
-
Package.new(self, name, override_schema_name)
|
225
|
-
when 'TABLE'
|
226
|
-
Table.new(self, name, override_schema_name)
|
227
|
-
when 'VIEW'
|
228
|
-
View.new(self, name, override_schema_name)
|
229
|
-
when 'SEQUENCE'
|
230
|
-
Sequence.new(self, name, override_schema_name)
|
231
|
-
when 'TYPE'
|
232
|
-
Type.new(self, name, override_schema_name)
|
233
|
-
when 'SYNONYM'
|
234
|
-
target_schema_name, target_object_name = @connection.describe_synonym(object_schema_name, object_name)
|
235
|
-
find_database_object(target_object_name, target_schema_name)
|
236
233
|
end
|
237
234
|
end
|
238
|
-
end
|
239
235
|
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
236
|
+
def _errors(object_schema_name, object_name, object_type)
|
237
|
+
result = ""
|
238
|
+
previous_line = 0
|
239
|
+
select_all(
|
240
|
+
"SELECT e.line, e.position, e.text error_text, s.text source_text
|
241
|
+
FROM all_errors e, all_source s
|
242
|
+
WHERE e.owner = :owner AND e.name = :name AND e.type = :type
|
243
|
+
AND s.owner = e.owner AND s.name = e.name AND s.type = e.type AND s.line = e.line
|
244
|
+
ORDER BY e.sequence",
|
245
|
+
object_schema_name, object_name, object_type
|
246
|
+
).each do |line, position, error_text, source_text|
|
247
|
+
result << "Error on line #{'%4d' % line}: #{source_text}" if line > previous_line
|
248
|
+
result << " position #{'%4d' % position}: #{error_text}\n"
|
249
|
+
previous_line = line
|
250
|
+
end
|
251
|
+
result unless result.empty?
|
254
252
|
end
|
255
|
-
result unless result.empty?
|
256
|
-
end
|
257
253
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
254
|
+
def find_other_schema(name)
|
255
|
+
return nil if @original_schema
|
256
|
+
if select_first("SELECT username FROM all_users WHERE username = :username", name.to_s.upcase)
|
257
|
+
Schema.new(connection, name, self)
|
258
|
+
else
|
259
|
+
nil
|
260
|
+
end
|
264
261
|
end
|
265
|
-
end
|
266
|
-
|
267
|
-
def find_standard_procedure(name)
|
268
|
-
return nil if @original_schema
|
269
|
-
Procedure.find(self, name, 'STANDARD', 'SYS')
|
270
|
-
end
|
271
262
|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
end
|
263
|
+
def find_standard_procedure(name)
|
264
|
+
return nil if @original_schema
|
265
|
+
Procedure.find(self, name, "STANDARD", "SYS")
|
266
|
+
end
|
277
267
|
|
268
|
+
def find_public_synonym(name)
|
269
|
+
return nil if @original_schema
|
270
|
+
target_schema_name, target_object_name = @connection.describe_synonym("PUBLIC", name)
|
271
|
+
find_database_object(target_object_name, target_schema_name) if target_schema_name
|
272
|
+
end
|
278
273
|
end
|
279
274
|
end
|
280
275
|
|
data/lib/plsql/sequence.rb
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
module PLSQL
|
2
|
-
|
3
2
|
module SequenceClassMethods #:nodoc:
|
4
3
|
def find(schema, sequence)
|
5
4
|
if schema.select_first(
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
"SELECT sequence_name FROM all_sequences
|
6
|
+
WHERE sequence_owner = :owner
|
7
|
+
AND sequence_name = :sequence_name",
|
9
8
|
schema.schema_name, sequence.to_s.upcase)
|
10
9
|
new(schema, sequence)
|
11
10
|
# search for synonym
|
12
11
|
elsif (row = schema.select_first(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
"SELECT t.sequence_owner, t.sequence_name
|
13
|
+
FROM all_synonyms s, all_sequences t
|
14
|
+
WHERE s.owner IN (:owner, 'PUBLIC')
|
15
|
+
AND s.synonym_name = :synonym_name
|
16
|
+
AND t.sequence_owner = s.table_owner
|
17
|
+
AND t.sequence_name = s.table_name
|
18
|
+
ORDER BY DECODE(s.owner, 'PUBLIC', 1, 0)",
|
20
19
|
schema.schema_name, sequence.to_s.upcase))
|
21
20
|
new(schema, row[1], row[0])
|
22
21
|
else
|
@@ -43,7 +42,5 @@ module PLSQL
|
|
43
42
|
def currval
|
44
43
|
@schema.select_one "SELECT \"#{@schema_name}\".\"#{@sequence_name}\".CURRVAL FROM dual"
|
45
44
|
end
|
46
|
-
|
47
45
|
end
|
48
|
-
|
49
46
|
end
|
data/lib/plsql/sql_statements.rb
CHANGED
@@ -16,7 +16,7 @@ module PLSQL
|
|
16
16
|
end
|
17
17
|
|
18
18
|
# Select :first or :all values. Examples:
|
19
|
-
#
|
19
|
+
#
|
20
20
|
# plsql.select :first, "SELECT * FROM employees WHERE employee_id = :1", 1
|
21
21
|
# plsql.select :all, "SELECT * FROM employees ORDER BY employee_id"
|
22
22
|
def select(*args)
|
@@ -43,9 +43,9 @@ module PLSQL
|
|
43
43
|
|
44
44
|
# Execute COMMIT in current database session.
|
45
45
|
# Use beforehand
|
46
|
-
#
|
46
|
+
#
|
47
47
|
# plsql.connection.autocommit = false
|
48
|
-
#
|
48
|
+
#
|
49
49
|
# to turn off automatic commits after each statement.
|
50
50
|
def commit
|
51
51
|
@connection.commit
|
@@ -53,9 +53,9 @@ module PLSQL
|
|
53
53
|
|
54
54
|
# Execute ROLLBACK in current database session.
|
55
55
|
# Use beforehand
|
56
|
-
#
|
56
|
+
#
|
57
57
|
# plsql.connection.autocommit = false
|
58
|
-
#
|
58
|
+
#
|
59
59
|
# to turn off automatic commits after each statement.
|
60
60
|
def rollback
|
61
61
|
@connection.rollback
|
@@ -64,9 +64,9 @@ module PLSQL
|
|
64
64
|
# Create SAVEPOINT with specified name. Later use +rollback_to+ method to roll changes back
|
65
65
|
# to specified savepoint.
|
66
66
|
# Use beforehand
|
67
|
-
#
|
67
|
+
#
|
68
68
|
# plsql.connection.autocommit = false
|
69
|
-
#
|
69
|
+
#
|
70
70
|
# to turn off automatic commits after each statement.
|
71
71
|
def savepoint(name)
|
72
72
|
execute "SAVEPOINT #{name}"
|
@@ -74,14 +74,12 @@ module PLSQL
|
|
74
74
|
|
75
75
|
# Roll back changes to specified savepoint (that was created using +savepoint+ method)
|
76
76
|
# Use beforehand
|
77
|
-
#
|
77
|
+
#
|
78
78
|
# plsql.connection.autocommit = false
|
79
|
-
#
|
79
|
+
#
|
80
80
|
# to turn off automatic commits after each statement.
|
81
81
|
def rollback_to(name)
|
82
82
|
execute "ROLLBACK TO #{name}"
|
83
83
|
end
|
84
|
-
|
85
84
|
end
|
86
85
|
end
|
87
|
-
|
data/lib/plsql/table.rb
CHANGED
@@ -1,28 +1,27 @@
|
|
1
1
|
module PLSQL
|
2
|
-
|
3
2
|
module TableClassMethods #:nodoc:
|
4
3
|
def find(schema, table)
|
5
4
|
if schema.select_first(
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
"SELECT table_name FROM all_tables
|
6
|
+
WHERE owner = :owner
|
7
|
+
AND table_name = :table_name",
|
9
8
|
schema.schema_name, table.to_s.upcase)
|
10
9
|
new(schema, table)
|
11
10
|
# search for synonym
|
12
11
|
elsif (row = schema.select_first(
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
12
|
+
"SELECT t.owner, t.table_name
|
13
|
+
FROM all_synonyms s, all_tables t
|
14
|
+
WHERE s.owner = :owner
|
15
|
+
AND s.synonym_name = :synonym_name
|
16
|
+
AND t.owner = s.table_owner
|
17
|
+
AND t.table_name = s.table_name
|
18
|
+
UNION ALL
|
19
|
+
SELECT t.owner, t.table_name
|
20
|
+
FROM all_synonyms s, all_tables t
|
21
|
+
WHERE s.owner = 'PUBLIC'
|
22
|
+
AND s.synonym_name = :synonym_name
|
23
|
+
AND t.owner = s.table_owner
|
24
|
+
AND t.table_name = s.table_name",
|
26
25
|
schema.schema_name, table.to_s.upcase, table.to_s.upcase))
|
27
26
|
new(schema, row[1], row[0])
|
28
27
|
else
|
@@ -58,34 +57,34 @@ module PLSQL
|
|
58
57
|
) do |r|
|
59
58
|
column_name, position,
|
60
59
|
data_type, data_length, data_precision, data_scale, char_used,
|
61
|
-
data_type_owner,
|
60
|
+
data_type_owner, _, typecode, nullable, data_default = r
|
62
61
|
# remove scale (n) from data_type (returned for TIMESTAMPs and INTERVALs)
|
63
|
-
data_type.sub!(/\(\d+\)/,
|
62
|
+
data_type.sub!(/\(\d+\)/, "")
|
64
63
|
# store column metadata
|
65
64
|
@columns[column_name.downcase.to_sym] = {
|
66
|
-
:
|
67
|
-
:
|
68
|
-
:
|
69
|
-
:
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
73
|
-
:
|
74
|
-
:
|
75
|
-
:
|
76
|
-
:
|
65
|
+
position: position && position.to_i,
|
66
|
+
data_type: data_type_owner && (typecode == "COLLECTION" ? "TABLE" : "OBJECT") || data_type,
|
67
|
+
data_length: data_type_owner ? nil : data_length && data_length.to_i,
|
68
|
+
data_precision: data_precision && data_precision.to_i,
|
69
|
+
data_scale: data_scale && data_scale.to_i,
|
70
|
+
char_used: char_used,
|
71
|
+
type_owner: data_type_owner,
|
72
|
+
type_name: data_type_owner && data_type,
|
73
|
+
sql_type_name: data_type_owner && "#{data_type_owner}.#{data_type}",
|
74
|
+
nullable: nullable == "Y", # store as true or false
|
75
|
+
data_default: data_default && data_default.strip # remove leading and trailing whitespace
|
77
76
|
}
|
78
77
|
end
|
79
78
|
end
|
80
79
|
|
81
80
|
# list of table column names
|
82
81
|
def column_names
|
83
|
-
@column_names ||= @columns.keys.sort_by{|k| columns[k][:position]}
|
82
|
+
@column_names ||= @columns.keys.sort_by { |k| columns[k][:position] }
|
84
83
|
end
|
85
84
|
|
86
85
|
# General select method with :first, :all or :count as first parameter.
|
87
86
|
# It is recommended to use #first, #all or #count method instead of this one.
|
88
|
-
def select(first_or_all, sql_params=
|
87
|
+
def select(first_or_all, sql_params = "", *bindvars)
|
89
88
|
case first_or_all
|
90
89
|
when :first, :all
|
91
90
|
select_sql = "SELECT * "
|
@@ -102,7 +101,7 @@ module PLSQL
|
|
102
101
|
raise ArgumentError, "Cannot specify bind variables when passing WHERE conditions as Hash" unless bindvars.empty?
|
103
102
|
where_sqls = []
|
104
103
|
order_by_sql = nil
|
105
|
-
sql_params.each do |k,v|
|
104
|
+
sql_params.each do |k, v|
|
106
105
|
if k == :order_by
|
107
106
|
order_by_sql = " ORDER BY #{v} "
|
108
107
|
elsif v.nil? || v == :is_null
|
@@ -114,7 +113,7 @@ module PLSQL
|
|
114
113
|
bindvars << v
|
115
114
|
end
|
116
115
|
end
|
117
|
-
select_sql << "WHERE " << where_sqls.join(
|
116
|
+
select_sql << "WHERE " << where_sqls.join(" AND ") unless where_sqls.empty?
|
118
117
|
select_sql << order_by_sql if order_by_sql
|
119
118
|
else
|
120
119
|
raise ArgumentError, "Only String or Hash can be provided as SQL condition argument"
|
@@ -131,48 +130,49 @@ module PLSQL
|
|
131
130
|
# plsql.employees.all
|
132
131
|
# plsql.employees.all(:order_by => :employee_id)
|
133
132
|
# plsql.employees.all("WHERE employee_id > :employee_id", 5)
|
134
|
-
#
|
135
|
-
def all(sql=
|
133
|
+
#
|
134
|
+
def all(sql = "", *bindvars)
|
136
135
|
select(:all, sql, *bindvars)
|
137
136
|
end
|
138
137
|
|
139
138
|
# Select first table record using optional conditions. Examples:
|
140
|
-
#
|
139
|
+
#
|
141
140
|
# plsql.employees.first
|
142
141
|
# plsql.employees.first(:employee_id => 1)
|
143
142
|
# plsql.employees.first("WHERE employee_id = 1")
|
144
143
|
# plsql.employees.first("WHERE employee_id = :employee_id", 1)
|
145
|
-
#
|
146
|
-
def first(sql=
|
144
|
+
#
|
145
|
+
def first(sql = "", *bindvars)
|
147
146
|
select(:first, sql, *bindvars)
|
148
147
|
end
|
149
148
|
|
150
149
|
# Count table records using optional conditions. Examples:
|
151
|
-
#
|
150
|
+
#
|
152
151
|
# plsql.employees.count
|
153
152
|
# plsql.employees.count("WHERE employee_id > :employee_id", 5)
|
154
|
-
#
|
155
|
-
def count(sql=
|
153
|
+
#
|
154
|
+
def count(sql = "", *bindvars)
|
156
155
|
select(:count, sql, *bindvars)
|
157
156
|
end
|
158
157
|
|
159
158
|
# Insert record or records in table. Examples:
|
160
|
-
#
|
159
|
+
#
|
161
160
|
# employee = { :employee_id => 1, :first_name => 'First', :last_name => 'Last', :hire_date => Time.local(2000,01,31) }
|
162
161
|
# plsql.employees.insert employee
|
163
162
|
# # => INSERT INTO employees VALUES (1, 'First', 'Last', ...)
|
164
|
-
#
|
163
|
+
#
|
165
164
|
# employees = [employee1, employee2, ... ] # array of many Hashes
|
166
165
|
# plsql.employees.insert employees
|
167
166
|
#
|
168
167
|
def insert(record)
|
169
168
|
# if Array of records is passed then insert each individually
|
170
169
|
if record.is_a?(Array)
|
171
|
-
record.each {|r| insert(r)}
|
170
|
+
record.each { |r| insert(r) }
|
172
171
|
return nil
|
173
172
|
end
|
174
173
|
|
175
174
|
table_proc = TableProcedure.new(@schema, self, :insert)
|
175
|
+
record = record.map { |k, v| [k.downcase.to_sym, v] }.to_h
|
176
176
|
table_proc.add_insert_arguments(record)
|
177
177
|
|
178
178
|
call = ProcedureCall.new(table_proc, table_proc.argument_values)
|
@@ -180,15 +180,15 @@ module PLSQL
|
|
180
180
|
end
|
181
181
|
|
182
182
|
# Insert record or records in table using array of values. Examples:
|
183
|
-
#
|
183
|
+
#
|
184
184
|
# # with values for all columns
|
185
185
|
# plsql.employees.insert_values [1, 'First', 'Last', Time.local(2000,01,31)]
|
186
186
|
# # => INSERT INTO employees VALUES (1, 'First', 'Last', ...)
|
187
|
-
#
|
187
|
+
#
|
188
188
|
# # with values for specified columns
|
189
189
|
# plsql.employees.insert_values [:employee_id, :first_name, :last_name], [1, 'First', 'Last']
|
190
190
|
# # => INSERT INTO employees (employee_id, first_name, last_name) VALUES (1, 'First', 'Last')
|
191
|
-
#
|
191
|
+
#
|
192
192
|
# # with values for many records
|
193
193
|
# plsql.employees.insert_values [:employee_id, :first_name, :last_name], [1, 'First', 'Last'], [2, 'Second', 'Last']
|
194
194
|
# # => INSERT INTO employees (employee_id, first_name, last_name) VALUES (1, 'First', 'Last')
|
@@ -197,7 +197,7 @@ module PLSQL
|
|
197
197
|
def insert_values(*args)
|
198
198
|
raise ArgumentError, "no arguments given" unless args.first
|
199
199
|
# if first argument is array of symbols then use it as list of fields
|
200
|
-
if args.first.all?{|a| a.instance_of?(Symbol)}
|
200
|
+
if args.first.all? { |a| a.instance_of?(Symbol) }
|
201
201
|
fields = args.shift
|
202
202
|
# otherwise use all columns as list of fields
|
203
203
|
else
|
@@ -211,14 +211,14 @@ module PLSQL
|
|
211
211
|
end
|
212
212
|
|
213
213
|
# Update table records using optional conditions. Example:
|
214
|
-
#
|
214
|
+
#
|
215
215
|
# plsql.employees.update(:first_name => 'Second', :where => {:employee_id => 1})
|
216
216
|
# # => UPDATE employees SET first_name = 'Second' WHERE employee_id = 1
|
217
217
|
#
|
218
218
|
def update(params)
|
219
219
|
raise ArgumentError, "Only Hash parameter can be passed to table update method" unless params.is_a?(Hash)
|
220
220
|
where = params.delete(:where)
|
221
|
-
|
221
|
+
|
222
222
|
table_proc = TableProcedure.new(@schema, self, :update)
|
223
223
|
table_proc.add_set_arguments(params)
|
224
224
|
table_proc.add_where_arguments(where) if where
|
@@ -227,11 +227,11 @@ module PLSQL
|
|
227
227
|
end
|
228
228
|
|
229
229
|
# Delete table records using optional conditions. Example:
|
230
|
-
#
|
230
|
+
#
|
231
231
|
# plsql.employees.delete(:employee_id => 1)
|
232
232
|
# # => DELETE FROM employees WHERE employee_id = 1
|
233
|
-
#
|
234
|
-
def delete(sql_params=
|
233
|
+
#
|
234
|
+
def delete(sql_params = "", *bindvars)
|
235
235
|
delete_sql = "DELETE FROM \"#{@schema_name}\".\"#{@table_name}\" "
|
236
236
|
case sql_params
|
237
237
|
when String
|
@@ -239,11 +239,11 @@ module PLSQL
|
|
239
239
|
when Hash
|
240
240
|
raise ArgumentError, "Cannot specify bind variables when passing WHERE conditions as Hash" unless bindvars.empty?
|
241
241
|
where_sqls = []
|
242
|
-
sql_params.each do |k,v|
|
242
|
+
sql_params.each do |k, v|
|
243
243
|
where_sqls << "#{k} = :#{k}"
|
244
244
|
bindvars << v
|
245
245
|
end
|
246
|
-
delete_sql << "WHERE " << where_sqls.join(
|
246
|
+
delete_sql << "WHERE " << where_sqls.join(" AND ") unless where_sqls.empty?
|
247
247
|
else
|
248
248
|
raise ArgumentError, "Only String or Hash can be provided as SQL condition argument"
|
249
249
|
end
|
@@ -287,7 +287,7 @@ module PLSQL
|
|
287
287
|
end
|
288
288
|
|
289
289
|
def add_insert_arguments(params)
|
290
|
-
params.each do |k,v|
|
290
|
+
params.each do |k, v|
|
291
291
|
raise ArgumentError, "Invalid column name #{k.inspect} specified as argument" unless (column_metadata = @table.columns[k])
|
292
292
|
@argument_list[0] << k
|
293
293
|
@arguments[0][k] = column_metadata
|
@@ -296,7 +296,7 @@ module PLSQL
|
|
296
296
|
end
|
297
297
|
|
298
298
|
def add_set_arguments(params)
|
299
|
-
params.each do |k,v|
|
299
|
+
params.each do |k, v|
|
300
300
|
raise ArgumentError, "Invalid column name #{k.inspect} specified as argument" unless (column_metadata = @table.columns[k])
|
301
301
|
@argument_list[0] << k
|
302
302
|
@arguments[0][k] = column_metadata
|
@@ -308,7 +308,7 @@ module PLSQL
|
|
308
308
|
def add_where_arguments(params)
|
309
309
|
case params
|
310
310
|
when Hash
|
311
|
-
params.each do |k,v|
|
311
|
+
params.each do |k, v|
|
312
312
|
raise ArgumentError, "Invalid column name #{k.inspect} specified as argument" unless (column_metadata = @table.columns[k])
|
313
313
|
@argument_list[0] << :"w_#{k}"
|
314
314
|
@arguments[0][:"w_#{k}"] = column_metadata
|
@@ -332,7 +332,7 @@ module PLSQL
|
|
332
332
|
def call_sql(params_string)
|
333
333
|
case @operation
|
334
334
|
when :insert
|
335
|
-
"INSERT INTO \"#{@table.schema_name}\".\"#{@table.table_name}\"(#{@argument_list[0].map{|a| a.to_s}.join(', ')}) VALUES (#{params_string});\n"
|
335
|
+
"INSERT INTO \"#{@table.schema_name}\".\"#{@table.table_name}\"(#{@argument_list[0].map { |a| a.to_s }.join(', ')}) VALUES (#{params_string});\n"
|
336
336
|
when :update
|
337
337
|
update_sql = "UPDATE \"#{@table.schema_name}\".\"#{@table.table_name}\" SET #{@set_sqls.join(', ')}"
|
338
338
|
update_sql << " WHERE #{@where_sqls.join(' AND ')}" unless @where_sqls.empty?
|
@@ -340,9 +340,6 @@ module PLSQL
|
|
340
340
|
update_sql
|
341
341
|
end
|
342
342
|
end
|
343
|
-
|
344
343
|
end
|
345
|
-
|
346
344
|
end
|
347
|
-
|
348
345
|
end
|