nitro 0.2.0 → 0.3.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 (76) hide show
  1. data/ChangeLog +186 -0
  2. data/README +40 -11
  3. data/RELEASES +10 -1
  4. data/Rakefile +5 -4
  5. data/bin/cluster.rb +3 -3
  6. data/{etc/new-project.rb → bin/new_app.rb} +1 -1
  7. data/examples/og/README +4 -0
  8. data/examples/og/run.rb +254 -0
  9. data/examples/simple/app.rb +3 -3
  10. data/examples/simple/conf/config.rb +10 -22
  11. data/examples/simple/conf/debug-config.rb +6 -32
  12. data/examples/simple/conf/live-config.rb +3 -23
  13. data/examples/simple/conf/requires.rb +5 -5
  14. data/examples/simple/env.rb +3 -4
  15. data/examples/simple/lib/articles/entities.rb +17 -15
  16. data/examples/simple/lib/articles/methods.rb +15 -15
  17. data/examples/simple/lib/articles/part.rb +7 -8
  18. data/examples/simple/root/comments.si +1 -1
  19. data/examples/simple/root/index.sx +1 -1
  20. data/examples/simple/root/view-article.sx +1 -2
  21. data/examples/tiny/app.rb +3 -3
  22. data/examples/tiny/conf/config.rb +4 -4
  23. data/examples/tiny/conf/requires.rb +3 -4
  24. data/lib/n/config.rb +50 -3
  25. data/lib/n/logger.rb +14 -2
  26. data/lib/n/og.rb +381 -0
  27. data/lib/n/og/backend.rb +252 -0
  28. data/lib/n/og/backends/mysql.rb +352 -0
  29. data/lib/n/og/backends/psql.rb +351 -0
  30. data/lib/n/og/connection.rb +253 -0
  31. data/lib/n/og/meta.rb +127 -0
  32. data/lib/n/properties.rb +6 -6
  33. data/lib/n/server.rb +4 -7
  34. data/lib/n/server/appserver.rb +58 -0
  35. data/lib/n/{app → server}/cluster.rb +3 -3
  36. data/lib/n/{app → server}/cookie.rb +3 -3
  37. data/lib/n/server/dispatcher.rb +55 -0
  38. data/lib/n/server/{filter.rb → filters.rb} +1 -1
  39. data/lib/n/{app → server}/filters/autologin.rb +5 -5
  40. data/lib/n/{app → server}/fragment.rb +3 -3
  41. data/lib/n/{app → server}/handlers.rb +4 -4
  42. data/lib/n/{app → server}/handlers/code-handler.rb +6 -6
  43. data/lib/n/{app → server}/handlers/page-handler.rb +9 -7
  44. data/lib/n/{app → server}/request.rb +8 -8
  45. data/lib/n/{app/request-part.rb → server/requestpart.rb} +4 -4
  46. data/lib/n/{app → server}/script.rb +5 -5
  47. data/lib/n/{app → server}/server.rb +1 -1
  48. data/lib/n/{app → server}/session.rb +5 -5
  49. data/lib/n/{app → server}/user.rb +1 -1
  50. data/lib/n/{app/webrick-servlet.rb → server/webrick.rb} +77 -20
  51. data/lib/n/shaders.rb +3 -2
  52. data/lib/n/std.rb +5 -32
  53. data/test/n/{app → server}/tc_cookie.rb +2 -2
  54. data/test/n/server/tc_filters.rb +38 -0
  55. data/test/n/{app → server}/tc_request.rb +6 -6
  56. data/test/n/{app → server}/tc_requestpart.rb +3 -3
  57. data/test/n/{app → server}/tc_session.rb +2 -2
  58. data/test/n/tc_og.rb +178 -0
  59. data/test/n/ui/tc_pager.rb +3 -3
  60. metadata +41 -65
  61. data/examples/ndb/README +0 -5
  62. data/examples/ndb/run.rb +0 -271
  63. data/lib/n/app/webrick.rb +0 -73
  64. data/lib/n/db.rb +0 -233
  65. data/lib/n/db/README +0 -232
  66. data/lib/n/db/connection.rb +0 -365
  67. data/lib/n/db/managed.rb +0 -233
  68. data/lib/n/db/mixins.rb +0 -279
  69. data/lib/n/db/mysql.rb +0 -345
  70. data/lib/n/db/psql.rb +0 -383
  71. data/lib/n/db/tools.rb +0 -106
  72. data/lib/n/db/utils.rb +0 -102
  73. data/lib/n/server/PLAYBACK.txt +0 -8
  74. data/lib/n/server/RESEARCH.txt +0 -13
  75. data/test/n/tc_db.rb +0 -223
  76. data/test/n/tc_db_mysql.rb +0 -241
