sequel_core 1.5.1 → 2.0.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 +116 -0
- data/COPYING +19 -19
- data/README +83 -32
- data/Rakefile +9 -20
- data/bin/sequel +43 -112
- data/doc/cheat_sheet.rdoc +225 -0
- data/doc/dataset_filtering.rdoc +257 -0
- data/lib/sequel_core/adapters/adapter_skeleton.rb +4 -2
- data/lib/sequel_core/adapters/ado.rb +3 -1
- data/lib/sequel_core/adapters/db2.rb +4 -2
- data/lib/sequel_core/adapters/dbi.rb +127 -113
- data/lib/sequel_core/adapters/informix.rb +4 -2
- data/lib/sequel_core/adapters/jdbc.rb +5 -3
- data/lib/sequel_core/adapters/mysql.rb +112 -46
- data/lib/sequel_core/adapters/odbc.rb +5 -7
- data/lib/sequel_core/adapters/odbc_mssql.rb +12 -3
- data/lib/sequel_core/adapters/openbase.rb +3 -1
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +261 -262
- data/lib/sequel_core/adapters/sqlite.rb +72 -22
- data/lib/sequel_core/connection_pool.rb +140 -73
- data/lib/sequel_core/core_ext.rb +201 -66
- data/lib/sequel_core/core_sql.rb +123 -153
- data/lib/sequel_core/database/schema.rb +156 -0
- data/lib/sequel_core/database.rb +321 -338
- data/lib/sequel_core/dataset/callback.rb +11 -12
- data/lib/sequel_core/dataset/convenience.rb +213 -240
- data/lib/sequel_core/dataset/pagination.rb +58 -43
- data/lib/sequel_core/dataset/parse_tree_sequelizer.rb +331 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sequelizer.rb +41 -373
- data/lib/sequel_core/dataset/sql.rb +741 -632
- data/lib/sequel_core/dataset.rb +183 -168
- data/lib/sequel_core/deprecated.rb +1 -169
- data/lib/sequel_core/exceptions.rb +24 -19
- data/lib/sequel_core/migration.rb +44 -52
- data/lib/sequel_core/object_graph.rb +43 -42
- data/lib/sequel_core/pretty_table.rb +71 -76
- data/lib/sequel_core/schema/generator.rb +163 -105
- data/lib/sequel_core/schema/sql.rb +250 -93
- data/lib/sequel_core/schema.rb +2 -8
- data/lib/sequel_core/sql.rb +394 -0
- data/lib/sequel_core/worker.rb +37 -27
- data/lib/sequel_core.rb +99 -45
- data/spec/adapters/informix_spec.rb +0 -1
- data/spec/adapters/mysql_spec.rb +177 -124
- data/spec/adapters/oracle_spec.rb +0 -1
- data/spec/adapters/postgres_spec.rb +98 -58
- data/spec/adapters/sqlite_spec.rb +45 -4
- data/spec/blockless_filters_spec.rb +269 -0
- data/spec/connection_pool_spec.rb +21 -18
- data/spec/core_ext_spec.rb +169 -19
- data/spec/core_sql_spec.rb +56 -49
- data/spec/database_spec.rb +78 -17
- data/spec/dataset_spec.rb +300 -428
- data/spec/migration_spec.rb +1 -1
- data/spec/object_graph_spec.rb +5 -11
- data/spec/rcov.opts +1 -1
- data/spec/schema_generator_spec.rb +16 -4
- data/spec/schema_spec.rb +89 -10
- data/spec/sequelizer_spec.rb +56 -56
- data/spec/spec.opts +0 -5
- data/spec/spec_config.rb +7 -0
- data/spec/spec_config.rb.example +5 -5
- data/spec/spec_helper.rb +6 -0
- data/spec/worker_spec.rb +1 -1
- metadata +78 -63
@@ -1,198 +1,191 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
unless methods.include?('quote')
|
10
|
-
def self.quote(obj)
|
11
|
-
case obj
|
12
|
-
when true
|
13
|
-
TRUE
|
14
|
-
when false
|
15
|
-
FALSE
|
16
|
-
when nil
|
17
|
-
NULL
|
18
|
-
when String
|
19
|
-
"'#{obj}'"
|
20
|
-
else
|
21
|
-
obj.to_s
|
22
|
-
end
|
1
|
+
begin
|
2
|
+
require 'pg'
|
3
|
+
rescue LoadError => e
|
4
|
+
begin
|
5
|
+
require 'postgres'
|
6
|
+
class PGconn
|
7
|
+
metaalias :escape_string, :escape unless self.respond_to?(:escape_string)
|
8
|
+
alias_method :finish, :close unless method_defined?(:finish)
|
23
9
|
end
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
value = "E#{value}" if value =~ /\\/
|
36
|
-
return value
|
37
|
-
end
|
38
|
-
alias_method :quote_without_proper_escaping, :quote
|
39
|
-
alias_method :quote, :quote_with_proper_escaping
|
40
|
-
end
|
10
|
+
class PGresult
|
11
|
+
alias_method :nfields, :num_fields unless method_defined?(:nfields)
|
12
|
+
alias_method :ntuples, :num_tuples unless method_defined?(:ntuples)
|
13
|
+
alias_method :ftype, :type unless method_defined?(:ftype)
|
14
|
+
alias_method :fname, :fieldname unless method_defined?(:fname)
|
15
|
+
alias_method :cmd_tuples, :cmdtuples unless method_defined?(:cmd_tuples)
|
16
|
+
end
|
17
|
+
rescue LoadError
|
18
|
+
raise e
|
19
|
+
end
|
20
|
+
end
|
41
21
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
q = async_exec(sql)
|
62
|
-
else
|
63
|
-
raise e
|
22
|
+
module Sequel
|
23
|
+
module Postgres
|
24
|
+
class Adapter < ::PGconn
|
25
|
+
# the pure-ruby postgres adapter does not have a quote method.
|
26
|
+
TRUE = 'true'.freeze
|
27
|
+
FALSE = 'false'.freeze
|
28
|
+
NULL = 'NULL'.freeze
|
29
|
+
|
30
|
+
def self.quote(obj)
|
31
|
+
case obj
|
32
|
+
when TrueClass
|
33
|
+
TRUE
|
34
|
+
when FalseClass
|
35
|
+
FALSE
|
36
|
+
when NilClass
|
37
|
+
NULL
|
38
|
+
else
|
39
|
+
"'#{escape_string(obj.to_s)}'"
|
40
|
+
end
|
64
41
|
end
|
65
|
-
end
|
66
|
-
begin
|
67
|
-
block ? block[q] : q.cmdtuples
|
68
|
-
ensure
|
69
|
-
q.clear
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
attr_accessor :transaction_in_progress
|
74
|
-
|
75
|
-
SELECT_CURRVAL = "SELECT currval('%s')".freeze
|
76
42
|
|
77
|
-
|
78
|
-
|
79
|
-
if !@table_sequences.include?(table)
|
80
|
-
pkey_and_seq = pkey_and_sequence(table)
|
81
|
-
if pkey_and_seq
|
82
|
-
@table_sequences[table] = pkey_and_seq[1]
|
43
|
+
def connected?
|
44
|
+
status == Adapter::CONNECTION_OK
|
83
45
|
end
|
84
|
-
end
|
85
|
-
if seq = @table_sequences[table]
|
86
|
-
r = async_query(SELECT_CURRVAL % seq)
|
87
|
-
return r[0][0].to_i unless r.nil? || (r.respond_to?(:empty?) && r.empty?)
|
88
|
-
end
|
89
|
-
nil # primary key sequence not found
|
90
|
-
end
|
91
46
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
47
|
+
def execute(sql, &block)
|
48
|
+
q = nil
|
49
|
+
begin
|
50
|
+
q = exec(sql)
|
51
|
+
rescue PGError => e
|
52
|
+
unless connected?
|
53
|
+
reset
|
54
|
+
q = exec(sql)
|
55
|
+
else
|
56
|
+
raise e
|
57
|
+
end
|
58
|
+
end
|
59
|
+
begin
|
60
|
+
block ? block[q] : q.cmd_tuples
|
61
|
+
ensure
|
62
|
+
q.clear
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_accessor :transaction_in_progress
|
67
|
+
|
68
|
+
SELECT_CURRVAL = "SELECT currval('%s')".freeze
|
69
|
+
|
70
|
+
def last_insert_id(table)
|
71
|
+
@table_sequences ||= {}
|
72
|
+
if !@table_sequences.include?(table)
|
73
|
+
pkey_and_seq = pkey_and_sequence(table)
|
74
|
+
if pkey_and_seq
|
75
|
+
@table_sequences[table] = pkey_and_seq[1]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if seq = @table_sequences[table]
|
79
|
+
execute(SELECT_CURRVAL % seq) do |r|
|
80
|
+
return r.getvalue(0,0).to_i unless r.nil? || (r.ntuples == 0)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
nil # primary key sequence not found
|
84
|
+
end
|
85
|
+
|
86
|
+
# Shamelessly appropriated from ActiveRecord's Postgresql adapter.
|
87
|
+
SELECT_PK_AND_SERIAL_SEQUENCE = <<-end_sql
|
88
|
+
SELECT attr.attname, name.nspname, seq.relname
|
89
|
+
FROM pg_class seq, pg_attribute attr, pg_depend dep,
|
90
|
+
pg_namespace name, pg_constraint cons
|
91
|
+
WHERE seq.oid = dep.objid
|
92
|
+
AND seq.relnamespace = name.oid
|
93
|
+
AND seq.relkind = 'S'
|
94
|
+
AND attr.attrelid = dep.refobjid
|
95
|
+
AND attr.attnum = dep.refobjsubid
|
96
|
+
AND attr.attrelid = cons.conrelid
|
97
|
+
AND attr.attnum = cons.conkey[1]
|
98
|
+
AND cons.contype = 'p'
|
99
|
+
AND dep.refobjid = '%s'::regclass
|
100
|
+
end_sql
|
101
|
+
|
102
|
+
SELECT_PK_AND_CUSTOM_SEQUENCE = <<-end_sql
|
103
|
+
SELECT attr.attname,
|
104
|
+
CASE
|
105
|
+
WHEN split_part(def.adsrc, '''', 2) ~ '.' THEN
|
106
|
+
substr(split_part(def.adsrc, '''', 2),
|
107
|
+
strpos(split_part(def.adsrc, '''', 2), '.')+1)
|
108
|
+
ELSE split_part(def.adsrc, '''', 2)
|
109
|
+
END
|
110
|
+
FROM pg_class t
|
111
|
+
JOIN pg_namespace name ON (t.relnamespace = name.oid)
|
112
|
+
JOIN pg_attribute attr ON (t.oid = attrelid)
|
113
|
+
JOIN pg_attrdef def ON (adrelid = attrelid AND adnum = attnum)
|
114
|
+
JOIN pg_constraint cons ON (conrelid = adrelid AND adnum = conkey[1])
|
115
|
+
WHERE t.oid = '%s'::regclass
|
116
|
+
AND cons.contype = 'p'
|
117
|
+
AND def.adsrc ~* 'nextval'
|
118
|
+
end_sql
|
119
|
+
|
120
|
+
SELECT_PK = <<-end_sql
|
121
|
+
SELECT pg_attribute.attname
|
122
|
+
FROM pg_class, pg_attribute, pg_index
|
123
|
+
WHERE pg_class.oid = pg_attribute.attrelid AND
|
124
|
+
pg_class.oid = pg_index.indrelid AND
|
125
|
+
pg_index.indkey[0] = pg_attribute.attnum AND
|
126
|
+
pg_index.indisprimary = 't' AND
|
127
|
+
pg_class.relname = '%s'
|
128
|
+
end_sql
|
129
|
+
|
130
|
+
def pkey_and_sequence(table)
|
131
|
+
execute(SELECT_PK_AND_SERIAL_SEQUENCE % table) do |r|
|
132
|
+
return [r.getvalue(0,2), r.getvalue(0,2)] unless r.nil? || (r.ntuples == 0)
|
133
|
+
end
|
134
|
+
|
135
|
+
execute(SELECT_PK_AND_CUSTOM_SEQUENCE % table) do |r|
|
136
|
+
return [r.getvalue(0,0), r.getvalue(0,1)] unless r.nil? || (r.ntuples == 0)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def primary_key(table)
|
141
|
+
execute(SELECT_PK % table) do |r|
|
142
|
+
if (r.nil? || (r.ntuples == 0)) then
|
143
|
+
return nil
|
144
|
+
else
|
145
|
+
r.getvalue(0,0)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.string_to_bool(s)
|
151
|
+
if(s.blank?)
|
152
|
+
nil
|
153
|
+
elsif(s.downcase == 't' || s.downcase == 'true')
|
154
|
+
true
|
155
|
+
else
|
156
|
+
false
|
157
|
+
end
|
158
|
+
end
|
161
159
|
end
|
162
|
-
end
|
163
|
-
end
|
164
160
|
|
165
|
-
module Sequel
|
166
|
-
module Postgres
|
167
161
|
PG_TYPES = {
|
168
|
-
16 =>
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
162
|
+
16 => lambda{ |s| Adapter.string_to_bool(s) },
|
163
|
+
17 => lambda{ |s| Adapter.unescape_bytea(s) },
|
164
|
+
20 => lambda{ |s| s.to_i },
|
165
|
+
21 => lambda{ |s| s.to_i },
|
166
|
+
22 => lambda{ |s| s.to_i },
|
167
|
+
23 => lambda{ |s| s.to_i },
|
168
|
+
26 => lambda{ |s| s.to_i },
|
169
|
+
700 => lambda{ |s| s.to_f },
|
170
|
+
701 => lambda{ |s| s.to_f },
|
171
|
+
790 => lambda{ |s| s.to_f },
|
172
|
+
1082 => lambda{ |s| s.to_date },
|
173
|
+
1083 => lambda{ |s| s.to_time },
|
174
|
+
1114 => lambda{ |s| s.to_time },
|
175
|
+
1184 => lambda{ |s| s.to_time },
|
176
|
+
1186 => lambda{ |s| s.to_i }
|
182
177
|
}
|
183
178
|
|
184
|
-
if
|
185
|
-
|
186
|
-
AUTO_TRANSLATE = true
|
187
|
-
else
|
188
|
-
AUTO_TRANSLATE = false
|
179
|
+
if Adapter.respond_to?(:translate_results=)
|
180
|
+
Adapter.translate_results = false
|
189
181
|
end
|
182
|
+
AUTO_TRANSLATE = false
|
190
183
|
|
191
184
|
class Database < Sequel::Database
|
192
185
|
set_adapter_scheme :postgres
|
193
186
|
|
194
187
|
def connect
|
195
|
-
conn =
|
188
|
+
conn = Adapter.connect(
|
196
189
|
@opts[:host] || 'localhost',
|
197
190
|
@opts[:port] || 5432,
|
198
191
|
'', '',
|
@@ -207,7 +200,7 @@ module Sequel
|
|
207
200
|
end
|
208
201
|
|
209
202
|
def disconnect
|
210
|
-
@pool.disconnect {|c| c.
|
203
|
+
@pool.disconnect {|c| c.finish}
|
211
204
|
end
|
212
205
|
|
213
206
|
def dataset(opts = nil)
|
@@ -229,11 +222,13 @@ module Sequel
|
|
229
222
|
end
|
230
223
|
|
231
224
|
def execute(sql, &block)
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
225
|
+
begin
|
226
|
+
log_info(sql)
|
227
|
+
@pool.hold {|conn| conn.execute(sql, &block)}
|
228
|
+
rescue => e
|
229
|
+
log_info(e.message)
|
230
|
+
raise convert_pgerror(e)
|
231
|
+
end
|
237
232
|
end
|
238
233
|
|
239
234
|
def primary_key_for_table(conn, table)
|
@@ -250,11 +245,7 @@ module Sequel
|
|
250
245
|
rescue PGError => e
|
251
246
|
# An error could occur if the inserted values include a primary key
|
252
247
|
# value, while the primary key is serial.
|
253
|
-
|
254
|
-
raise Error, "Could not return primary key value for the inserted record. Are you specifying a primary key value for a serial primary key?"
|
255
|
-
else
|
256
|
-
raise e
|
257
|
-
end
|
248
|
+
raise Error.new(e.message =~ RE_CURRVAL_ERROR ? "Could not return primary key value for the inserted record. Are you specifying a primary key value for a serial primary key?" : e.message)
|
258
249
|
end
|
259
250
|
|
260
251
|
case values
|
@@ -268,25 +259,34 @@ module Sequel
|
|
268
259
|
end
|
269
260
|
|
270
261
|
def server_version
|
271
|
-
@server_version
|
262
|
+
return @server_version if @server_version
|
263
|
+
@server_version = pool.hold do |conn|
|
272
264
|
if conn.respond_to?(:server_version)
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
265
|
+
begin
|
266
|
+
conn.server_version
|
267
|
+
rescue StandardError
|
268
|
+
nil
|
269
|
+
end
|
277
270
|
end
|
278
271
|
end
|
272
|
+
unless @server_version
|
273
|
+
m = /PostgreSQL (\d+)\.(\d+)\.(\d+)/.match(get(:version[]))
|
274
|
+
@server_version = (m[1].to_i * 10000) + (m[2].to_i * 100) + m[3].to_i
|
275
|
+
end
|
276
|
+
@server_version
|
279
277
|
end
|
280
278
|
|
281
279
|
def execute_insert(sql, table, values)
|
282
|
-
|
283
|
-
|
284
|
-
conn
|
285
|
-
|
280
|
+
begin
|
281
|
+
log_info(sql)
|
282
|
+
@pool.hold do |conn|
|
283
|
+
conn.execute(sql)
|
284
|
+
insert_result(conn, table, values)
|
285
|
+
end
|
286
|
+
rescue => e
|
287
|
+
log_info(e.message)
|
288
|
+
raise convert_pgerror(e)
|
286
289
|
end
|
287
|
-
rescue => e
|
288
|
-
@logger.error(e.message) if @logger
|
289
|
-
raise e
|
290
290
|
end
|
291
291
|
|
292
292
|
SQL_BEGIN = 'BEGIN'.freeze
|
@@ -298,24 +298,25 @@ module Sequel
|
|
298
298
|
if conn.transaction_in_progress
|
299
299
|
yield conn
|
300
300
|
else
|
301
|
-
|
302
|
-
conn.
|
301
|
+
log_info(SQL_BEGIN)
|
302
|
+
conn.execute(SQL_BEGIN)
|
303
303
|
begin
|
304
304
|
conn.transaction_in_progress = true
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
@logger.error(e.message) if @logger
|
311
|
-
raise e
|
312
|
-
end
|
313
|
-
result
|
314
|
-
rescue => e
|
315
|
-
@logger.info(SQL_ROLLBACK) if @logger
|
316
|
-
conn.async_exec(SQL_ROLLBACK) rescue nil
|
317
|
-
raise e unless Error::Rollback === e
|
305
|
+
yield
|
306
|
+
rescue ::Exception => e
|
307
|
+
log_info(SQL_ROLLBACK)
|
308
|
+
conn.execute(SQL_ROLLBACK) rescue nil
|
309
|
+
raise convert_pgerror(e) unless Error::Rollback === e
|
318
310
|
ensure
|
311
|
+
unless e
|
312
|
+
begin
|
313
|
+
log_info(SQL_COMMIT)
|
314
|
+
conn.execute(SQL_COMMIT)
|
315
|
+
rescue => e
|
316
|
+
log_info(e.message)
|
317
|
+
raise convert_pgerror(e)
|
318
|
+
end
|
319
|
+
end
|
319
320
|
conn.transaction_in_progress = nil
|
320
321
|
end
|
321
322
|
end
|
@@ -328,11 +329,11 @@ module Sequel
|
|
328
329
|
|
329
330
|
def index_definition_sql(table_name, index)
|
330
331
|
index_name = index[:name] || default_index_name(table_name, index[:columns])
|
331
|
-
expr =
|
332
|
+
expr = literal(Array(index[:columns]))
|
332
333
|
unique = "UNIQUE " if index[:unique]
|
333
334
|
index_type = index[:type]
|
334
335
|
filter = index[:where] || index[:filter]
|
335
|
-
filter = " WHERE #{
|
336
|
+
filter = " WHERE #{filter_expr(filter)}" if filter
|
336
337
|
case index_type
|
337
338
|
when :full_text
|
338
339
|
lang = index[:language] ? "#{literal(index[:language])}, " : ""
|
@@ -348,22 +349,41 @@ module Sequel
|
|
348
349
|
def drop_table_sql(name)
|
349
350
|
"DROP TABLE #{name} CASCADE"
|
350
351
|
end
|
352
|
+
|
353
|
+
private
|
354
|
+
# If the given exception is a PGError, return a Sequel::Error with the same message, otherwise
|
355
|
+
# just return the given exception
|
356
|
+
def convert_pgerror(e)
|
357
|
+
PGError === e ? Error.new(e.message) : e
|
358
|
+
end
|
359
|
+
|
360
|
+
# PostgreSQL currently can always reuse connections. It doesn't need the pool to convert exceptions, either.
|
361
|
+
def connection_pool_default_options
|
362
|
+
super.merge(:pool_reuse_connections=>:always, :pool_convert_exceptions=>false)
|
363
|
+
end
|
364
|
+
|
365
|
+
def schema_ds_filter(table_name, opts)
|
366
|
+
filt = super
|
367
|
+
# Restrict it to the given or public schema, unless specifically requesting :schema = nil
|
368
|
+
filt = SQL::ComplexExpression.new(:AND, filt, {:c__table_schema=>opts[:schema] || 'public'}) if opts[:schema] || !opts.include?(:schema)
|
369
|
+
filt
|
370
|
+
end
|
351
371
|
end
|
352
372
|
|
353
373
|
class Dataset < Sequel::Dataset
|
354
374
|
|
355
375
|
PG_TIMESTAMP_FORMAT = "TIMESTAMP '%Y-%m-%d %H:%M:%S".freeze
|
356
376
|
|
357
|
-
def quote_column_ref(c); "\"#{c}\""; end
|
358
|
-
|
359
377
|
def literal(v)
|
360
378
|
case v
|
361
379
|
when LiteralString
|
362
380
|
v
|
363
|
-
when String,
|
364
|
-
|
381
|
+
when String, TrueClass, FalseClass
|
382
|
+
Adapter.quote(v)
|
365
383
|
when Time
|
366
384
|
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d",v.usec)}'"
|
385
|
+
when DateTime
|
386
|
+
"#{v.strftime(PG_TIMESTAMP_FORMAT)}.#{sprintf("%06d", (v.sec_fraction * 86400000000).to_i)}'"
|
367
387
|
else
|
368
388
|
super
|
369
389
|
end
|
@@ -457,9 +477,9 @@ module Sequel
|
|
457
477
|
def multi_insert_sql(columns, values)
|
458
478
|
return super if @db.server_version < 80200
|
459
479
|
|
460
|
-
# postgresql 8.2 introduces support for insert
|
461
|
-
columns =
|
462
|
-
values = values.map {|r|
|
480
|
+
# postgresql 8.2 introduces support for multi-row insert
|
481
|
+
columns = column_list(columns)
|
482
|
+
values = values.map {|r| literal(Array(r))}.join(COMMA_SEPARATOR)
|
463
483
|
["INSERT INTO #{source_list(@opts[:from])} (#{columns}) VALUES #{values}"]
|
464
484
|
end
|
465
485
|
|
@@ -475,47 +495,26 @@ module Sequel
|
|
475
495
|
def delete(opts = nil)
|
476
496
|
@db.execute(delete_sql(opts))
|
477
497
|
end
|
478
|
-
|
479
|
-
def fetch_rows(sql, &block)
|
480
|
-
@db.execute(sql) do |q|
|
481
|
-
conv = row_converter(q)
|
482
|
-
q.each {|r| yield conv[r]}
|
483
|
-
end
|
484
|
-
end
|
485
|
-
|
486
|
-
@@converters_mutex = Mutex.new
|
487
|
-
@@converters = {}
|
488
498
|
|
489
|
-
def
|
490
|
-
@columns = []
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
used_columns = []
|
505
|
-
kvs = []
|
506
|
-
columns.each_with_index do |column, idx|
|
507
|
-
next if used_columns.include?(column)
|
508
|
-
used_columns << column
|
509
|
-
|
510
|
-
if !AUTO_TRANSLATE and translator = translators[idx]
|
511
|
-
kvs << ":\"#{column}\" => ((t = r[#{idx}]) ? t.#{translator} : nil)"
|
512
|
-
else
|
513
|
-
kvs << ":\"#{column}\" => r[#{idx}]"
|
499
|
+
def fetch_rows(sql, &block)
|
500
|
+
@columns = []
|
501
|
+
@db.execute(sql) do |res|
|
502
|
+
(0...res.ntuples).each do |recnum|
|
503
|
+
converted_rec = {}
|
504
|
+
(0...res.nfields).each do |fieldnum|
|
505
|
+
fieldsym = res.fname(fieldnum).to_sym
|
506
|
+
@columns << fieldsym
|
507
|
+
converted_rec[fieldsym] = if value = res.getvalue(recnum,fieldnum)
|
508
|
+
(PG_TYPES[res.ftype(fieldnum)] || lambda{|s| s.to_s}).call(value)
|
509
|
+
else
|
510
|
+
value
|
511
|
+
end
|
512
|
+
end
|
513
|
+
yield converted_rec
|
514
514
|
end
|
515
515
|
end
|
516
|
-
eval("lambda {|r| {#{kvs.join(COMMA_SEPARATOR)}}}")
|
517
516
|
end
|
518
|
-
|
519
517
|
end
|
520
518
|
end
|
521
519
|
end
|
520
|
+
|