sequel 3.21.0 → 3.31.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.
Files changed (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -0,0 +1,321 @@
1
+ Sequel.require 'adapters/utils/emulate_offset_with_row_number'
2
+
3
+ module Sequel
4
+ module DB2
5
+ @use_clob_as_blob = true
6
+
7
+ class << self
8
+ # Whether to use clob as the generic File type, true by default.
9
+ attr_accessor :use_clob_as_blob
10
+ end
11
+
12
+ module DatabaseMethods
13
+ AUTOINCREMENT = 'GENERATED ALWAYS AS IDENTITY'.freeze
14
+ NOT_NULL = ' NOT NULL'.freeze
15
+ NULL = ''.freeze
16
+
17
+ # DB2 always uses :db2 as it's database type
18
+ def database_type
19
+ :db2
20
+ end
21
+
22
+ # Return the database version as a string. Don't rely on this,
23
+ # it may return an integer in the future.
24
+ def db2_version
25
+ return @db2_version if @db2_version
26
+ @db2_version = metadata_dataset.with_sql("select service_level from sysibmadm.env_inst_info").first[:service_level]
27
+ end
28
+ alias_method :server_version, :db2_version
29
+
30
+ # Use SYSIBM.SYSCOLUMNS to get the information on the tables.
31
+ def schema_parse_table(table, opts = {})
32
+ m = output_identifier_meth(opts[:dataset])
33
+ im = input_identifier_meth(opts[:dataset])
34
+ metadata_dataset.with_sql("SELECT * FROM SYSIBM.SYSCOLUMNS WHERE TBNAME = #{literal(im.call(table))} ORDER BY COLNO").
35
+ collect do |column|
36
+ column[:db_type] = column.delete(:typename)
37
+ if column[:db_type] == "DECIMAL"
38
+ column[:db_type] << "(#{column[:longlength]},#{column[:scale]})"
39
+ end
40
+ column[:allow_null] = column.delete(:nulls) == 'Y'
41
+ column[:primary_key] = column.delete(:identity) == 'Y' || !column[:keyseq].nil?
42
+ column[:type] = schema_column_type(column[:db_type])
43
+ [ m.call(column.delete(:name)), column]
44
+ end
45
+ end
46
+
47
+ # Use SYSCAT.TABLES to get the tables for the database
48
+ def tables
49
+ metadata_dataset.
50
+ with_sql("SELECT TABNAME FROM SYSCAT.TABLES WHERE TYPE='T' AND OWNER = #{literal(input_identifier_meth.call(opts[:user]))}").
51
+ all.map{|h| output_identifier_meth.call(h[:tabname]) }
52
+ end
53
+
54
+ # Use SYSCAT.TABLES to get the views for the database
55
+ def views
56
+ metadata_dataset.
57
+ with_sql("SELECT TABNAME FROM SYSCAT.TABLES WHERE TYPE='V' AND OWNER = #{literal(input_identifier_meth.call(opts[:user]))}").
58
+ all.map{|h| output_identifier_meth.call(h[:tabname]) }
59
+ end
60
+
61
+ # Use SYSCAT.INDEXES to get the indexes for the table
62
+ def indexes(table, opts = {})
63
+ metadata_dataset.
64
+ with_sql("SELECT INDNAME,UNIQUERULE,MADE_UNIQUE,SYSTEM_REQUIRED FROM SYSCAT.INDEXES WHERE TABNAME = #{literal(input_identifier_meth.call(table))}").
65
+ all.map{|h| Hash[ h.map{|k,v| [k.to_sym, v]} ] }
66
+ end
67
+
68
+ private
69
+
70
+ # Handle DB2 specific alter table operations.
71
+ def alter_table_sql(table, op)
72
+ case op[:op]
73
+ when :add_column
74
+ if op[:primary_key] && op[:auto_increment] && op[:type] == Integer
75
+ [
76
+ "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op.merge(:auto_increment=>false, :primary_key=>false, :default=>0, :null=>false))}",
77
+ "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{literal(op[:name])} DROP DEFAULT",
78
+ "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{literal(op[:name])} SET #{AUTOINCREMENT}"
79
+ ]
80
+ else
81
+ "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
82
+ end
83
+ when :drop_column
84
+ "ALTER TABLE #{quote_schema_table(table)} DROP #{column_definition_sql(op)}"
85
+ when :rename_column # renaming is only possible after db2 v9.7
86
+ "ALTER TABLE #{quote_schema_table(table)} RENAME COLUMN #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
87
+ when :set_column_type
88
+ "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} SET DATA TYPE #{type_literal(op)}"
89
+ when :set_column_default
90
+ "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} SET DEFAULT #{literal(op[:default])}"
91
+ when :add_constraint
92
+ if op[:type] == :unique
93
+ sqls = op[:columns].map{|c| ["ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(c)} SET NOT NULL", reorg_sql(table)]}
94
+ sqls << super
95
+ sqls.flatten
96
+ else
97
+ super
98
+ end
99
+ else
100
+ super
101
+ end
102
+ end
103
+
104
+ # DB2 uses an identity column for autoincrement.
105
+ def auto_increment_sql
106
+ AUTOINCREMENT
107
+ end
108
+
109
+ # Add null/not null SQL fragment to column creation SQL.
110
+ def column_definition_null_sql(sql, column)
111
+ null = column.fetch(:null, column[:allow_null])
112
+ null = false if column[:primary_key]
113
+
114
+ sql << NOT_NULL if null == false
115
+ sql << NULL if null == true
116
+ end
117
+
118
+ # Supply columns with NOT NULL if they are part of a composite
119
+ # primary/foreign key
120
+ def column_list_sql(g)
121
+ ks = []
122
+ g.constraints.each{|c| ks = c[:columns] if [:primary_key, :foreign_key].include? c[:type]}
123
+ g.columns.each{|c| c[:null] = false if ks.include?(c[:name]) }
124
+ super
125
+ end
126
+
127
+ # Here we use DGTT which has most backward compatibility, which uses
128
+ # DECLARE instead of CREATE. CGTT can only be used after version 9.7.
129
+ # http://www.ibm.com/developerworks/data/library/techarticle/dm-0912globaltemptable/
130
+ def create_table_sql(name, generator, options)
131
+ if options[:temp]
132
+ "DECLARE GLOBAL TEMPORARY TABLE #{quote_identifier(name)} (#{column_list_sql(generator)})"
133
+ else
134
+ super
135
+ end
136
+ end
137
+
138
+ # DB2 has issues with quoted identifiers, so
139
+ # turn off database quoting by default.
140
+ def quote_identifiers_default
141
+ false
142
+ end
143
+
144
+ # DB2 uses RENAME TABLE to rename tables.
145
+ def rename_table_sql(name, new_name)
146
+ "RENAME TABLE #{quote_schema_table(name)} TO #{quote_schema_table(new_name)}"
147
+ end
148
+
149
+ # Run the REORG TABLE command for the table, necessary when
150
+ # the table has been altered.
151
+ def reorg(table)
152
+ synchronize(opts[:server]){|c| c.execute(reorg_sql(table))}
153
+ end
154
+
155
+ # The SQL to use for REORGing a table.
156
+ def reorg_sql(table)
157
+ "CALL ADMIN_CMD(#{literal("REORG TABLE #{table}")})"
158
+ end
159
+
160
+ # We uses the clob type by default for Files.
161
+ # Note: if user select to use blob, then insert statement should use
162
+ # use this for blob value:
163
+ # cast(X'fffefdfcfbfa' as blob(2G))
164
+ def type_literal_generic_file(column)
165
+ ::Sequel::DB2::use_clob_as_blob ? :clob : :blob
166
+ end
167
+
168
+ # DB2 uses smallint to store booleans.
169
+ def type_literal_generic_trueclass(column)
170
+ :smallint
171
+ end
172
+ alias type_literal_generic_falseclass type_literal_generic_trueclass
173
+ end
174
+
175
+ module DatasetMethods
176
+ include EmulateOffsetWithRowNumber
177
+
178
+ PAREN_CLOSE = Dataset::PAREN_CLOSE
179
+ PAREN_OPEN = Dataset::PAREN_OPEN
180
+ BITWISE_METHOD_MAP = {:& =>:BITAND, :| => :BITOR, :^ => :BITXOR, :'B~'=>:BITNOT}
181
+ BOOL_TRUE = '1'.freeze
182
+ BOOL_FALSE = '0'.freeze
183
+ CAST_STRING_OPEN = "RTRIM(CHAR(".freeze
184
+ CAST_STRING_CLOSE = "))".freeze
185
+ FETCH_FIRST_ROW_ONLY = " FETCH FIRST ROW ONLY".freeze
186
+ FETCH_FIRST = " FETCH FIRST ".freeze
187
+ ROWS_ONLY = " ROWS ONLY".freeze
188
+ EMPTY_FROM_TABLE = ' FROM "SYSIBM"."SYSDUMMY1"'.freeze
189
+
190
+ # DB2 casts strings using RTRIM and CHAR instead of VARCHAR.
191
+ def cast_sql_append(sql, expr, type)
192
+ if(type == String)
193
+ sql << CAST_STRING_OPEN
194
+ literal_append(sql, expr)
195
+ sql << CAST_STRING_CLOSE
196
+ else
197
+ super
198
+ end
199
+ end
200
+
201
+ # Handle DB2 specific LIKE and bitwise operator support, and
202
+ # emulate the extract method, which DB2 doesn't natively support.
203
+ def complex_expression_sql_append(sql, op, args)
204
+ case op
205
+ when :ILIKE
206
+ super(sql, :LIKE, [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
207
+ when :"NOT ILIKE"
208
+ super(sql, :"NOT LIKE", [SQL::Function.new(:upper, args.at(0)), SQL::Function.new(:upper, args.at(1)) ])
209
+ when :&, :|, :^
210
+ # works with db2 v9.5 and after
211
+ op = BITWISE_METHOD_MAP[op]
212
+ sql << complex_expression_arg_pairs(args){|a, b| literal(SQL::Function.new(op, a, b))}
213
+ when :<<
214
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} * POWER(2, #{literal(b)}))"}
215
+ when :>>
216
+ sql << complex_expression_arg_pairs(args){|a, b| "(#{literal(a)} / POWER(2, #{literal(b)}))"}
217
+ when :'B~'
218
+ literal_append(sql, SQL::Function.new(:BITNOT, *args))
219
+ when :extract
220
+ sql << args.at(0).to_s
221
+ sql << PAREN_OPEN
222
+ literal_append(sql, args.at(1))
223
+ sql << PAREN_CLOSE
224
+ else
225
+ super
226
+ end
227
+ end
228
+
229
+ # DB2 supports GROUP BY CUBE
230
+ def supports_group_cube?
231
+ true
232
+ end
233
+
234
+ # DB2 supports GROUP BY ROLLUP
235
+ def supports_group_rollup?
236
+ true
237
+ end
238
+
239
+ # DB2 does not support IS TRUE.
240
+ def supports_is_true?
241
+ false
242
+ end
243
+
244
+ # DB2 does not support multiple columns in IN.
245
+ def supports_multiple_column_in?
246
+ false
247
+ end
248
+
249
+ # DB2 only allows * in SELECT if it is the only thing being selected.
250
+ def supports_select_all_and_column?
251
+ false
252
+ end
253
+
254
+ # DB2 does not support fractional seconds in timestamps.
255
+ def supports_timestamp_usecs?
256
+ false
257
+ end
258
+
259
+ # DB2 supports window functions
260
+ def supports_window_functions?
261
+ true
262
+ end
263
+
264
+ # DB2 does not support WHERE 1.
265
+ def supports_where_true?
266
+ false
267
+ end
268
+
269
+ private
270
+
271
+ # DB2 needs the standard workaround to insert all default values into
272
+ # a table with more than one column.
273
+ def insert_supports_empty_values?
274
+ false
275
+ end
276
+
277
+ # Use 0 for false on DB2
278
+ def literal_false
279
+ BOOL_FALSE
280
+ end
281
+
282
+ # Use 1 for true on DB2
283
+ def literal_true
284
+ BOOL_TRUE
285
+ end
286
+
287
+ # Add a fallback table for empty from situation
288
+ def select_from_sql(sql)
289
+ @opts[:from] ? super : (sql << EMPTY_FROM_TABLE)
290
+ end
291
+
292
+ # Modify the sql to limit the number of rows returned
293
+ # Note:
294
+ #
295
+ # After db2 v9.7, MySQL flavored "LIMIT X OFFSET Y" can be enabled using
296
+ #
297
+ # db2set DB2_COMPATIBILITY_VECTOR=MYSQL
298
+ # db2stop
299
+ # db2start
300
+ #
301
+ # Support for this feature is not used in this adapter however.
302
+ def select_limit_sql(sql)
303
+ if l = @opts[:limit]
304
+ if l == 1
305
+ sql << FETCH_FIRST_ROW_ONLY
306
+ elsif l > 1
307
+ sql << FETCH_FIRST
308
+ literal_append(sql, l)
309
+ sql << ROWS_ONLY
310
+ end
311
+ end
312
+ end
313
+
314
+ def _truncate_sql(table)
315
+ # "TRUNCATE #{table} IMMEDIATE" is only for newer version of db2, so we
316
+ # use the following one
317
+ "ALTER TABLE #{quote_schema_table(table)} ACTIVATE NOT LOGGED INITIALLY WITH EMPTY TABLE"
318
+ end
319
+ end
320
+ end
321
+ end
@@ -0,0 +1,221 @@
1
+ module Sequel
2
+ module Firebird
3
+ module DatabaseMethods
4
+ AUTO_INCREMENT = ''.freeze
5
+ TEMPORARY = 'GLOBAL TEMPORARY '.freeze
6
+
7
+ def clear_primary_key(*tables)
8
+ tables.each{|t| @primary_keys.delete(dataset.send(:input_identifier, t))}
9
+ end
10
+
11
+ def create_trigger(*args)
12
+ self << create_trigger_sql(*args)
13
+ end
14
+
15
+ def database_type
16
+ :firebird
17
+ end
18
+
19
+ def drop_sequence(name)
20
+ self << drop_sequence_sql(name)
21
+ end
22
+
23
+ # Return primary key for the given table.
24
+ def primary_key(table)
25
+ t = dataset.send(:input_identifier, table)
26
+ @primary_keys.fetch(t) do
27
+ pk = fetch("SELECT RDB$FIELD_NAME FROM RDB$INDEX_SEGMENTS NATURAL JOIN RDB$RELATION_CONSTRAINTS WHERE RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' AND RDB$RELATION_NAME = ?", t).single_value
28
+ @primary_keys[t] = dataset.send(:output_identifier, pk.rstrip) if pk
29
+ end
30
+ end
31
+
32
+ def restart_sequence(*args)
33
+ self << restart_sequence_sql(*args)
34
+ end
35
+
36
+ def sequences(opts={})
37
+ ds = self[:"rdb$generators"].server(opts[:server]).filter(:"rdb$system_flag" => 0).select(:"rdb$generator_name")
38
+ block_given? ? yield(ds) : ds.map{|r| ds.send(:output_identifier, r[:"rdb$generator_name"])}
39
+ end
40
+
41
+ def tables(opts={})
42
+ tables_or_views(0, opts)
43
+ end
44
+
45
+ def views(opts={})
46
+ tables_or_views(1, opts)
47
+ end
48
+
49
+ private
50
+
51
+ # Use Firebird specific syntax for add column
52
+ def alter_table_sql(table, op)
53
+ case op[:op]
54
+ when :add_column
55
+ "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
56
+ when :drop_column
57
+ "ALTER TABLE #{quote_schema_table(table)} DROP #{column_definition_sql(op)}"
58
+ when :rename_column
59
+ "ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
60
+ when :set_column_type
61
+ "ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TYPE #{type_literal(op)}"
62
+ else
63
+ super(table, op)
64
+ end
65
+ end
66
+
67
+ def auto_increment_sql()
68
+ AUTO_INCREMENT
69
+ end
70
+
71
+ def create_sequence_sql(name, opts={})
72
+ "CREATE SEQUENCE #{quote_identifier(name)}"
73
+ end
74
+
75
+ # Firebird gets an override because of the mess of creating a
76
+ # sequence and trigger for auto-incrementing primary keys.
77
+ def create_table_from_generator(name, generator, options)
78
+ drop_statement, create_statements = create_table_sql_list(name, generator, options)
79
+ (execute_ddl(drop_statement) rescue nil) if drop_statement
80
+ create_statements.each{|sql| execute_ddl(sql)}
81
+ end
82
+
83
+ def create_table_sql_list(name, generator, options={})
84
+ statements = [create_table_sql(name, generator, options)]
85
+ drop_seq_statement = nil
86
+ generator.columns.each do |c|
87
+ if c[:auto_increment]
88
+ c[:sequence_name] ||= "seq_#{name}_#{c[:name]}"
89
+ unless c[:create_sequence] == false
90
+ drop_seq_statement = drop_sequence_sql(c[:sequence_name])
91
+ statements << create_sequence_sql(c[:sequence_name])
92
+ statements << restart_sequence_sql(c[:sequence_name], {:restart_position => c[:sequence_start_position]}) if c[:sequence_start_position]
93
+ end
94
+ unless c[:create_trigger] == false
95
+ c[:trigger_name] ||= "BI_#{name}_#{c[:name]}"
96
+ c[:quoted_name] = quote_identifier(c[:name])
97
+ trigger_definition = <<-END
98
+ begin
99
+ if ((new.#{c[:quoted_name]} is null) or (new.#{c[:quoted_name]} = 0)) then
100
+ begin
101
+ new.#{c[:quoted_name]} = next value for #{c[:sequence_name]};
102
+ end
103
+ end
104
+ END
105
+ statements << create_trigger_sql(name, c[:trigger_name], trigger_definition, {:events => [:insert]})
106
+ end
107
+ end
108
+ end
109
+ [drop_seq_statement, statements]
110
+ end
111
+
112
+ def create_trigger_sql(table, name, definition, opts={})
113
+ events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
114
+ whence = opts[:after] ? 'AFTER' : 'BEFORE'
115
+ inactive = opts[:inactive] ? 'INACTIVE' : 'ACTIVE'
116
+ position = opts.fetch(:position, 0)
117
+ sql = <<-end_sql
118
+ CREATE TRIGGER #{quote_identifier(name)} for #{quote_identifier(table)}
119
+ #{inactive} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} position #{position}
120
+ as #{definition}
121
+ end_sql
122
+ sql
123
+ end
124
+
125
+ def drop_sequence_sql(name)
126
+ "DROP SEQUENCE #{quote_identifier(name)}"
127
+ end
128
+
129
+ def remove_cached_schema(table)
130
+ clear_primary_key(table)
131
+ super
132
+ end
133
+
134
+ def restart_sequence_sql(name, opts={})
135
+ seq_name = quote_identifier(name)
136
+ "ALTER SEQUENCE #{seq_name} RESTART WITH #{opts[:restart_position]}"
137
+ end
138
+
139
+ def tables_or_views(type, opts)
140
+ ds = self[:"rdb$relations"].server(opts[:server]).filter(:"rdb$relation_type" => type, Sequel::SQL::Function.new(:COALESCE, :"rdb$system_flag", 0) => 0).select(:"rdb$relation_name")
141
+ ds.map{|r| ds.send(:output_identifier, r[:"rdb$relation_name"].rstrip)}
142
+ end
143
+
144
+ def type_literal_generic_string(column)
145
+ column[:text] ? :"BLOB SUB_TYPE TEXT" : super
146
+ end
147
+ end
148
+
149
+ module DatasetMethods
150
+ BOOL_TRUE = '1'.freeze
151
+ BOOL_FALSE = '0'.freeze
152
+ NULL = LiteralString.new('NULL').freeze
153
+ SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'with select distinct limit columns from join where group having compounds order')
154
+ INSERT_CLAUSE_METHODS = Dataset.clause_methods(:insert, %w'insert into columns values returning')
155
+ FIRST = " FIRST ".freeze
156
+ SKIP = " SKIP ".freeze
157
+
158
+ # Insert given values into the database.
159
+ def insert(*values)
160
+ if @opts[:sql] || @opts[:returning]
161
+ super
162
+ else
163
+ returning(insert_pk).insert(*values){|r| return r.values.first}
164
+ end
165
+ end
166
+
167
+ # Insert a record returning the record inserted
168
+ def insert_select(*values)
169
+ returning.insert(*values){|r| return r}
170
+ end
171
+
172
+ def requires_sql_standard_datetimes?
173
+ true
174
+ end
175
+
176
+ def supports_insert_select?
177
+ true
178
+ end
179
+
180
+ # Firebird does not support INTERSECT or EXCEPT
181
+ def supports_intersect_except?
182
+ false
183
+ end
184
+
185
+ private
186
+
187
+ def insert_clause_methods
188
+ INSERT_CLAUSE_METHODS
189
+ end
190
+
191
+ def insert_pk(*values)
192
+ pk = db.primary_key(opts[:from].first)
193
+ pk ? Sequel::SQL::Identifier.new(pk) : NULL
194
+ end
195
+
196
+ def literal_false
197
+ BOOL_FALSE
198
+ end
199
+
200
+ def literal_true
201
+ BOOL_TRUE
202
+ end
203
+
204
+ # The order of clauses in the SELECT SQL statement
205
+ def select_clause_methods
206
+ SELECT_CLAUSE_METHODS
207
+ end
208
+
209
+ def select_limit_sql(sql)
210
+ if l = @opts[:limit]
211
+ sql << FIRST
212
+ literal_append(sql, l)
213
+ end
214
+ if o = @opts[:offset]
215
+ sql << SKIP
216
+ literal_append(sql, o)
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,53 @@
1
+ module Sequel
2
+ module Informix
3
+ module DatabaseMethods
4
+ TEMPORARY = 'TEMP '.freeze
5
+
6
+ # Informix uses the :informix database type
7
+ def database_type
8
+ :informix
9
+ end
10
+
11
+ private
12
+
13
+ # Informix has issues with quoted identifiers, so
14
+ # turn off database quoting by default.
15
+ def quote_identifiers_default
16
+ false
17
+ end
18
+
19
+ # SQL fragment for showing a table is temporary
20
+ def temporary_table_sql
21
+ TEMPORARY
22
+ end
23
+ end
24
+
25
+ module DatasetMethods
26
+ SELECT_CLAUSE_METHODS = Dataset.clause_methods(:select, %w'select limit distinct columns from join where having group compounds order')
27
+ FIRST = " FIRST ".freeze
28
+ SKIP = " SKIP ".freeze
29
+
30
+ private
31
+
32
+ # Informix does not support INTERSECT or EXCEPT
33
+ def supports_intersect_except?
34
+ false
35
+ end
36
+
37
+ def select_clause_methods
38
+ SELECT_CLAUSE_METHODS
39
+ end
40
+
41
+ def select_limit_sql(sql)
42
+ if o = @opts[:offset]
43
+ sql << SKIP
44
+ literal_append(sql, o)
45
+ end
46
+ if l = @opts[:limit]
47
+ sql << FIRST
48
+ literal_append(sql, l)
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end