sequel 4.3.0 → 4.4.0
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 +4 -4
- data/CHANGELOG +34 -0
- data/README.rdoc +7 -7
- data/Rakefile +2 -2
- data/doc/active_record.rdoc +2 -2
- data/doc/association_basics.rdoc +21 -7
- data/doc/bin_sequel.rdoc +2 -2
- data/doc/cheat_sheet.rdoc +2 -1
- data/doc/dataset_basics.rdoc +1 -1
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +2 -2
- data/doc/object_model.rdoc +2 -2
- data/doc/opening_databases.rdoc +13 -1
- data/doc/querying.rdoc +9 -4
- data/doc/release_notes/4.4.0.txt +92 -0
- data/doc/schema_modification.rdoc +1 -1
- data/doc/security.rdoc +2 -2
- data/doc/sql.rdoc +3 -3
- data/doc/thread_safety.rdoc +1 -1
- data/doc/validations.rdoc +1 -1
- data/doc/virtual_rows.rdoc +1 -1
- data/lib/sequel/adapters/jdbc.rb +85 -19
- data/lib/sequel/adapters/jdbc/db2.rb +1 -1
- data/lib/sequel/adapters/jdbc/derby.rb +1 -1
- data/lib/sequel/adapters/jdbc/h2.rb +2 -2
- data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +34 -3
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +57 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +2 -2
- data/lib/sequel/adapters/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/oracle.rb +41 -4
- data/lib/sequel/adapters/shared/sqlanywhere.rb +458 -0
- data/lib/sequel/adapters/sqlanywhere.rb +177 -0
- data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +11 -3
- data/lib/sequel/core.rb +4 -4
- data/lib/sequel/database/connecting.rb +1 -1
- data/lib/sequel/database/query.rb +1 -1
- data/lib/sequel/database/schema_generator.rb +1 -1
- data/lib/sequel/database/schema_methods.rb +2 -2
- data/lib/sequel/dataset.rb +1 -1
- data/lib/sequel/dataset/actions.rb +2 -0
- data/lib/sequel/dataset/graph.rb +1 -1
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +37 -16
- data/lib/sequel/extensions/constraint_validations.rb +1 -1
- data/lib/sequel/extensions/date_arithmetic.rb +2 -2
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +5 -4
- data/lib/sequel/extensions/pg_array.rb +2 -2
- data/lib/sequel/extensions/pg_array_ops.rb +2 -2
- data/lib/sequel/extensions/pg_hstore.rb +2 -2
- data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
- data/lib/sequel/extensions/pg_json.rb +2 -2
- data/lib/sequel/extensions/pg_json_ops.rb +2 -2
- data/lib/sequel/extensions/pg_range.rb +2 -2
- data/lib/sequel/extensions/pg_range_ops.rb +2 -2
- data/lib/sequel/extensions/pg_row.rb +2 -2
- data/lib/sequel/extensions/pg_row_ops.rb +3 -3
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/associations.rb +106 -17
- data/lib/sequel/model/base.rb +23 -19
- data/lib/sequel/plugins/json_serializer.rb +1 -1
- data/lib/sequel/plugins/many_through_many.rb +14 -6
- data/lib/sequel/plugins/pg_array_associations.rb +28 -0
- data/lib/sequel/plugins/rcte_tree.rb +1 -1
- data/lib/sequel/plugins/serialization.rb +11 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
- data/lib/sequel/plugins/table_select.rb +41 -0
- data/lib/sequel/plugins/tree.rb +1 -1
- data/lib/sequel/sql.rb +2 -2
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/oracle_spec.rb +22 -1
- data/spec/adapters/postgres_spec.rb +31 -48
- data/spec/adapters/sqlanywhere_spec.rb +170 -0
- data/spec/core/dataset_spec.rb +109 -0
- data/spec/core/object_graph_spec.rb +7 -0
- data/spec/extensions/constraint_validations_spec.rb +7 -0
- data/spec/extensions/core_refinements_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +65 -0
- data/spec/extensions/pg_array_associations_spec.rb +44 -0
- data/spec/extensions/rcte_tree_spec.rb +3 -3
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/table_select_spec.rb +71 -0
- data/spec/integration/associations_test.rb +279 -7
- data/spec/integration/dataset_test.rb +13 -4
- data/spec/integration/schema_test.rb +12 -14
- data/spec/model/associations_spec.rb +472 -3
- data/spec/model/class_dataset_methods_spec.rb +1 -0
- data/spec/model/model_spec.rb +10 -0
- metadata +10 -2
|
@@ -586,7 +586,7 @@ the table if the table already exists. On some databases, it uses
|
|
|
586
586
|
<tt>IF NOT EXISTS</tt>, on others it does a separate query to check for
|
|
587
587
|
existence.
|
|
588
588
|
|
|
589
|
-
This should not be used inside migrations, as if the
|
|
589
|
+
This should not be used inside migrations, as if the table does not
|
|
590
590
|
exist, it may mess up the migration.
|
|
591
591
|
|
|
592
592
|
=== +rename_table+
|
data/doc/security.rdoc
CHANGED
|
@@ -79,7 +79,7 @@ in which case Sequel automatically literalizes the input:
|
|
|
79
79
|
Sequel generally treats ruby strings as SQL strings (escaping them correctly), and
|
|
80
80
|
not as raw SQL. However, you can convert a ruby string to a literal string, and
|
|
81
81
|
Sequel will then treat it as raw SQL. This is typically done through String#lit
|
|
82
|
-
if the {core_extensions}[
|
|
82
|
+
if the {core_extensions}[rdoc-ref:doc/core_extensions.rdoc] are in use,
|
|
83
83
|
or Sequel.lit[rdoc-ref:Sequel::SQL::Builders#lit] if they are not in use.
|
|
84
84
|
|
|
85
85
|
'a'.lit
|
|
@@ -308,7 +308,7 @@ practice, though being explicit on a per-call basis is still recommended:
|
|
|
308
308
|
Album.set_allowed_columns(:name, :copies_sold)
|
|
309
309
|
Album.create(params[:album]) # Only name and copies_sold set
|
|
310
310
|
|
|
311
|
-
For more details on the mass assignment methods, see the {Mass Assignment Guide}[
|
|
311
|
+
For more details on the mass assignment methods, see the {Mass Assignment Guide}[rdoc-ref:doc/mass_assignment.rdoc].
|
|
312
312
|
|
|
313
313
|
== General Parameter Handling
|
|
314
314
|
|
data/doc/sql.rdoc
CHANGED
|
@@ -78,7 +78,7 @@ Almost everywhere in Sequel, you can drop down to literal SQL by providing a lit
|
|
|
78
78
|
DB[:albums].select('name') # SELECT 'name' FROM albums
|
|
79
79
|
DB[:albums].select(Sequel.lit('name')) # SELECT name FROM albums
|
|
80
80
|
|
|
81
|
-
For a simpler way of creating literal strings, you can also use the {core_extensions extension}[
|
|
81
|
+
For a simpler way of creating literal strings, you can also use the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc], which adds the <tt>String#lit</tt> method, and other methods that integrate Sequel's DSL with the ruby language:
|
|
82
82
|
|
|
83
83
|
DB[:albums].select('name'.lit)
|
|
84
84
|
|
|
@@ -137,7 +137,7 @@ The other way to qualify an identifier is to use the <tt>Sequel.qualify</tt> wit
|
|
|
137
137
|
|
|
138
138
|
Sequel.qualify(:table, :column) # "table"."column"
|
|
139
139
|
|
|
140
|
-
Another way to generate identifiers is to use Sequel's {virtual row support}[
|
|
140
|
+
Another way to generate identifiers is to use Sequel's {virtual row support}[rdoc-ref:doc/virtual_rows.rdoc]:
|
|
141
141
|
|
|
142
142
|
DB[:albums].select{name} # SELECT "name" FROM "albums"
|
|
143
143
|
DB[:albums].select{albums__name} # SELECT "albums"."name" FROM "albums"
|
|
@@ -573,4 +573,4 @@ Note how +update+ and +delete+ used the +where+ argument, but that +insert+ did
|
|
|
573
573
|
|
|
574
574
|
=== Methods Used for Each SQL Clause
|
|
575
575
|
|
|
576
|
-
To see which methods exist that affect each SQL clause, see the {"Dataset Basics" guide}[
|
|
576
|
+
To see which methods exist that affect each SQL clause, see the {"Dataset Basics" guide}[rdoc-ref:doc/dataset_basics.rdoc].
|
data/doc/thread_safety.rdoc
CHANGED
|
@@ -4,7 +4,7 @@ Most Sequel usage (and all common Sequel usage) is thread safe by default. Spec
|
|
|
4
4
|
|
|
5
5
|
== Connection Pool
|
|
6
6
|
|
|
7
|
-
In order to allow multiple threads to operate on the same database at the same time, Sequel uses a connection pool. The connection pool is designed so that a thread uses a connection for the minimum amount of time, returning the connection to the pool as soon as it is done using the connection. If a thread requests a connection and the pool does not have an available connection, a new connection will be created. If the maximum number of connections in the pool has already been reached, the thread will block (actually busy-wait) until a connection is available or the
|
|
7
|
+
In order to allow multiple threads to operate on the same database at the same time, Sequel uses a connection pool. The connection pool is designed so that a thread uses a connection for the minimum amount of time, returning the connection to the pool as soon as it is done using the connection. If a thread requests a connection and the pool does not have an available connection, a new connection will be created. If the maximum number of connections in the pool has already been reached, the thread will block (actually busy-wait) until a connection is available or the connection pool timeout has elapsed (in which case a PoolTimeout error will be raised).
|
|
8
8
|
|
|
9
9
|
== Exceptions
|
|
10
10
|
|
data/doc/validations.rdoc
CHANGED
|
@@ -299,7 +299,7 @@ Additionally, you can also include an optional options hash as the last argument
|
|
|
299
299
|
:message :: The message to use
|
|
300
300
|
:only_if_modified :: Only check the uniqueness if the object is new or one of the columns has been modified.
|
|
301
301
|
|
|
302
|
-
+validates_unique+ is the only method in +validation_helpers+ that checks with the database. Attempting to validate uniqueness outside of the database suffers from a race condition, so any time you want to add a uniqueness validation, you should make sure to add a uniqueness constraint or unique index on the underlying database table. See the {"Migrations and Schema Modification" guide}[
|
|
302
|
+
+validates_unique+ is the only method in +validation_helpers+ that checks with the database. Attempting to validate uniqueness outside of the database suffers from a race condition, so any time you want to add a uniqueness validation, you should make sure to add a uniqueness constraint or unique index on the underlying database table. See the {"Migrations and Schema Modification" guide}[rdoc-ref:doc/migration.rdoc] for details on how to do that.
|
|
303
303
|
|
|
304
304
|
== +validation_helpers+ Options
|
|
305
305
|
|
data/doc/virtual_rows.rdoc
CHANGED
|
@@ -68,7 +68,7 @@ inside the proc. If that doesn't make sense, maybe this example will help:
|
|
|
68
68
|
# WHERE c > (a - 32)
|
|
69
69
|
|
|
70
70
|
There are two related differences here. First is the usage of <tt>o.c</tt> vs +c+,
|
|
71
|
-
and second is the difference between the
|
|
71
|
+
and second is the difference between the use of +a+. In the regular proc,
|
|
72
72
|
you couldn't call +c+ without an explicit receiver in the proc, unless the self of the
|
|
73
73
|
surrounding scope responded to it. For +a+, note how ruby calls the method on
|
|
74
74
|
the receiver of the surrounding scope in the regular proc, which returns an integer,
|
data/lib/sequel/adapters/jdbc.rb
CHANGED
|
@@ -143,6 +143,25 @@ module Sequel
|
|
|
143
143
|
db.extend(Sequel::JDBC::Cubrid::DatabaseMethods)
|
|
144
144
|
db.extend_datasets Sequel::Cubrid::DatasetMethods
|
|
145
145
|
Java::cubrid.jdbc.driver.CUBRIDDriver
|
|
146
|
+
end,
|
|
147
|
+
:sqlanywhere=>proc do |db|
|
|
148
|
+
drv = [
|
|
149
|
+
lambda{Java::sybase.jdbc4.sqlanywhere.IDriver},
|
|
150
|
+
lambda{Java::ianywhere.ml.jdbcodbc.jdbc4.IDriver},
|
|
151
|
+
lambda{Java::sybase.jdbc.sqlanywhere.IDriver},
|
|
152
|
+
lambda{Java::ianywhere.ml.jdbcodbc.jdbc.IDriver},
|
|
153
|
+
lambda{Java::com.sybase.jdbc4.jdbc.Sybdriver},
|
|
154
|
+
lambda{Java::com.sybase.jdbc3.jdbc.Sybdriver}
|
|
155
|
+
].each do |class_proc|
|
|
156
|
+
begin
|
|
157
|
+
break class_proc.call
|
|
158
|
+
rescue NameError
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
Sequel.require 'adapters/jdbc/sqlanywhere'
|
|
162
|
+
db.extend(Sequel::JDBC::SqlAnywhere::DatabaseMethods)
|
|
163
|
+
db.dataset_class = Sequel::JDBC::SqlAnywhere::Dataset
|
|
164
|
+
drv
|
|
146
165
|
end
|
|
147
166
|
}
|
|
148
167
|
|
|
@@ -286,15 +305,31 @@ module Sequel
|
|
|
286
305
|
def execute_insert(sql, opts=OPTS)
|
|
287
306
|
execute(sql, {:type=>:insert}.merge(opts))
|
|
288
307
|
end
|
|
289
|
-
|
|
308
|
+
|
|
309
|
+
# Use the JDBC metadata to get a list of foreign keys for the table.
|
|
310
|
+
def foreign_key_list(table, opts=OPTS)
|
|
311
|
+
m = output_identifier_meth
|
|
312
|
+
schema, table = metadata_schema_and_table(table, opts)
|
|
313
|
+
foreign_keys = {}
|
|
314
|
+
metadata(:getImportedKeys, nil, schema, table) do |r|
|
|
315
|
+
if fk = foreign_keys[r[:fk_name]]
|
|
316
|
+
fk[:columns] << [r[:key_seq], m.call(r[:fkcolumn_name])]
|
|
317
|
+
fk[:key] << [r[:key_seq], m.call(r[:pkcolumn_name])]
|
|
318
|
+
elsif r[:fk_name]
|
|
319
|
+
foreign_keys[r[:fk_name]] = {:name=>m.call(r[:fk_name]), :columns=>[[r[:key_seq], m.call(r[:fkcolumn_name])]], :table=>m.call(r[:pktable_name]), :key=>[[r[:key_seq], m.call(r[:pkcolumn_name])]]}
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
foreign_keys.values.each do |fk|
|
|
323
|
+
[:columns, :key].each do |k|
|
|
324
|
+
fk[k] = fk[k].sort.map{|_, v| v}
|
|
325
|
+
end
|
|
326
|
+
end
|
|
327
|
+
end
|
|
328
|
+
|
|
290
329
|
# Use the JDBC metadata to get the index information for the table.
|
|
291
330
|
def indexes(table, opts=OPTS)
|
|
292
331
|
m = output_identifier_meth
|
|
293
|
-
|
|
294
|
-
schema, table = schema_and_table(table)
|
|
295
|
-
schema ||= opts[:schema]
|
|
296
|
-
schema = im.call(schema) if schema
|
|
297
|
-
table = im.call(table)
|
|
332
|
+
schema, table = metadata_schema_and_table(table, opts)
|
|
298
333
|
indexes = {}
|
|
299
334
|
metadata(:getIndexInfo, nil, schema, table, false, true) do |r|
|
|
300
335
|
next unless name = r[:column_name]
|
|
@@ -511,6 +546,16 @@ module Sequel
|
|
|
511
546
|
end
|
|
512
547
|
end
|
|
513
548
|
|
|
549
|
+
# Return the schema and table suitable for use with metadata queries.
|
|
550
|
+
def metadata_schema_and_table(table, opts)
|
|
551
|
+
im = input_identifier_meth(opts[:dataset])
|
|
552
|
+
schema, table = schema_and_table(table)
|
|
553
|
+
schema ||= opts[:schema]
|
|
554
|
+
schema = im.call(schema) if schema
|
|
555
|
+
table = im.call(table)
|
|
556
|
+
[schema, table]
|
|
557
|
+
end
|
|
558
|
+
|
|
514
559
|
# Created a JDBC prepared statement on the connection with the given SQL.
|
|
515
560
|
def prepare_jdbc_statement(conn, sql, opts)
|
|
516
561
|
conn.prepareStatement(sql)
|
|
@@ -563,12 +608,8 @@ module Sequel
|
|
|
563
608
|
# Parse the table schema for the given table.
|
|
564
609
|
def schema_parse_table(table, opts=OPTS)
|
|
565
610
|
m = output_identifier_meth(opts[:dataset])
|
|
566
|
-
im = input_identifier_meth(opts[:dataset])
|
|
567
611
|
ds = dataset
|
|
568
|
-
schema, table =
|
|
569
|
-
schema ||= opts[:schema]
|
|
570
|
-
schema = im.call(schema) if schema
|
|
571
|
-
table = im.call(table)
|
|
612
|
+
schema, table = metadata_schema_and_table(table, opts)
|
|
572
613
|
pks, ts = [], []
|
|
573
614
|
metadata(:getPrimaryKeys, nil, schema, table) do |h|
|
|
574
615
|
next if schema_parse_table_skip?(h, schema)
|
|
@@ -742,7 +783,7 @@ module Sequel
|
|
|
742
783
|
# Return a callable object that will convert any value of <tt>v</tt>'s
|
|
743
784
|
# class to a ruby object. If no callable object can handle <tt>v</tt>'s
|
|
744
785
|
# class, return false so that the negative lookup is cached.
|
|
745
|
-
def convert_type_proc(v)
|
|
786
|
+
def convert_type_proc(v, ctn=nil)
|
|
746
787
|
case v
|
|
747
788
|
when JAVA_BIG_DECIMAL
|
|
748
789
|
DECIMAL_METHOD
|
|
@@ -768,6 +809,16 @@ module Sequel
|
|
|
768
809
|
false
|
|
769
810
|
end
|
|
770
811
|
end
|
|
812
|
+
|
|
813
|
+
# The generic JDBC support does not use column info when deciding on conversion procs.
|
|
814
|
+
def convert_type_proc_uses_column_info?
|
|
815
|
+
false
|
|
816
|
+
end
|
|
817
|
+
|
|
818
|
+
# By default, if using column info, assume the info needed is the column's type name.
|
|
819
|
+
def convert_type_proc_column_info(meta, i)
|
|
820
|
+
meta.column_type_name(i)
|
|
821
|
+
end
|
|
771
822
|
|
|
772
823
|
# Extend the dataset with the JDBC stored procedure methods.
|
|
773
824
|
def prepare_extend_sproc(ds)
|
|
@@ -781,14 +832,29 @@ module Sequel
|
|
|
781
832
|
meta = result.getMetaData
|
|
782
833
|
cols = []
|
|
783
834
|
i = 0
|
|
784
|
-
meta.getColumnCount.times{cols << [output_identifier(meta.getColumnLabel(i+=1)), i]}
|
|
785
|
-
columns = cols.map{|c| c.at(0)}
|
|
786
|
-
@columns = columns
|
|
787
835
|
ct = @convert_types
|
|
788
|
-
|
|
789
|
-
|
|
836
|
+
ct = db.convert_types if ct.nil?
|
|
837
|
+
|
|
838
|
+
if ct
|
|
839
|
+
use_column_info = convert_type_proc_uses_column_info?
|
|
840
|
+
# When converting types, four values are associated with every column:
|
|
841
|
+
# 1) column name symbol
|
|
842
|
+
# 2) index (starting at 1, as JDBC does)
|
|
843
|
+
# 3) database-specific value usable by convert_type_proc to determine the conversion proc to use for column
|
|
844
|
+
# 4) nil (later updated with the actual conversion proc during the lookup process)
|
|
845
|
+
meta.getColumnCount.times do
|
|
846
|
+
i += 1
|
|
847
|
+
cols << [output_identifier(meta.getColumnLabel(i)), i, (convert_type_proc_column_info(meta, i) if use_column_info), nil]
|
|
848
|
+
end
|
|
849
|
+
@columns = cols.map{|c| c.at(0)}
|
|
790
850
|
process_result_set_convert(cols, result, &block)
|
|
791
851
|
else
|
|
852
|
+
# When not converting types, only the type name and the index are used.
|
|
853
|
+
meta.getColumnCount.times do
|
|
854
|
+
i += 1
|
|
855
|
+
cols << [output_identifier(meta.getColumnLabel(i)), i]
|
|
856
|
+
end
|
|
857
|
+
@columns = cols.map{|c| c.at(0)}
|
|
792
858
|
process_result_set_no_convert(cols, result, &block)
|
|
793
859
|
end
|
|
794
860
|
ensure
|
|
@@ -816,13 +882,13 @@ module Sequel
|
|
|
816
882
|
def process_result_set_convert(cols, result)
|
|
817
883
|
while result.next
|
|
818
884
|
row = {}
|
|
819
|
-
cols.each do |n, i, p|
|
|
885
|
+
cols.each do |n, i, ctn, p|
|
|
820
886
|
v = result.getObject(i)
|
|
821
887
|
row[n] = if v
|
|
822
888
|
if p
|
|
823
889
|
p.call(v)
|
|
824
890
|
elsif p.nil?
|
|
825
|
-
cols[i-1][
|
|
891
|
+
cols[i-1][3] = p = convert_type_proc(v, ctn)
|
|
826
892
|
if p
|
|
827
893
|
p.call(v)
|
|
828
894
|
else
|
|
@@ -255,7 +255,7 @@ module Sequel
|
|
|
255
255
|
DERBY_CLOB_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:derby_clob)
|
|
256
256
|
|
|
257
257
|
# Handle clobs on Derby as strings.
|
|
258
|
-
def convert_type_proc(v)
|
|
258
|
+
def convert_type_proc(v, ctn=nil)
|
|
259
259
|
if v.is_a?(JAVA_SQL_CLOB)
|
|
260
260
|
DERBY_CLOB_METHOD
|
|
261
261
|
else
|
|
@@ -62,7 +62,7 @@ module Sequel
|
|
|
62
62
|
when :add_column
|
|
63
63
|
if (pk = op.delete(:primary_key)) || (ref = op.delete(:table))
|
|
64
64
|
sqls = [super(table, op)]
|
|
65
|
-
sqls << "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})" if pk
|
|
65
|
+
sqls << "ALTER TABLE #{quote_schema_table(table)} ADD PRIMARY KEY (#{quote_identifier(op[:name])})" if pk && op[:type] != :identity
|
|
66
66
|
if ref
|
|
67
67
|
op[:table] = ref
|
|
68
68
|
sqls << "ALTER TABLE #{quote_schema_table(table)} ADD FOREIGN KEY (#{quote_identifier(op[:name])}) #{column_references_sql(op)}"
|
|
@@ -202,7 +202,7 @@ module Sequel
|
|
|
202
202
|
H2_CLOB_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:h2_clob)
|
|
203
203
|
|
|
204
204
|
# Handle H2 specific clobs as strings.
|
|
205
|
-
def convert_type_proc(v)
|
|
205
|
+
def convert_type_proc(v, ctn=nil)
|
|
206
206
|
if v.is_a?(Java::OrgH2Jdbc::JdbcClob)
|
|
207
207
|
H2_CLOB_METHOD
|
|
208
208
|
else
|
|
@@ -37,6 +37,13 @@ module Sequel
|
|
|
37
37
|
# HSQLDB specific SQL for renaming columns, and changing column types and/or nullity.
|
|
38
38
|
def alter_table_sql(table, op)
|
|
39
39
|
case op[:op]
|
|
40
|
+
when :add_column
|
|
41
|
+
if op[:table]
|
|
42
|
+
[super(table, op.merge(:table=>nil)),
|
|
43
|
+
alter_table_sql(table, op.merge(:op=>:add_constraint, :type=>:foreign_key, :name=>op[:foreign_key_name], :columns=>[op[:name]], :table=>op[:table]))]
|
|
44
|
+
else
|
|
45
|
+
super
|
|
46
|
+
end
|
|
40
47
|
when :rename_column
|
|
41
48
|
"ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} RENAME TO #{quote_identifier(op[:new_name])}"
|
|
42
49
|
when :set_column_type
|
|
@@ -33,7 +33,7 @@ module Sequel
|
|
|
33
33
|
JTDS_CLOB_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:jtds_clob)
|
|
34
34
|
|
|
35
35
|
# Handle CLOB types retrieved via JTDS.
|
|
36
|
-
def convert_type_proc(v)
|
|
36
|
+
def convert_type_proc(v, ctn=nil)
|
|
37
37
|
if v.is_a?(Java::NetSourceforgeJtdsJdbc::ClobImpl)
|
|
38
38
|
JTDS_CLOB_METHOD
|
|
39
39
|
else
|
|
@@ -168,17 +168,48 @@ module Sequel
|
|
|
168
168
|
# Handle PostgreSQL array and object types. Object types are just
|
|
169
169
|
# turned into strings, similarly to how the native adapter treats
|
|
170
170
|
# the types.
|
|
171
|
-
def convert_type_proc(v)
|
|
171
|
+
def convert_type_proc(v, ctn=nil)
|
|
172
172
|
case v
|
|
173
173
|
when Java::OrgPostgresqlJdbc4::Jdbc4Array
|
|
174
|
-
|
|
174
|
+
if pr = db.conversion_procs[ctn]
|
|
175
|
+
lambda{|x| pr.call(PG_OBJECT_METHOD.call(x))}
|
|
176
|
+
else
|
|
177
|
+
PGArrayConverter.new(method(:convert_type_proc))
|
|
178
|
+
end
|
|
175
179
|
when Java::OrgPostgresqlUtil::PGobject
|
|
176
|
-
|
|
180
|
+
if pr = db.conversion_procs[ctn]
|
|
181
|
+
lambda{|x| pr.call(PG_OBJECT_METHOD.call(x))}
|
|
182
|
+
else
|
|
183
|
+
PG_OBJECT_METHOD
|
|
184
|
+
end
|
|
185
|
+
when String
|
|
186
|
+
if pr = db.conversion_procs[ctn]
|
|
187
|
+
pr
|
|
188
|
+
else
|
|
189
|
+
false
|
|
190
|
+
end
|
|
191
|
+
when JAVA_HASH_MAP
|
|
192
|
+
if Sequel.respond_to?(:hstore)
|
|
193
|
+
lambda{|x| Sequel.hstore(HASH_MAP_METHOD.call(x))}
|
|
194
|
+
else
|
|
195
|
+
HASH_MAP_METHOD
|
|
196
|
+
end
|
|
177
197
|
else
|
|
178
198
|
super
|
|
179
199
|
end
|
|
180
200
|
end
|
|
181
201
|
|
|
202
|
+
# The jdbc/postgresql adapter uses column type oids when determining
|
|
203
|
+
# conversion procs.
|
|
204
|
+
def convert_type_proc_uses_column_info?
|
|
205
|
+
true
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# Use the column type oid as the database specific column info value.
|
|
209
|
+
def convert_type_proc_column_info(meta, i)
|
|
210
|
+
meta.field(i).oid
|
|
211
|
+
end
|
|
212
|
+
|
|
182
213
|
# Literalize strings similar to the native postgres adapter
|
|
183
214
|
def literal_string_append(sql, v)
|
|
184
215
|
sql << APOS << db.synchronize(@opts[:server]){|c| c.escape_string(v)} << APOS
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
Sequel.require 'adapters/shared/sqlanywhere'
|
|
2
|
+
Sequel.require 'adapters/jdbc/transactions'
|
|
3
|
+
|
|
4
|
+
module Sequel
|
|
5
|
+
module JDBC
|
|
6
|
+
module SqlAnywhere
|
|
7
|
+
# Database instance methods for Sybase databases accessed via JDBC.
|
|
8
|
+
module DatabaseMethods
|
|
9
|
+
extend Sequel::Database::ResetIdentifierMangling
|
|
10
|
+
include Sequel::SqlAnywhere::DatabaseMethods
|
|
11
|
+
include Sequel::JDBC::Transactions
|
|
12
|
+
|
|
13
|
+
LAST_INSERT_ID = 'SELECT @@IDENTITY'.freeze
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
# Get the last inserted id.
|
|
18
|
+
def last_insert_id(conn, opts=OPTS)
|
|
19
|
+
statement(conn) do |stmt|
|
|
20
|
+
sql = LAST_INSERT_ID
|
|
21
|
+
rs = log_yield(sql){stmt.executeQuery(sql)}
|
|
22
|
+
rs.next
|
|
23
|
+
rs.getInt(1)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
#Dataset class for Sybase datasets accessed via JDBC.
|
|
29
|
+
class Dataset < JDBC::Dataset
|
|
30
|
+
include Sequel::SqlAnywhere::DatasetMethods
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
class ::Sequel::JDBC::Dataset::TYPE_TRANSLATOR
|
|
35
|
+
def sqla_boolean(i) i != 0 end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
BOOLEAN_METHOD = TYPE_TRANSLATOR_INSTANCE.method(:sqla_boolean)
|
|
39
|
+
|
|
40
|
+
def convert_type_proc(v, ctn=nil)
|
|
41
|
+
case
|
|
42
|
+
when ctn && ctn =~ SqlAnywhere::DatabaseMethods::SMALLINT_RE
|
|
43
|
+
BOOLEAN_METHOD
|
|
44
|
+
else
|
|
45
|
+
super(v, ctn)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# SQLAnywhere needs the column info if it is converting smallint to bool,
|
|
50
|
+
# since the JDBC adapter always returns smallint as integer.
|
|
51
|
+
def convert_type_proc_uses_column_info?
|
|
52
|
+
convert_smallint_to_bool
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -22,13 +22,13 @@ module Sequel
|
|
|
22
22
|
def process_result_set_convert(cols, result)
|
|
23
23
|
while result.next
|
|
24
24
|
row = {}
|
|
25
|
-
cols.each do |n, i, p|
|
|
25
|
+
cols.each do |n, i, ctn, p|
|
|
26
26
|
v = (n == :is_autoincrement ? result.getString(i) : result.getObject(i))
|
|
27
27
|
row[n] = if v
|
|
28
28
|
if p
|
|
29
29
|
p.call(v)
|
|
30
30
|
elsif p.nil?
|
|
31
|
-
cols[i-1][
|
|
31
|
+
cols[i-1][3] = p = convert_type_proc(v, ctn)
|
|
32
32
|
if p
|
|
33
33
|
p.call(v)
|
|
34
34
|
else
|