og 0.40.0 → 0.41.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|