data/lib/n/db/mysql.rb DELETED
@@ -1,345 +0,0 @@
1
- # = MySQL backend
2
- #
3
- # Implement the Db backend using the MySQL RDBMS.
4
- # Include the MySQL backend to the standard DbConnection
5
- # object to synthesize a MySQLConnection at runtime.
6
- #
7
- # EXPERIMENTAL: NOT WORKING YET
8
- #
9
- # code:
10
- # Elias Athanasopoulos <elathan@navel.gr>
11
- # George Moschovitis <gm@navel.gr>
12
- #
13
- # (c) 2004 Navel, all rights reserved.
14
- # $Id: mysql.rb 98 2004-10-22 07:36:20Z gmosx $
15
-
16
- require "mysql"
17
- require "time.rb"
18
- require "date.rb"
19
-
20
- module N;
21
-
22
- # = DbUtils
23
- #
24
- # Backend specific utils. Extend the base utils
25
- # collection.
26
- #
27
- module DbUtils
28
-
29
- # Escape an sql string
30
- #
31
- def self.escape(str)
32
- return nil unless str
33
- return Mysql.quote(str)
34
- end
35
-
36
- # Convert a ruby time to an sql timestamp.
37
- #
38
- def self.sql_timestamp(time = Time.now)
39
- return nil unless time
40
- return time.strftime("%Y-%m-%d %H:%M:%S")
41
- end
42
-
43
- # Output YYY-mm-dd
44
- #
45
- def self.sql_date(date)
46
- return nil unless date
47
- return "#{date.year}-#{date.month}-#{date.mday}"
48
- end
49
-
50
- # Parse sql datetime
51
- #
52
- # TODO: Optimize this
53
- #
54
- def self.parse_sql_timestamp(str)
55
- return Time.parse(str)
56
- end
57
-
58
- # Input YYYY-mm-dd
59
- #
60
- def self.parse_sql_date(str)
61
- return nil unless str
62
- return Date.strptime(str)
63
- end
64
-
65
- # Return an evaluator for reading the property
66
- # No need to optimize this, used only to precalculate code.
67
- #
68
- def self.read_prop(p, idx)
69
- case p.klass.to_s
70
- when Fixnum.name
71
- return "rows.getvalue(tuple, #{idx}).to_i()"
72
- when Float.name
73
- return "rows.getvalue(tuple, #{idx}).to_f()"
74
- when Time.name
75
- return "N::DbUtils.parse_sql_timestamp(rows.getvalue(tuple, #{idx}))"
76
- when Date.name
77
- return "N::DbUtils.parse_sql_date(rows.getvalue(tuple, #{idx}))"
78
- when TrueClass.name
79
- return "('true' == rows.getvalue(tuple, #{idx}))"
80
- else # String
81
- return "rows.getvalue(tuple, #{idx})"
82
- end
83
- end
84
- end
85
-
86
- # = MysqlBackend
87
- #
88
- # Implement the Db backend using the MySQL RDBMS.
89
- #
90
- module MysqlBackend
91
-
92
- # map between Ruby and SQL types
93
- #
94
- TYPEMAP = {
95
- Integer => "integer",
96
- Fixnum => "integer",
97
- Float => "float",
98
- String => "text",
99
- Time => "timestamp",
100
- Date => "date",
101
- TrueClass => "boolean",
102
- Array => "bytea",
103
- Hash => "bytea"
104
- }
105
-
106
- # Initialize a connection to the database
107
- #
108
- def initialize(config)
109
- @rdb = Mysql.connect(config[:address], config[:user], config[:password], config[:database])
110
- end
111
-
112
- # Close the connection to the database
113
- #
114
- def close()
115
- @rdb.close
116
- end
117
-
118
- # Create the sequence that generates the unified space id
119
- # oids. You *MUST* call this method on newly created
120
- # databases.
121
- #
122
- def create_schema()
123
- @rdb.query("CREATE SEQUENCE oids_seq")
124
- end
125
-
126
- # Drop the oid sequence
127
- #
128
- def drop_schema()
129
- @rdb.query("DROP SEQUENCE oids_seq")
130
- end
131
-
132
- # NOT IMPLEMENTED
133
- #
134
- def prepare_statement()
135
- @rdb.query("PREPARE")
136
- end
137
- alias_method :pstatement, :prepare_statement
138
-
139
- # NOT IMPLEMENTED
140
- #
141
- def execute_statement()
142
- self.select("EXECUTE")
143
- end
144
- alias_method :xstatement, :execute_statement
145
-
146
- # Create a table for an entity.
147
- #
148
- def create_table(klass)
149
- fields = []
150
- klass.__props.each { |p|
151
- field = "#{p.symbol}"
152
- if p.sql_type
153
- field << " #{p.sql_type}"
154
- else
155
- field << " #{TYPEMAP[p.klass]}"
156
- end
157
- field << " #{p.sql}" if p.sql
158
-
159
- field << " NOT NULL AUTO_INCREMENT" if p.symbol == :oid
160
- fields << field
161
- }
162
-
163
- sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
164
-
165
- # Create table constrains
166
-
167
- if klass.__meta and constrains = klass.__meta[:sql_constrain]
168
- sql << ", #{constrains.join(', ')}"
169
- end
170
-
171
- sql << ");"
172
- safe_query(sql)
173
-
174
- $log.info "Created table #{klass::DBTABLE}! :: #{sql}"
175
-
176
- # Create indices
177
- if klass.__meta
178
- for data in klass.__meta[:sql_index]
179
- sql = ""
180
- idx = data[0]
181
- idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
182
- sql << " CREATE"
183
- sql << " UNIQUE" if data[1]
184
- sql << " INDEX #{klass::DBTABLE}_#{idxname}_idx #{data[3]} ON #{klass::DBTABLE} (#{idx});"
185
- safe_query(sql)
186
- end
187
- end
188
- end
189
-
190
- # Drop the entity table
191
- #
192
- def drop_table(klass)
193
- safe_query("DROP TABLE #{klass::DBTABLE}")
194
- end
195
-
196
- # Calculate the fields map for the given class
197
- #
198
- def calc_fields(rows, klass)
199
- # gmosx SOS, FIXME, INVESTIGATE: no need for second safe hash ????
200
- fields = $db.fields[klass] = {}
201
- for field in rows.fields
202
- fields[field] = rows.fieldnum(field)
203
- end
204
- N::Managed.eval_db_read_row(klass)
205
- end
206
-
207
- # Grab the join fields returned by an sql join query, and attach them
208
- # to the entity.
209
- #
210
- def get_join_fields(rows, tuple, entity, join_fields)
211
- entity.join_fields = {}
212
- for f in join_fields
213
- entity.join_fields[f] = rows.getvalue(tuple, $db.fields[entity.class][f.to_s])
214
- end
215
- end
216
-
217
- # If the connection is in deserialize mode, deserialize one row.
218
- #
219
- def deserialize_one(rows, klass, join_fields = nil)
220
- return nil unless rows
221
-
222
- calc_fields(rows, klass) unless $db.fields[klass]
223
-
224
- if @deserialize
225
- # gmosx: Enities should have no params constructor SOS.
226
- #
227
- entity = klass.new()
228
- entity.__db_read_row(rows, 0)
229
-
230
- get_join_fields(rows, 0, entity, join_fields) if join_fields
231
-
232
- rows.clear()
233
- return entity
234
- end
235
-
236
- return rows[0]
237
- end
238
-
239
- # If the connection is in deserialize mode, deserialize all rows.
240
- #
241
- def deserialize_all(rows, klass, join_fields = nil)
242
- return nil unless rows
243
-
244
- calc_fields(rows, klass) unless $db.fields[klass]
245
-
246
- if @deserialize
247
- entities = []
248
-
249
- for tuple in (0...rows.num_tuples)
250
- entity = klass.new()
251
- entity.__db_read_row(rows, tuple)
252
-
253
- get_join_fields(rows, tuple, entity, join_fields) if join_fields
254
-
255
- entities << entity
256
- end
257
-
258
- rows.clear()
259
- return entities
260
- end
261
-
262
- return rows
263
- end
264
-
265
- #
266
- # Execute an sql query. If the entity table is missing, create
267
- # it and retry.
268
- #
269
- def retry_query(sql, klass = nil)
270
- $log.debug sql if $DBG
271
- retries = 0
272
- begin
273
- rows = @rdb.query(sql)
274
- if rows && (rows.num_tuples > 0)
275
- return rows
276
- else
277
- return nil
278
- end
279
- rescue => ex
280
- if ex.errno == 1146 # table does not exist
281
- $log.info "retry_query: #{ex}"
282
- # table does not exist, create it!
283
- create_table(klass)
284
- # gmosx: only allow ONE retry to avoid loops here!
285
- retries += 1
286
- retry if retries <= 1
287
- else
288
- $log.error "DB Error: #{ex} (#{ex.errno}), [#{sql}]"
289
- $log.error "#{caller[0]} : #{caller[1]} : #{caller[2]}"
290
- return nil
291
- end
292
- end
293
- end
294
-
295
- # Execute an sql query and catch the errors.
296
- #
297
- def safe_query(sql)
298
- $log.debug sql if $DBG
299
- begin
300
- rows = @rdb.query(sql)
301
- if rows #&& (rows.num_tuples > 0)
302
- return rows
303
- else
304
- return nil
305
- end
306
- rescue => ex
307
- $log.error "DB Error (safe_query): #{ex} (#{ex.errno}), [#{sql}]"
308
- $log.error "#{caller[0]} : #{caller[1]} : #{caller[2]}"
309
- return nil
310
- end
311
- end
312
-
313
- # Get the next oid in the sequence for this klass
314
- #
315
- def next_oid(klass)
316
- retries = 0
317
- begin
318
- res = @rdb.insert_id()
319
- res ? oid = res + 1 : oid = 1
320
- return oid
321
- rescue => ex
322
- if ex.errno == 1146 # table does not exist
323
- $log.info "next_oid: #{ex}"
324
- # table does not exist, create it!
325
- create_table(klass)
326
- # gmosx: only allow ONE retry to avoid loops here!
327
- retries += 1
328
- retry if retries <= 1
329
- else
330
- $log.error "DB Error (next_oid): #{ex} (#{ex.errno})"
331
- $log.error "#{caller[0]} : #{caller[1]} : #{caller[2]}"
332
- return nil
333
- end
334
- end
335
- end
336
-
337
- end
338
-
339
- # Mix into the DbConnection class
340
- #
341
- N::DbConnection.module_eval %{
342
- include N::MysqlBackend
343
- }
344
-
345
- end # namespace
data/lib/n/db/psql.rb DELETED
@@ -1,383 +0,0 @@
1
- # code:
2
- # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id$
6
-
7
- require "base64"
8
- require "postgres"
9
- require "time.rb"
10
- require "date.rb"
11
-
12
- module N;
13
-
14
- # = DbUtils
15
- #
16
- # Backend specific utils
17
- #
18
- module DbUtils
19
-
20
- # Escape an sql string
21
- #
22
- def self.escape(str)
23
- return nil unless str
24
- return PGconn.escape(str)
25
- end
26
-
27
- # Escape bytes
28
- #
29
- def self.escape_bytes(bytes)
30
- return nil unless bytes
31
- return PGconn.escape_bytea(bytes)
32
- end
33
-
34
- # Unescape bytes
35
- # FIXME: optimize this! Even better integrate this in the
36
- # libpq library, or find out why the default method doesnt
37
- # work.
38
- #
39
- def self.unescape_bytes(bytes)
40
- return bytes.gsub(/(\\\d+)/) { |m| m.gsub(/\\/, "").oct.chr }
41
- end
42
-
43
- # Convert a ruby time to an sql timestamp.
44
- #
45
- def self.sql_timestamp(time = Time.now)
46
- return nil unless time
47
- return time.strftime("%Y-%m-%d %H:%M:%S")
48
- end
49
-
50
- # Output YYY-mm-dd
51
- #
52
- def self.sql_date(date)
53
- return nil unless date
54
- return "#{date.year}-#{date.month}-#{date.mday}"
55
- end
56
-
57
- # Parse sql datetime
58
- #
59
- # TODO: Optimize this
60
- #
61
- def self.parse_sql_timestamp(str)
62
- return Time.parse(str)
63
- end
64
-
65
- # Input YYYY-mm-dd
66
- #
67
- def self.parse_sql_date(str)
68
- return nil unless str
69
- return Date.strptime(str)
70
- end
71
-
72
- # Return an evaluator for reading the property
73
- # No need to optimize this, used only to precalculate code.
74
- #--
75
- # gmosx: base64 encoding is used because the unencode_bytea
76
- # method of postgres is not implemented
77
- #++
78
- #
79
- def self.read_prop(p, idx)
80
- case p.klass.to_s
81
- when Fixnum.name
82
- return "rows.getvalue(tuple, #{idx}).to_i()"
83
- when Float.name
84
- return "rows.getvalue(tuple, #{idx}).to_f()"
85
- when Time.name
86
- return "N::DbUtils.parse_sql_timestamp(rows.getvalue(tuple, #{idx}))"
87
- when Date.name
88
- return "N::DbUtils.parse_sql_date(rows.getvalue(tuple, #{idx}))"
89
- when TrueClass.name
90
- return "('true' == rows.getvalue(tuple, #{idx}))"
91
- when Object.name
92
- return "Marshal.load(Base64.decode64(rows.getvalue(tuple, #{idx}).gsub(/\\\\012/, '\n')))"
93
- when Array.name
94
- return "Marshal.load(Base64.decode64(rows.getvalue(tuple, #{idx}).gsub(/\\\\012/, '\n')))"
95
- # return "Marshal.load(N::DbUtils.unescape_bytes(rows.getvalue(tuple, #{idx})))"
96
- when Hash.name
97
- return "Marshal.load(Base64.decode64(rows.getvalue(tuple, #{idx}).gsub(/\\\\012/, '\n')))"
98
- else # String
99
- return "rows.getvalue(tuple, #{idx})"
100
- end
101
- end
102
- end
103
-
104
- # = PsqlBackend
105
- #
106
- # Implement the Db backend using the PostgreSQL RDBMS.
107
- #
108
- # Include the Psql backend to the standard DbConnection
109
- # object to synthesize a PsqlConnection at runtime.
110
- #
111
- module PsqlBackend
112
-
113
- # map between Ruby and SQL types
114
- #
115
- TYPEMAP = {
116
- Integer => "integer",
117
- Fixnum => "integer",
118
- Float => "float",
119
- String => "text",
120
- Time => "timestamp",
121
- Date => "date",
122
- TrueClass => "boolean",
123
- Object => "bytea",
124
- Array => "bytea",
125
- Hash => "bytea"
126
- }
127
-
128
- # Initialize a connection to the database
129
- #
130
- def initialize(config)
131
- @rdb = PGconn.connect(nil, nil, nil, nil, config[:database],
132
- config[:user], config[:password])
133
- end
134
-
135
- # Close the connection to the database
136
- #
137
- def close()
138
- @rdb.close
139
- end
140
-
141
- # Create the sequence that generates the unified space id
142
- # oids. You *MUST* call this method on newly created
143
- # databases.
144
- #
145
- def create_schema()
146
- safe_query("CREATE SEQUENCE oids_seq")
147
- end
148
-
149
- # Drop the oid sequence
150
- #
151
- def drop_schema()
152
- safe_query("DROP SEQUENCE oids_seq")
153
- end
154
-
155
- # NOT IMPLEMENTED
156
- #
157
- def prepare_statement()
158
- @rdb.query("PREPARE")
159
- end
160
- alias_method :pstatement, :prepare_statement
161
-
162
- # NOT IMPLEMENTED
163
- #
164
- def execute_statement()
165
- self.select("EXECUTE")
166
- end
167
- alias_method :xstatement, :execute_statement
168
-
169
- # Create a table for an entity.
170
- #
171
- def create_table(klass)
172
- fields = []
173
- klass.__props.each { |p|
174
- field = "#{p.symbol}"
175
- if p.sql
176
- field << " #{p.sql}"
177
- else
178
- field << " #{TYPEMAP[p.klass]}"
179
- end
180
-
181
- fields << field
182
- }
183
-
184
- sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
185
-
186
- # Create table constrains
187
-
188
- if klass.__meta and constrains = klass.__meta[:sql_constrain]
189
- sql << ", #{constrains.join(', ')}"
190
- end
191
-
192
- sql << ") WITHOUT OIDS;"
193
-
194
- # Create indices
195
-
196
- if klass.__meta
197
- for data in klass.__meta[:sql_index]
198
- idx, pre_sql, post_sql = *data
199
- idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
200
- sql << " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx});"
201
- end
202
- end
203
-
204
- safe_query(sql)
205
- $log.info "Created table #{klass::DBTABLE}!"
206
-
207
- # create the sequence for this table. Even if the table
208
- # uses the oids_seq, attempt to create it. This makes
209
- # the system more fault tolerant.
210
- safe_query("CREATE SEQUENCE #{klass::DBSEQ}")
211
- $log.info "Created sequence #{klass::DBSEQ}!"
212
- end
213
-
214
- # Drop the entity table
215
- #
216
- def drop_table(klass)
217
- safe_query("DROP TABLE #{klass::DBTABLE}")
218
- if klass.include?(N::Sequenced)
219
- safe_query("DROP SEQUENCE #{klass::DBSEQ};")
220
- end
221
- end
222
-
223
- # Calculate the fields map for the given class
224
- #
225
- def calc_fields(rows, klass)
226
- # gmosx SOS, FIXME, INVESTIGATE: no need for second safe hash ????
227
- fields = $db.fields[klass] = {}
228
- for field in rows.fields
229
- fields[field] = rows.fieldnum(field)
230
- end
231
- N::Managed.eval_db_read_row(klass)
232
- end
233
-
234
- # Grab the join fields returned by an sql join query, and attach them
235
- # to the entity.
236
- #
237
- def get_join_fields(rows, tuple, entity, join_fields)
238
- entity.join_fields = {}
239
- for f in join_fields
240
- entity.join_fields[f] = rows.getvalue(tuple, $db.fields[entity.class][f.to_s])
241
- end
242
- end
243
-
244
- # If the connection is in deserialize mode, deserialize one row.
245
- #
246
- def deserialize_one(rows, klass, join_fields = nil)
247
- return nil unless rows
248
-
249
- calc_fields(rows, klass) unless $db.fields[klass]
250
-
251
- if @deserialize
252
- # gmosx: Enities should have no params constructor SOS.
253
- #
254
- entity = klass.new()
255
- entity.__db_read_row(rows, 0)
256
-
257
- get_join_fields(rows, 0, entity, join_fields) if join_fields
258
-
259
- rows.clear()
260
- return entity
261
- end
262
-
263
- return rows[0]
264
- end
265
-
266
- # If the connection is in deserialize mode, deserialize all rows.
267
- #
268
- def deserialize_all(rows, klass, join_fields = nil)
269
- return nil unless rows
270
-
271
- calc_fields(rows, klass) unless $db.fields[klass]
272
-
273
- if @deserialize
274
- entities = []
275
-
276
- for tuple in (0...rows.num_tuples)
277
- entity = klass.new()
278
- entity.__db_read_row(rows, tuple)
279
-
280
- get_join_fields(rows, tuple, entity, join_fields) if join_fields
281
-
282
- entities << entity
283
- end
284
-
285
- rows.clear()
286
- return entities
287
- end
288
-
289
- return rows
290
- end
291
-
292
- #
293
- # Execute an sql query. If the entity table is missing, create
294
- # it and retry.
295
- #
296
- # exec() is used instead of query because it is faster and we also
297
- # need fields()
298
- #
299
- # FIXME: is the result cleared?
300
- #
301
- def retry_query(sql, klass = nil)
302
- $log.debug sql if $DBG
303
- retries = 0
304
- begin
305
- rows = @rdb.exec(sql)
306
- if rows && (rows.num_tuples > 0)
307
- return rows
308
- else
309
- return nil
310
- end
311
- rescue => ex
312
- # Any idea how to better test this?
313
- if ex.to_s =~ /relation .* not exist/
314
- $log.info "RETRY_QUERY"
315
- # table does not exist, create it!
316
- create_table(klass)
317
- # gmosx: only allow ONE retry to avoid loops here!
318
- retries += 1
319
- retry if retries <= 1
320
- else
321
- $log.error "RETRY_QUERY: surpressing db error: #{ex}, [#{sql}]"
322
- # $log.debug "#{caller[0]} : #{caller[1]} : #{caller[2]}"
323
- return nil
324
- end
325
- end
326
- end
327
-
328
- # Execute an sql query and catch the errors.
329
- #
330
- # exec() is used instead of query because it is faster and we also
331
- # need fields()
332
- #
333
- def safe_query(sql)
334
- $log.debug sql if $DBG
335
- begin
336
- rows = @rdb.exec(sql)
337
- if rows && (rows.num_tuples > 0)
338
- return rows
339
- else
340
- return nil
341
- end
342
- rescue => ex
343
- $log.error "SAFE_QUERY: surpressing db error #{ex}, [#{sql}]"
344
- # $log.debug "#{caller[0]} : #{caller[1]} : #{caller[2]}"
345
- return nil
346
- end
347
- end
348
-
349
- # Get the next oid in the sequence for this klass
350
- #
351
- def next_oid(klass)
352
- retries = 0
353
- begin
354
- res = @rdb.exec("SELECT nextval('#{klass::DBSEQ}')")
355
- oid = res.getvalue(0, 0).to_i()
356
- res.clear()
357
- return oid
358
- rescue => ex
359
- # Any idea how to better test this?
360
- if ex.to_s =~ /relation .* not exist/
361
- $log.info "next_oid: #{ex}"
362
- # table does not exist, create it!
363
- create_table(klass)
364
- # gmosx: only allow ONE retry to avoid loops here!
365
- retries += 1
366
- retry if retries <= 1
367
- else
368
- $log.error "DB Error: #{ex}, #next_oid"
369
- $log.debug "#{caller[0]} : #{caller[1]} : #{caller[2]}"
370
- return nil
371
- end
372
- end
373
- end
374
-
375
- end
376
-
377
- # Mix into the DbConnection class
378
- #
379
- N::DbConnection.module_eval %{
380
- include N::PsqlBackend
381
- }
382
-
383
- end # namespace