sequel 2.9.0 → 2.10.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.
- data/CHANGELOG +56 -0
- data/{README → README.rdoc} +85 -57
- data/Rakefile +10 -5
- data/bin/sequel +7 -16
- data/doc/advanced_associations.rdoc +5 -17
- data/doc/cheat_sheet.rdoc +18 -20
- data/doc/dataset_filtering.rdoc +8 -32
- data/doc/schema.rdoc +20 -0
- data/lib/sequel_core.rb +35 -1
- data/lib/sequel_core/adapters/ado.rb +1 -1
- data/lib/sequel_core/adapters/db2.rb +2 -2
- data/lib/sequel_core/adapters/dbi.rb +2 -11
- data/lib/sequel_core/adapters/do.rb +205 -0
- data/lib/sequel_core/adapters/do/mysql.rb +38 -0
- data/lib/sequel_core/adapters/do/postgres.rb +92 -0
- data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
- data/lib/sequel_core/adapters/firebird.rb +298 -0
- data/lib/sequel_core/adapters/informix.rb +10 -1
- data/lib/sequel_core/adapters/jdbc.rb +78 -19
- data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
- data/lib/sequel_core/adapters/jdbc/mysql.rb +10 -0
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +7 -3
- data/lib/sequel_core/adapters/mysql.rb +53 -77
- data/lib/sequel_core/adapters/odbc.rb +1 -1
- data/lib/sequel_core/adapters/openbase.rb +1 -1
- data/lib/sequel_core/adapters/oracle.rb +2 -2
- data/lib/sequel_core/adapters/postgres.rb +16 -14
- data/lib/sequel_core/adapters/shared/mysql.rb +44 -9
- data/lib/sequel_core/adapters/shared/oracle.rb +4 -5
- data/lib/sequel_core/adapters/shared/postgres.rb +86 -82
- data/lib/sequel_core/adapters/shared/sqlite.rb +39 -24
- data/lib/sequel_core/adapters/sqlite.rb +11 -1
- data/lib/sequel_core/connection_pool.rb +10 -2
- data/lib/sequel_core/core_sql.rb +13 -3
- data/lib/sequel_core/database.rb +131 -30
- data/lib/sequel_core/database/schema.rb +5 -5
- data/lib/sequel_core/dataset.rb +31 -6
- data/lib/sequel_core/dataset/convenience.rb +11 -11
- data/lib/sequel_core/dataset/query.rb +2 -2
- data/lib/sequel_core/dataset/sql.rb +6 -6
- data/lib/sequel_core/exceptions.rb +4 -0
- data/lib/sequel_core/migration.rb +4 -4
- data/lib/sequel_core/schema/generator.rb +19 -3
- data/lib/sequel_core/schema/sql.rb +24 -20
- data/lib/sequel_core/sql.rb +13 -16
- data/lib/sequel_core/version.rb +11 -0
- data/lib/sequel_model.rb +2 -0
- data/lib/sequel_model/base.rb +2 -2
- data/lib/sequel_model/hooks.rb +46 -7
- data/lib/sequel_model/record.rb +11 -9
- data/lib/sequel_model/schema.rb +1 -1
- data/lib/sequel_model/validations.rb +72 -61
- data/spec/adapters/firebird_spec.rb +371 -0
- data/spec/adapters/mysql_spec.rb +118 -62
- data/spec/adapters/oracle_spec.rb +5 -5
- data/spec/adapters/postgres_spec.rb +33 -18
- data/spec/adapters/sqlite_spec.rb +2 -2
- data/spec/integration/dataset_test.rb +3 -3
- data/spec/integration/schema_test.rb +55 -5
- data/spec/integration/spec_helper.rb +11 -0
- data/spec/integration/type_test.rb +59 -16
- data/spec/sequel_core/connection_pool_spec.rb +14 -0
- data/spec/sequel_core/core_sql_spec.rb +24 -14
- data/spec/sequel_core/database_spec.rb +96 -11
- data/spec/sequel_core/dataset_spec.rb +97 -37
- data/spec/sequel_core/expression_filters_spec.rb +51 -40
- data/spec/sequel_core/object_graph_spec.rb +2 -2
- data/spec/sequel_core/schema_generator_spec.rb +31 -6
- data/spec/sequel_core/schema_spec.rb +25 -9
- data/spec/sequel_core/spec_helper.rb +4 -1
- data/spec/sequel_core/version_spec.rb +7 -0
- data/spec/sequel_model/associations_spec.rb +1 -1
- data/spec/sequel_model/hooks_spec.rb +68 -13
- data/spec/sequel_model/model_spec.rb +4 -4
- data/spec/sequel_model/record_spec.rb +22 -0
- data/spec/sequel_model/spec_helper.rb +2 -1
- data/spec/sequel_model/validations_spec.rb +107 -7
- metadata +15 -5
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'sequel_core/adapters/shared/mysql'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module DataObjects
|
5
|
+
# Database and Dataset instance methods for MySQL specific
|
6
|
+
# support via DataObjects.
|
7
|
+
module MySQL
|
8
|
+
# Database instance methods for MySQL databases accessed via DataObjects.
|
9
|
+
module DatabaseMethods
|
10
|
+
include Sequel::MySQL::DatabaseMethods
|
11
|
+
|
12
|
+
# Return instance of Sequel::DataObjects::MySQL::Dataset with the given opts.
|
13
|
+
def dataset(opts=nil)
|
14
|
+
Sequel::DataObjects::MySQL::Dataset.new(self, opts)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# The database name for the given database. Need to parse it out
|
20
|
+
# of the connection string, since the DataObjects does no parsing on the
|
21
|
+
# given connection string by default.
|
22
|
+
def database_name
|
23
|
+
(m = /\/(.*)/.match(URI.parse(uri).path)) && m[1]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Dataset class for MySQL datasets accessed via DataObjects.
|
28
|
+
class Dataset < DataObjects::Dataset
|
29
|
+
include Sequel::MySQL::DatasetMethods
|
30
|
+
|
31
|
+
# Use execute_insert to execute the replace_sql.
|
32
|
+
def replace(*args)
|
33
|
+
execute_insert(replace_sql(*args))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'sequel_core/adapters/shared/postgres'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
Postgres::CONVERTED_EXCEPTIONS << PostgresError
|
5
|
+
|
6
|
+
module DataObjects
|
7
|
+
# Adapter, Database, and Dataset support for accessing a PostgreSQL
|
8
|
+
# database via DataObjects.
|
9
|
+
module Postgres
|
10
|
+
# Methods to add to the DataObjects adapter/connection to allow it to work
|
11
|
+
# with the shared PostgreSQL code.
|
12
|
+
module AdapterMethods
|
13
|
+
include Sequel::Postgres::AdapterMethods
|
14
|
+
|
15
|
+
# Give the DataObjects adapter a direct execute method, which creates
|
16
|
+
# a statement with the given sql and executes it.
|
17
|
+
def execute(sql, args=nil)
|
18
|
+
command = create_command(sql)
|
19
|
+
begin
|
20
|
+
if block_given?
|
21
|
+
begin
|
22
|
+
reader = command.execute_reader
|
23
|
+
yield(reader)
|
24
|
+
ensure
|
25
|
+
reader.close if reader
|
26
|
+
end
|
27
|
+
else
|
28
|
+
command.execute_non_query
|
29
|
+
end
|
30
|
+
rescue PostgresError => e
|
31
|
+
raise_error(e)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# DataObjects specific method of getting specific values from a result set.
|
38
|
+
def single_value(reader)
|
39
|
+
while(reader.next!) do
|
40
|
+
return reader.values.at(0)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Methods to add to Database instances that access PostgreSQL via
|
46
|
+
# DataObjects.
|
47
|
+
module DatabaseMethods
|
48
|
+
include Sequel::Postgres::DatabaseMethods
|
49
|
+
|
50
|
+
# Add the primary_keys and primary_key_sequences instance variables,
|
51
|
+
# so we can get the correct return values for inserted rows.
|
52
|
+
def self.extended(db)
|
53
|
+
db.instance_eval do
|
54
|
+
@primary_keys = {}
|
55
|
+
@primary_key_sequences = {}
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Return instance of Sequel::DataObjects::Postgres::Dataset with the given opts.
|
60
|
+
def dataset(opts=nil)
|
61
|
+
Sequel::DataObjects::Postgres::Dataset.new(self, opts)
|
62
|
+
end
|
63
|
+
|
64
|
+
# Run the INSERT sql on the database and return the primary key
|
65
|
+
# for the record.
|
66
|
+
def execute_insert(sql, opts={})
|
67
|
+
log_info(sql)
|
68
|
+
synchronize(opts[:server]) do |conn|
|
69
|
+
conn.create_command(sql).execute_non_query
|
70
|
+
insert_result(conn, opts[:table], opts[:values])
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Extend the adapter with the DataObjects PostgreSQL AdapterMethods
|
77
|
+
def setup_connection(conn)
|
78
|
+
conn = super(conn)
|
79
|
+
conn.extend(Sequel::DataObjects::Postgres::AdapterMethods)
|
80
|
+
conn.db = self
|
81
|
+
conn.apply_connection_settings
|
82
|
+
conn
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Dataset subclass used for datasets that connect to PostgreSQL via DataObjects.
|
87
|
+
class Dataset < DataObjects::Dataset
|
88
|
+
include Sequel::Postgres::DatasetMethods
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'sequel_core/adapters/shared/sqlite'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
module DataObjects
|
5
|
+
# Database and Dataset support for SQLite databases accessed via DataObjects.
|
6
|
+
module SQLite
|
7
|
+
# Instance methods for SQLite Database objects accessed via DataObjects.
|
8
|
+
module DatabaseMethods
|
9
|
+
include Sequel::SQLite::DatabaseMethods
|
10
|
+
|
11
|
+
# Return Sequel::DataObjects::SQLite::Dataset object with the given opts.
|
12
|
+
def dataset(opts=nil)
|
13
|
+
Sequel::DataObjects::SQLite::Dataset.new(self, opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Default to a single connection for a memory database.
|
19
|
+
def connection_pool_default_options
|
20
|
+
o = super
|
21
|
+
uri == 'sqlite3::memory:' ? o.merge(:max_connections=>1) : o
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Dataset class for SQLite datasets accessed via DataObjects.
|
26
|
+
class Dataset < DataObjects::Dataset
|
27
|
+
include Sequel::SQLite::DatasetMethods
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,298 @@
|
|
1
|
+
require 'fb'
|
2
|
+
|
3
|
+
module Sequel
|
4
|
+
# The Sequel Firebird adapter requires the ruby fb driver located at
|
5
|
+
# http://github.com/wishdev/fb.
|
6
|
+
module Firebird
|
7
|
+
class Database < Sequel::Database
|
8
|
+
set_adapter_scheme :firebird
|
9
|
+
|
10
|
+
AUTO_INCREMENT = ''.freeze
|
11
|
+
|
12
|
+
# Add the primary_keys and primary_key_sequences instance variables,
|
13
|
+
# so we can get the correct return values for inserted rows.
|
14
|
+
def initialize(*args)
|
15
|
+
super
|
16
|
+
@primary_keys = {}
|
17
|
+
@primary_key_sequences = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# Use Firebird specific syntax for add column
|
21
|
+
def alter_table_sql(table, op)
|
22
|
+
case op[:op]
|
23
|
+
when :add_column
|
24
|
+
"ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
|
25
|
+
when :drop_column
|
26
|
+
"ALTER TABLE #{quote_schema_table(table)} DROP #{column_definition_sql(op)}"
|
27
|
+
when :rename_column
|
28
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
|
29
|
+
when :set_column_type
|
30
|
+
"ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TYPE #{type_literal(op)}"
|
31
|
+
else
|
32
|
+
super(table, op)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def auto_increment_sql()
|
37
|
+
AUTO_INCREMENT
|
38
|
+
end
|
39
|
+
|
40
|
+
def connect(server)
|
41
|
+
opts = server_opts(server)
|
42
|
+
|
43
|
+
db = Fb::Database.new(
|
44
|
+
:database => "#{opts[:host]}:#{opts[:database]}",
|
45
|
+
:username => opts[:user],
|
46
|
+
:password => opts[:password])
|
47
|
+
conn = db.connect
|
48
|
+
conn.downcase_names = true
|
49
|
+
conn
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_sequence_sql(name, opts={})
|
53
|
+
"CREATE SEQUENCE #{quote_identifier(name)}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Creates a table with the columns given in the provided block:
|
57
|
+
#
|
58
|
+
# DB.create_table :posts do
|
59
|
+
# primary_key :id, :serial
|
60
|
+
# column :title, :text
|
61
|
+
# column :content, :text
|
62
|
+
# index :title
|
63
|
+
# end
|
64
|
+
#
|
65
|
+
# See Schema::Generator.
|
66
|
+
# Firebird gets an override because of the mess of creating a
|
67
|
+
# generator for auto-incrementing primary keys.
|
68
|
+
def create_table(name, options={}, &block)
|
69
|
+
options = {:generator=>options} if options.is_a?(Schema::Generator)
|
70
|
+
statements = create_table_sql_list(name, *((options[:generator] ||= Schema::Generator.new(self, &block)).create_info << options))
|
71
|
+
begin
|
72
|
+
execute_ddl(statements[1])
|
73
|
+
rescue
|
74
|
+
nil
|
75
|
+
end if statements[1]
|
76
|
+
statements[0].flatten.each {|sql| execute_ddl(sql)}
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_table_sql_list(name, columns, indexes = nil, options={})
|
80
|
+
statements = super
|
81
|
+
drop_seq_statement = nil
|
82
|
+
columns.each do |c|
|
83
|
+
if c[:auto_increment]
|
84
|
+
c[:sequence_name] ||= "seq_#{name}_#{c[:name]}"
|
85
|
+
unless c[:create_sequence] == false
|
86
|
+
drop_seq_statement = drop_sequence_sql(c[:sequence_name])
|
87
|
+
statements << create_sequence_sql(c[:sequence_name])
|
88
|
+
statements << restart_sequence_sql(c[:sequence_name], {:restart_position => c[:sequence_start_position]}) if c[:sequence_start_position]
|
89
|
+
end
|
90
|
+
unless c[:create_trigger] == false
|
91
|
+
c[:trigger_name] ||= "BI_#{name}_#{c[:name]}"
|
92
|
+
c[:quoted_name] = quote_identifier(c[:name])
|
93
|
+
trigger_definition = <<-END
|
94
|
+
begin
|
95
|
+
if ((new.#{c[:quoted_name]} is null) or (new.#{c[:quoted_name]} = 0)) then
|
96
|
+
begin
|
97
|
+
new.#{c[:quoted_name]} = next value for #{c[:sequence_name]};
|
98
|
+
end
|
99
|
+
end
|
100
|
+
END
|
101
|
+
statements << create_trigger_sql(name, c[:trigger_name], trigger_definition, {:events => [:insert]})
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
[statements, drop_seq_statement]
|
106
|
+
end
|
107
|
+
|
108
|
+
def create_trigger(*args)
|
109
|
+
self << create_trigger_sql(*args)
|
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[:position] ? opts[: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 dataset(opts = nil)
|
126
|
+
Firebird::Dataset.new(self, opts)
|
127
|
+
end
|
128
|
+
|
129
|
+
def drop_sequence(name)
|
130
|
+
self << drop_sequence_sql(name)
|
131
|
+
end
|
132
|
+
|
133
|
+
def drop_sequence_sql(name)
|
134
|
+
"DROP SEQUENCE #{quote_identifier(name)}"
|
135
|
+
end
|
136
|
+
|
137
|
+
def execute(sql, opts={})
|
138
|
+
log_info(sql)
|
139
|
+
begin
|
140
|
+
synchronize(opts[:server]) do |conn|
|
141
|
+
r = conn.execute(sql)
|
142
|
+
yield(r) if block_given?
|
143
|
+
r
|
144
|
+
end
|
145
|
+
rescue => e
|
146
|
+
log_info(e.message)
|
147
|
+
raise_error(e, :classes=>[Fb::Error])
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Return primary key for the given table.
|
152
|
+
def primary_key(table, server=nil)
|
153
|
+
synchronize(server){|conn| primary_key_for_table(conn, table)}
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns primary key for the given table. This information is
|
157
|
+
# cached, and if the primary key for a table is changed, the
|
158
|
+
# @primary_keys instance variable should be reset manually.
|
159
|
+
def primary_key_for_table(conn, table)
|
160
|
+
@primary_keys[quote_identifier(table)] ||= conn.table_primary_key(quote_identifier(table))
|
161
|
+
end
|
162
|
+
|
163
|
+
def restart_sequence(*args)
|
164
|
+
self << restart_sequence_sql(*args)
|
165
|
+
end
|
166
|
+
|
167
|
+
def restart_sequence_sql(name, opts={})
|
168
|
+
seq_name = quote_identifier(name)
|
169
|
+
"ALTER SEQUENCE #{seq_name} RESTART WITH #{opts[:restart_position]}"
|
170
|
+
end
|
171
|
+
|
172
|
+
def sequences(opts={})
|
173
|
+
ds = self[:"rdb$generators"].server(opts[:server]).filter(:"rdb$system_flag" => 0).select(:"rdb$generator_name")
|
174
|
+
block_given? ? yield(ds) : ds.map{|r| ds.send(:output_identifier, r[:"rdb$generator_name"])}
|
175
|
+
end
|
176
|
+
|
177
|
+
def tables(opts={})
|
178
|
+
ds = self[:"rdb$relations"].server(opts[:server]).filter(:"rdb$view_blr" => nil, Sequel::SQL::Function.new(:COALESCE, :"rdb$system_flag", 0) => 0).select(:"rdb$relation_name")
|
179
|
+
block_given? ? yield(ds) : ds.map{|r| ds.send(:output_identifier, r[:"rdb$relation_name"])}
|
180
|
+
end
|
181
|
+
|
182
|
+
def transaction(server=nil)
|
183
|
+
synchronize(server) do |conn|
|
184
|
+
return yield(conn) if @transactions.include?(Thread.current)
|
185
|
+
log_info("Transaction.begin")
|
186
|
+
conn.transaction
|
187
|
+
begin
|
188
|
+
@transactions << Thread.current
|
189
|
+
yield(conn)
|
190
|
+
rescue ::Exception => e
|
191
|
+
log_info("Transaction.rollback")
|
192
|
+
conn.rollback
|
193
|
+
transaction_error(e, Fb::Error)
|
194
|
+
ensure
|
195
|
+
unless e
|
196
|
+
log_info("Transaction.commit")
|
197
|
+
conn.commit
|
198
|
+
end
|
199
|
+
@transactions.delete(Thread.current)
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
private
|
205
|
+
|
206
|
+
def disconnect_connection(c)
|
207
|
+
c.close
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
# Dataset class for Firebird datasets
|
212
|
+
class Dataset < Sequel::Dataset
|
213
|
+
include UnsupportedIntersectExcept
|
214
|
+
|
215
|
+
BOOL_TRUE = '1'.freeze
|
216
|
+
BOOL_FALSE = '0'.freeze
|
217
|
+
COMMA_SEPARATOR = ', '.freeze
|
218
|
+
FIREBIRD_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
|
219
|
+
SELECT_CLAUSE_ORDER = %w'distinct limit columns from join where group having compounds order'.freeze
|
220
|
+
|
221
|
+
# Yield all rows returned by executing the given SQL and converting
|
222
|
+
# the types.
|
223
|
+
def fetch_rows(sql, &block)
|
224
|
+
execute(sql) do |s|
|
225
|
+
begin
|
226
|
+
@columns = s.fields.map{|c| output_identifier(c.name)}
|
227
|
+
s.fetchall(:symbols_hash).each do |r|
|
228
|
+
h = {}
|
229
|
+
r.each{|k,v| h[output_identifier(k)] = v}
|
230
|
+
yield h
|
231
|
+
end
|
232
|
+
ensure
|
233
|
+
s.close
|
234
|
+
end
|
235
|
+
end
|
236
|
+
self
|
237
|
+
end
|
238
|
+
|
239
|
+
# Insert given values into the database.
|
240
|
+
def insert(*values)
|
241
|
+
if !@opts[:sql]
|
242
|
+
single_value(:sql=>insert_returning_pk_sql(*values))
|
243
|
+
else
|
244
|
+
execute_insert(insert_sql(*values), :table=>opts[:from].first,
|
245
|
+
:values=>values.size == 1 ? values.first : values)
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# Use the RETURNING clause to return the primary key of the inserted record, if it exists
|
250
|
+
def insert_returning_pk_sql(*values)
|
251
|
+
pk = db.primary_key(opts[:from].first)
|
252
|
+
insert_returning_sql(pk ? Sequel::SQL::Identifier.new(pk) : 'NULL'.lit, *values)
|
253
|
+
end
|
254
|
+
|
255
|
+
# Use the RETURNING clause to return the columns listed in returning.
|
256
|
+
def insert_returning_sql(returning, *values)
|
257
|
+
"#{insert_sql(*values)} RETURNING #{column_list(Array(returning))}"
|
258
|
+
end
|
259
|
+
|
260
|
+
# Insert a record returning the record inserted
|
261
|
+
def insert_select(*values)
|
262
|
+
single_record(:naked=>true, :sql=>insert_returning_sql(nil, *values))
|
263
|
+
end
|
264
|
+
|
265
|
+
def literal(v)
|
266
|
+
case v
|
267
|
+
when Time, DateTime
|
268
|
+
"#{v.strftime(FIREBIRD_TIMESTAMP_FORMAT)}.#{sprintf("%04d",v.usec / 100)}'"
|
269
|
+
when TrueClass
|
270
|
+
BOOL_TRUE
|
271
|
+
when FalseClass
|
272
|
+
BOOL_FALSE
|
273
|
+
else
|
274
|
+
super
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# The order of clauses in the SELECT SQL statement
|
279
|
+
def select_clause_order
|
280
|
+
SELECT_CLAUSE_ORDER
|
281
|
+
end
|
282
|
+
|
283
|
+
def select_limit_sql(sql, opts)
|
284
|
+
sql << " FIRST #{opts[:limit]}" if opts[:limit]
|
285
|
+
sql << " SKIP #{opts[:offset]}" if opts[:offset]
|
286
|
+
end
|
287
|
+
|
288
|
+
private
|
289
|
+
|
290
|
+
def hash_row(stmt, row)
|
291
|
+
@columns.inject({}) do |m, c|
|
292
|
+
m[c] = row.shift
|
293
|
+
m
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|