sequel 4.3.0 → 4.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|