og 0.40.0 → 0.41.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/doc/RELEASES +26 -0
- data/lib/glue/taggable.rb +17 -8
- data/lib/og.rb +1 -1
- data/lib/og/adapter/mysql.rb +6 -6
- data/lib/og/adapter/oracle.old.rb +509 -0
- data/lib/og/adapter/oracle.rb +299 -0
- data/lib/og/adapter/oracle/override.rb +23 -0
- data/lib/og/adapter/oracle/utils.rb +9 -0
- data/lib/og/adapter/postgresql.rb +0 -16
- data/lib/og/adapter/postgresql/script.rb +2 -2
- data/lib/og/entity.rb +36 -13
- data/lib/og/markers.rb +10 -2
- data/lib/og/store/sql.rb +11 -14
- data/lib/og/store/sql/evolution.rb +1 -1
- data/test/glue/tc_taggable.rb +47 -12
- data/test/og/CONFIG.rb +1 -1
- data/test/og/store/tc_sti2.rb +23 -2
- data/test/og/tc_inheritance2.rb +5 -3
- data/test/og/tc_polymorphic.rb +40 -13
- data/test/og/tc_reldelete.rb +11 -2
- metadata +9 -4
data/doc/RELEASES
CHANGED
@@ -1,3 +1,29 @@
|
|
1
|
+
== Version 0.41.0
|
2
|
+
|
3
|
+
This is a bug fix release. As it fixes some important bugs of the
|
4
|
+
previous release, including a DOS vulnurability you are strongly
|
5
|
+
advised to update your version. However, you will also find
|
6
|
+
a new feature:
|
7
|
+
|
8
|
+
* Extended entity .finder method can now handle relations.
|
9
|
+
|
10
|
+
Post.find_by_title_and_forum_name(title,forumName)
|
11
|
+
|
12
|
+
class Forum
|
13
|
+
property :name, String
|
14
|
+
has_many :posts, Post
|
15
|
+
end
|
16
|
+
|
17
|
+
class Post
|
18
|
+
property :title, String
|
19
|
+
property :message, String
|
20
|
+
belongs_to :forum, Forum
|
21
|
+
end
|
22
|
+
|
23
|
+
'forum' is the :forum from belongs_to, 'name' is a property from the
|
24
|
+
relations. It creates a SQL subquery to find the correct forum_oid.
|
25
|
+
|
26
|
+
|
1
27
|
== Version 0.40.0
|
2
28
|
|
3
29
|
This is the biggest release yet! Tons of new wonderful features,
|
data/lib/glue/taggable.rb
CHANGED
@@ -70,7 +70,11 @@ class Tag
|
|
70
70
|
# Return all tagged objects from all categories.
|
71
71
|
|
72
72
|
def tagged
|
73
|
-
|
73
|
+
t = []
|
74
|
+
self.class.relations.each do |rel|
|
75
|
+
t += rel[:target_class].find_with_any_tag(name)
|
76
|
+
end
|
77
|
+
return t
|
74
78
|
end
|
75
79
|
|
76
80
|
# Helper method
|
@@ -79,8 +83,16 @@ class Tag
|
|
79
83
|
tags.inject(1) { |total, t| total += t.count }
|
80
84
|
end
|
81
85
|
|
86
|
+
#--
|
87
|
+
# gmosx: Extra check, useful for utf-8 names on urls.
|
88
|
+
#++
|
89
|
+
|
82
90
|
def to_s
|
83
|
-
@name
|
91
|
+
if /^\w+$/ =~ @name
|
92
|
+
@name
|
93
|
+
else
|
94
|
+
@oid.to_s
|
95
|
+
end
|
84
96
|
end
|
85
97
|
end
|
86
98
|
|
@@ -112,8 +124,6 @@ module Taggable
|
|
112
124
|
|
113
125
|
include Og::EntityMixin
|
114
126
|
|
115
|
-
many_to_many Tag
|
116
|
-
|
117
127
|
# Add a tag for this object.
|
118
128
|
|
119
129
|
def tag(the_tags, options = {})
|
@@ -227,10 +237,9 @@ module Taggable
|
|
227
237
|
end
|
228
238
|
|
229
239
|
def self.included(base)
|
230
|
-
Tag.
|
231
|
-
|
232
|
-
|
233
|
-
base.extend(ClassMethods)
|
240
|
+
Tag.many_to_many base
|
241
|
+
base.extend ClassMethods
|
242
|
+
base.many_to_many Tag
|
234
243
|
#--
|
235
244
|
# FIXME: Og should handle this automatically.
|
236
245
|
#++
|
data/lib/og.rb
CHANGED
data/lib/og/adapter/mysql.rb
CHANGED
@@ -141,22 +141,22 @@ class MysqlAdapter < SqlStore
|
|
141
141
|
# Start a transaction.
|
142
142
|
|
143
143
|
def start
|
144
|
-
# nop
|
145
|
-
|
144
|
+
# nop on myISAM based tables
|
145
|
+
exec_statement "START TRANSACTION"
|
146
146
|
end
|
147
147
|
|
148
148
|
# Commit a transaction.
|
149
149
|
|
150
150
|
def commit
|
151
|
-
# nop
|
152
|
-
|
151
|
+
# nop on myISAM based tables
|
152
|
+
exec_statement "COMMIT"
|
153
153
|
end
|
154
154
|
|
155
155
|
# Rollback a transaction.
|
156
156
|
|
157
157
|
def rollback
|
158
|
-
# nop
|
159
|
-
|
158
|
+
# nop on myISAM based tables
|
159
|
+
exec_statement "ROLLBACK"
|
160
160
|
end
|
161
161
|
|
162
162
|
def write_attr(s, a)
|
@@ -0,0 +1,509 @@
|
|
1
|
+
# * Matt Bowen <matt.bowen@farweststeel.com>
|
2
|
+
# * George Moschovitis <gm@navel.gr>
|
3
|
+
# (c) 2004-2005 Navel, all rights reserved.
|
4
|
+
# $Id: oracle.rb 266 2005-02-28 14:50:48Z gmosx $
|
5
|
+
|
6
|
+
require 'oracle'
|
7
|
+
|
8
|
+
require 'og/store/sql'
|
9
|
+
#require 'og/adapter/oracle/override'
|
10
|
+
#require 'og/adapter/oracle/utils'
|
11
|
+
|
12
|
+
module Og
|
13
|
+
|
14
|
+
# The Oracle adapter. This adapter communicates with
|
15
|
+
# an Oracle rdbms. For extra documentation see
|
16
|
+
# lib/og/adapter.rb
|
17
|
+
|
18
|
+
class OracleAdapter < SqlStore
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super
|
22
|
+
|
23
|
+
@typemap.update(
|
24
|
+
Integer => 'number',
|
25
|
+
Fixnum => 'number',
|
26
|
+
String => 'varchar2(1024)', # max might be 4000 (Oracle 8)
|
27
|
+
TrueClass => 'char(1)',
|
28
|
+
Numeric => 'number',
|
29
|
+
Object => 'varchar2(1024)',
|
30
|
+
Array => 'varchar2(1024)',
|
31
|
+
Hash => 'varchar2(1024)'
|
32
|
+
)
|
33
|
+
|
34
|
+
# TODO: how to pass address etc?
|
35
|
+
@store = Oracle.new(config[:user], config[:password], config[:database])
|
36
|
+
# gmosx: better use this???
|
37
|
+
# @store = Oracle.new(config[:tns])
|
38
|
+
|
39
|
+
# gmosx: does this work?
|
40
|
+
@store.autocommit = true
|
41
|
+
rescue Exception => ex
|
42
|
+
# mcb:
|
43
|
+
# Oracle will raise a ORA-01017 if username, password, or
|
44
|
+
# SID aren't valid. I verified this for all three.
|
45
|
+
# irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
|
46
|
+
# /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017: invalid username/password; logon denied (OCIError)
|
47
|
+
if database_does_not_exist_exception? ex
|
48
|
+
Logger.info "Database '#{options[:name]}' not found!"
|
49
|
+
create_db(options)
|
50
|
+
retry
|
51
|
+
end
|
52
|
+
raise
|
53
|
+
end
|
54
|
+
|
55
|
+
def close
|
56
|
+
@store.logoff
|
57
|
+
super
|
58
|
+
end
|
59
|
+
|
60
|
+
#--
|
61
|
+
# mcb:
|
62
|
+
# Unlike MySQL or Postgres, Oracle database/schema creation is a big deal.
|
63
|
+
# I don't know how to do it from the command line. I use Oracle's Database
|
64
|
+
# Configuration Assistant utility (dbca). I takes 30min - 1hr to create
|
65
|
+
# a full blown schema. So, your FIXME comments are fine. I'm thinking you
|
66
|
+
# won't be able to do this via Og, but once created, Og will be able to
|
67
|
+
# create tables, indexes, and other objects.
|
68
|
+
#++
|
69
|
+
|
70
|
+
def create_db(database, user = nil, password = nil)
|
71
|
+
# FIXME: what is appropriate for oracle?
|
72
|
+
# `createdb #{database} -U #{user}`
|
73
|
+
super
|
74
|
+
raise NotImplementedError, "Oracle Database/Schema creation n/a"
|
75
|
+
end
|
76
|
+
|
77
|
+
def drop_db(database, user = nil, password = nil)
|
78
|
+
# FIXME: what is appropriate for oracle?
|
79
|
+
# `dropdb #{database} -U #{user}`
|
80
|
+
super
|
81
|
+
raise NotImplementedError, "Oracle Database/Schema dropping n/a"
|
82
|
+
end
|
83
|
+
|
84
|
+
# The type used for default primary keys.
|
85
|
+
|
86
|
+
def primary_key_type
|
87
|
+
'integer PRIMARY KEY'
|
88
|
+
end
|
89
|
+
|
90
|
+
def enchant(klass, manager)
|
91
|
+
pk = klass.primary_key
|
92
|
+
|
93
|
+
seq = if klass.schema_inheritance_child?
|
94
|
+
"#{table(klass.schema_inheritance_root_class)}_#{pk}_seq"
|
95
|
+
else
|
96
|
+
"#{table(klass)}_#{pk}_seq"
|
97
|
+
end
|
98
|
+
|
99
|
+
pkann = klass.ann[pk]
|
100
|
+
|
101
|
+
pkann[:sequence] = seq unless pkann[:sequence] == false
|
102
|
+
|
103
|
+
super
|
104
|
+
end
|
105
|
+
|
106
|
+
def query_statement(sql)
|
107
|
+
return @conn.exec(sql)
|
108
|
+
end
|
109
|
+
|
110
|
+
def exec_statement(sql)
|
111
|
+
@conn.exec(sql).clear
|
112
|
+
end
|
113
|
+
|
114
|
+
def sql_update(sql)
|
115
|
+
Logger.debug sql if $DBG
|
116
|
+
res = @conn.exec(sql)
|
117
|
+
changed = res.cmdtuples
|
118
|
+
res.clear
|
119
|
+
return changed
|
120
|
+
end
|
121
|
+
|
122
|
+
# Return the last inserted row id.
|
123
|
+
|
124
|
+
def last_insert_id(klass)
|
125
|
+
seq = klass.ann[klass.primary_key][:sequence]
|
126
|
+
|
127
|
+
res = query_statement("SELECT #{seq}.nextval FROM DUAL")
|
128
|
+
lid = Integer(res.first_value)
|
129
|
+
res.close
|
130
|
+
|
131
|
+
return lid
|
132
|
+
end
|
133
|
+
|
134
|
+
# The insert sql statements.
|
135
|
+
|
136
|
+
def insert_sql(sql, klass)
|
137
|
+
str = ''
|
138
|
+
|
139
|
+
if klass.ann[klass.primary_key][:sequence]
|
140
|
+
str << "@#{klass.primary_key} = store.last_insert_id(#{klass})\n"
|
141
|
+
end
|
142
|
+
|
143
|
+
str << "store.exec \"#{sql}\""
|
144
|
+
|
145
|
+
return str
|
146
|
+
end
|
147
|
+
|
148
|
+
# :section: Transaction methods.
|
149
|
+
|
150
|
+
# Start a new transaction.
|
151
|
+
|
152
|
+
def start
|
153
|
+
@store.autocommit = false
|
154
|
+
|
155
|
+
@transaction_nesting += 1
|
156
|
+
end
|
157
|
+
|
158
|
+
# Commit a transaction.
|
159
|
+
|
160
|
+
def commit
|
161
|
+
@transaction_nesting -= 1
|
162
|
+
@store.commit if @transaction_nesting < 1
|
163
|
+
ensure
|
164
|
+
@store.autocommit = true
|
165
|
+
end
|
166
|
+
|
167
|
+
# Rollback a transaction.
|
168
|
+
|
169
|
+
def rollback
|
170
|
+
@transaction_nesting -= 1
|
171
|
+
@store.rollbackif @transaction_nesting < 1
|
172
|
+
ensure
|
173
|
+
@store.autocommit = true
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
def create_table(klass)
|
178
|
+
super
|
179
|
+
|
180
|
+
seq = klass.ann[klass.primary_key][:sequence]
|
181
|
+
# Create the sequence for this table.
|
182
|
+
begin
|
183
|
+
exec_statement("CREATE SEQUENCE #{seq}")
|
184
|
+
Logger.info "Created sequence '#{seq}'."
|
185
|
+
rescue Exception => ex
|
186
|
+
# gmosx: any idea how to better test this?
|
187
|
+
if table_already_exists_exception?(ex)
|
188
|
+
Logger.debug "Sequence #{seq} already exists" if $DBG
|
189
|
+
else
|
190
|
+
raise
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
def drop_table(klass)
|
197
|
+
super
|
198
|
+
exec_statement("DROP SEQUENCE #{klass.ann[klass.primary_key][:sequence]}")
|
199
|
+
end
|
200
|
+
|
201
|
+
def read_attr(s, a, col)
|
202
|
+
store = self.class
|
203
|
+
{
|
204
|
+
String => nil,
|
205
|
+
Integer => :parse_int,
|
206
|
+
Float => :parse_float,
|
207
|
+
Time => :parse_timestamp,
|
208
|
+
Date => :parse_date,
|
209
|
+
TrueClass => :parse_boolean,
|
210
|
+
Og::Blob => :parse_blob
|
211
|
+
}.each do |klass, meth|
|
212
|
+
if a.class.ancestor? klass
|
213
|
+
return meth ?
|
214
|
+
"#{store}.#{meth}(res[#{col} + offset])" : "res[#{col} + offset]"
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
# else try to load it via YAML
|
219
|
+
"YAML::load(res[#{col} + offset])"
|
220
|
+
end
|
221
|
+
|
222
|
+
=begin
|
223
|
+
def calc_field_index(klass, db)
|
224
|
+
# gmosx: This is incredible!!! argh!
|
225
|
+
# res = db.query "SELECT * FROM #{klass::DBTABLE} # LIMIT 1"
|
226
|
+
res = db.query "SELECT * FROM (SELECT * FROM #{klass::DBTABLE}) WHERE ROWNUM <= 1"
|
227
|
+
meta = db.managed_classes[klass]
|
228
|
+
|
229
|
+
columns = res.getColNames
|
230
|
+
|
231
|
+
for idx in (0...columns.size)
|
232
|
+
# mcb: Oracle will return column names in uppercase.
|
233
|
+
meta.field_index[columns[idx].downcase] = idx
|
234
|
+
end
|
235
|
+
|
236
|
+
ensure
|
237
|
+
res.close if res
|
238
|
+
end
|
239
|
+
|
240
|
+
def eval_og_oid(klass)
|
241
|
+
klass.class_eval %{
|
242
|
+
prop_accessor :oid, Fixnum, :sql => "number PRIMARY KEY"
|
243
|
+
}
|
244
|
+
end
|
245
|
+
|
246
|
+
def create_table(klass, db)
|
247
|
+
conn = db.get_connection
|
248
|
+
|
249
|
+
fields = create_fields(klass)
|
250
|
+
|
251
|
+
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
252
|
+
|
253
|
+
# Create table constrains.
|
254
|
+
|
255
|
+
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
256
|
+
sql << ", #{constrains.join(', ')}"
|
257
|
+
end
|
258
|
+
|
259
|
+
# mcb: Oracle driver chokes on semicolon.
|
260
|
+
sql << ")"
|
261
|
+
|
262
|
+
# mcb:
|
263
|
+
# Oracle driver appears to have problems executing multiple SQL
|
264
|
+
# statements in single exec() call. Chokes with or without semicolon
|
265
|
+
# delimiter. Solution: make separate calls for each statement.
|
266
|
+
|
267
|
+
begin
|
268
|
+
conn.store.exec(sql).close
|
269
|
+
Logger.info "Created table '#{klass::DBTABLE}'."
|
270
|
+
|
271
|
+
# Create indices.
|
272
|
+
|
273
|
+
if klass.__meta and indices = klass.__meta[:sql_index]
|
274
|
+
for data in indices
|
275
|
+
idx, options = *data
|
276
|
+
idx = idx.to_s
|
277
|
+
pre_sql, post_sql = options[:pre], options[:post]
|
278
|
+
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
279
|
+
sql = " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx})"
|
280
|
+
conn.store.exec(sql).close
|
281
|
+
Logger.info "Created index '#{klass::DBTABLE}_#{idxname}_idx'."
|
282
|
+
end
|
283
|
+
end
|
284
|
+
rescue Exception => ex
|
285
|
+
# gmosx: any idea how to better test this?
|
286
|
+
if table_already_exists_exception?(ex)
|
287
|
+
Logger.debug 'Table or index already exists' if $DBG
|
288
|
+
return
|
289
|
+
else
|
290
|
+
raise
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# Create the sequence for this table.
|
295
|
+
begin
|
296
|
+
conn.store.exec("CREATE SEQUENCE #{klass::DBSEQ}").close
|
297
|
+
Logger.info "Created sequence '#{klass::DBSEQ}'."
|
298
|
+
rescue Exception => ex
|
299
|
+
# gmosx: any idea how to better test this?
|
300
|
+
if table_already_exists_exception?(ex)
|
301
|
+
Logger.debug "Sequence already exists" if $DBG
|
302
|
+
else
|
303
|
+
raise
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# Create join tables if needed. Join tables are used in
|
308
|
+
# 'many_to_many' relations.
|
309
|
+
|
310
|
+
if klass.__meta and joins = klass.__meta[:sql_join]
|
311
|
+
for data in joins
|
312
|
+
# the class to join to and some options.
|
313
|
+
join_class, options = *data
|
314
|
+
|
315
|
+
# gmosx: dont use DBTABLE here, perhaps the join class
|
316
|
+
# is not managed yet.
|
317
|
+
join_table = "#{self.class.join_table(klass, join_class)}"
|
318
|
+
join_src = "#{self.class.encode(klass)}_oid"
|
319
|
+
join_dst = "#{self.class.encode(join_class)}_oid"
|
320
|
+
begin
|
321
|
+
conn.store.exec("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").close
|
322
|
+
conn.store.exec("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").close
|
323
|
+
conn.store.exec("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").close
|
324
|
+
rescue Exception => ex
|
325
|
+
# gmosx: any idea how to better test this?
|
326
|
+
if table_already_exists_exception?(ex)
|
327
|
+
Logger.debug "Join table already exists" if $DBG
|
328
|
+
else
|
329
|
+
raise
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
ensure
|
336
|
+
db.put_connection
|
337
|
+
end
|
338
|
+
|
339
|
+
def drop_table(klass)
|
340
|
+
super
|
341
|
+
exec "DROP SEQUENCE #{klass::DBSEQ}"
|
342
|
+
end
|
343
|
+
|
344
|
+
# Generate the property for oid.
|
345
|
+
|
346
|
+
#--
|
347
|
+
# mcb:
|
348
|
+
# Oracle doesn't have a "serial" datatype. Replace with
|
349
|
+
# integer (which is probably just a synonym for NUMBER(38,0))
|
350
|
+
# A sequence is created automatically by Og.
|
351
|
+
#++
|
352
|
+
|
353
|
+
def eval_og_oid(klass)
|
354
|
+
klass.class_eval %{
|
355
|
+
prop_accessor :oid, Fixnum, :sql => 'integer PRIMARY KEY'
|
356
|
+
}
|
357
|
+
end
|
358
|
+
=end
|
359
|
+
private
|
360
|
+
|
361
|
+
def database_does_not_exist_exception?(ex)
|
362
|
+
ex.message =~ /ORA-01017/i
|
363
|
+
end
|
364
|
+
|
365
|
+
def table_already_exists_exception?(ex)
|
366
|
+
ex.message =~ /ORA-00955/i
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
=begin
|
372
|
+
# The Oracle connection.
|
373
|
+
|
374
|
+
class OracleConnection < Connection
|
375
|
+
|
376
|
+
# mcb:
|
377
|
+
# The database connection details are tucked away in a
|
378
|
+
# TNS entry (Transparent Network Substrate) which specifies host,
|
379
|
+
# port, protocol, and database instance. Here is a sample TNS
|
380
|
+
# entry:
|
381
|
+
#
|
382
|
+
# File: tns_names.ora
|
383
|
+
#
|
384
|
+
# KBSID =
|
385
|
+
# (DESCRIPTION =
|
386
|
+
# (ADDRESS_LIST =
|
387
|
+
# (ADDRESS = (PROTOCOL = TCP)(HOST = keebler.farweststeel.com)(PORT = 1521))
|
388
|
+
# )
|
389
|
+
# (CONNECT_DATA =
|
390
|
+
# (SID = KBSID)
|
391
|
+
# )
|
392
|
+
# )
|
393
|
+
|
394
|
+
def initialize(db)
|
395
|
+
super
|
396
|
+
config = db.config
|
397
|
+
|
398
|
+
begin
|
399
|
+
# FIXME: how to pass address etc?
|
400
|
+
@store = Oracle.new(config[:user], config[:password], config[:database])
|
401
|
+
# gmosx: better use this???
|
402
|
+
# @store = Oracle.new(config[:tns])
|
403
|
+
|
404
|
+
# gmosx: does this work?
|
405
|
+
@store.autocommit = true
|
406
|
+
rescue Exception => ex
|
407
|
+
# mcb:
|
408
|
+
# Oracle will raise a ORA-01017 if username, password, or
|
409
|
+
# SID aren't valid. I verified this for all three.
|
410
|
+
# irb(main):002:0> conn = Oracle.new('keebler', 'dfdfd', 'kbsid')
|
411
|
+
# /usr/local/lib/ruby/site_ruby/1.8/oracle.rb:27:in `logon': ORA-01017: invalid username/password; logon denied (OCIError)
|
412
|
+
# gmosx:
|
413
|
+
# any idea how to better test this? an integer error id?
|
414
|
+
if ex.to_s =~ /ORA-01017/i
|
415
|
+
Logger.info "Database '#{config[:database]}' not found!"
|
416
|
+
@db.adapter.create_db(config[:database], config[:user])
|
417
|
+
retry
|
418
|
+
end
|
419
|
+
raise
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def close
|
424
|
+
@store.logoff
|
425
|
+
super
|
426
|
+
end
|
427
|
+
|
428
|
+
def query(sql)
|
429
|
+
Logger.debug sql if $DBG
|
430
|
+
begin
|
431
|
+
return @store.exec(sql)
|
432
|
+
rescue Exception => ex
|
433
|
+
Logger.error "DB error #{ex}, [#{sql}]"
|
434
|
+
Logger.error ex.backtrace.join("\n")
|
435
|
+
raise
|
436
|
+
# return nil
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
def exec(sql)
|
441
|
+
Logger.debug sql if $DBG
|
442
|
+
begin
|
443
|
+
@store.exec(sql)
|
444
|
+
rescue Exception => ex
|
445
|
+
Logger.error "DB error #{ex}, [#{sql}]"
|
446
|
+
Logger.error ex.backtrace.join("\n")
|
447
|
+
raise
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
def start
|
452
|
+
@store.autocommit = false
|
453
|
+
end
|
454
|
+
|
455
|
+
def commit
|
456
|
+
@store.commit
|
457
|
+
ensure
|
458
|
+
@store.autocommit = true
|
459
|
+
end
|
460
|
+
|
461
|
+
def rollback
|
462
|
+
@store.rollback
|
463
|
+
ensure
|
464
|
+
@store.autocommit = true
|
465
|
+
end
|
466
|
+
|
467
|
+
def valid_res?(res)
|
468
|
+
return !(res.nil?)
|
469
|
+
end
|
470
|
+
|
471
|
+
def read_one(res, klass)
|
472
|
+
return nil unless valid_res?(res)
|
473
|
+
|
474
|
+
row = res.fetch
|
475
|
+
return nil unless row
|
476
|
+
|
477
|
+
obj = klass.new
|
478
|
+
obj.og_read(row)
|
479
|
+
|
480
|
+
res.close
|
481
|
+
return obj
|
482
|
+
end
|
483
|
+
|
484
|
+
def read_all(res, klass)
|
485
|
+
return [] unless valid_res?(res)
|
486
|
+
objects = []
|
487
|
+
|
488
|
+
while row = res.fetch
|
489
|
+
obj = klass.new
|
490
|
+
obj.og_read(row)
|
491
|
+
objects << obj
|
492
|
+
end
|
493
|
+
|
494
|
+
res.close
|
495
|
+
return objects
|
496
|
+
end
|
497
|
+
|
498
|
+
def read_int(res, idx = 0)
|
499
|
+
val = res.fetch[idx].to_i
|
500
|
+
res.close
|
501
|
+
return val
|
502
|
+
end
|
503
|
+
|
504
|
+
end
|
505
|
+
|
506
|
+
=end
|
507
|
+
|
508
|
+
end
|
509
|
+
|