sqlite-ruby 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/doc/faq/faq.html CHANGED
@@ -62,38 +62,40 @@
62
62
  <ul>
63
63
  <li>How do I do a database query?
64
64
  <ul>
65
- <li><a href='#538599180'>I just want an array of the rows&#8230;</a></li>
66
- <li><a href='#538599140'>I&#8217;d like to use a block to iterate through the rows&#8230;</a></li>
67
- <li><a href='#538599100'>I need to get the column names as well as the rows&#8230;</a></li>
68
- <li><a href='#538599060'>I need the result set object itself&#8230;</a></li>
69
- <li><a href='#538599020'>I just want the first row of the result set&#8230;</a></li>
70
- <li><a href='#538598980'>I just want the first value of the first row of the result set&#8230;</a></li>
65
+ <li><a href='#538683626'>I just want an array of the rows&#8230;</a></li>
66
+ <li><a href='#538683586'>I&#8217;d like to use a block to iterate through the rows&#8230;</a></li>
67
+ <li><a href='#538683546'>I need to get the column names as well as the rows&#8230;</a></li>
68
+ <li><a href='#538683506'>I need the result set object itself&#8230;</a></li>
69
+ <li><a href='#538683466'>I just want the first row of the result set&#8230;</a></li>
70
+ <li><a href='#538683426'>I just want the first value of the first row of the result set&#8230;</a></li>
71
71
  </ul>
72
72
  </li>
73
- <li><a href='#538598910'>How do I prepare a statement for repeated execution?</a></li>
74
- <li><a href='#538598870'>How do I use placeholders in an <span class="caps">SQL</span> statement?</a></li>
75
- <li><a href='#538598830'>How do I discover metadata about a query?</a></li>
76
- <li><a href='#538598790'>I&#8217;d like the rows to be indexible by column name.</a></li>
77
- <li><a href='#538598750'>I&#8217;d like the values from a query to be the correct types, instead of String.</a></li>
78
- <li><a href='#538598710'>How do I do a <span class="caps">DDL </span>(insert, update, delete) statement?</a></li>
79
- <li><a href='#538598670'>How do I execute multiple statements in a single string?</a></li>
80
- <li><a href='#538598630'>How do I begin/end a transaction?</a></li>
73
+ <li><a href='#538683356'>How do I prepare a statement for repeated execution?</a></li>
74
+ <li><a href='#538683316'>How do I use placeholders in an <span class="caps">SQL</span> statement?</a></li>
75
+ <li><a href='#538683276'>How do I discover metadata about a query?</a></li>
76
+ <li><a href='#538683236'>I&#8217;d like the rows to be indexible by column name.</a></li>
77
+ <li><a href='#538683196'>I&#8217;d like the values from a query to be the correct types, instead of String.</a></li>
78
+ <li><a href='#538683156'>How do I do a <span class="caps">DDL </span>(insert, update, delete) statement?</a></li>
79
+ <li><a href='#538683116'>How do I execute multiple statements in a single string?</a></li>
80
+ <li><a href='#538683076'>How do I begin/end a transaction?</a></li>
81
81
  </ul>
82
82
  </div>
83
- <a name='538599180'></a>
83
+ <a name='538683626'></a>
84
84
  <div class='faq-title'>How do I do a database query? I just want an array of the rows&#8230;</div>
85
85
  <div class='faq-answer'><p>Use the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a> method. If you don&#8217;t give it a block, it will return an array of all the rows:</p>
86
86
 
87
+
87
88
  <pre>
88
89
  require 'sqlite'
89
90
 
90
91
  db = SQLite::<a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database</a>.new( "test.db" )
91
92
  rows = db.execute( "select * from test" )
92
93
  </pre></div>
93
- <a name='538599140'></a>
94
+ <a name='538683586'></a>
94
95
  <div class='faq-title'>How do I do a database query? I&#8217;d like to use a block to iterate through the rows&#8230;</div>
95
96
  <div class='faq-answer'><p>Use the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a> method. If you give it a block, each row of the result will be yielded to the block:</p>
96
97
 
98
+
97
99
  <pre>
98
100
  require 'sqlite'
99
101
 
@@ -102,10 +104,11 @@
102
104
  ...
103
105
  end
104
106
  </pre></div>
105
- <a name='538599100'></a>
107
+ <a name='538683546'></a>
106
108
  <div class='faq-title'>How do I do a database query? I need to get the column names as well as the rows&#8230;</div>
107
109
  <div class='faq-answer'><p>Use the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute2</a> method. This works just like <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a>; if you don&#8217;t give it a block, it returns an array of rows; otherwise, it will yield each row to the block. <em>However</em>, the first row returned is always an array of the column names from the query:</p>
108
110
 
111
+
109
112
  <pre>
110
113
  require 'sqlite'
111
114
 
@@ -123,7 +126,7 @@
123
126
  end
124
127
  end
125
128
  </pre></div>
126
- <a name='538599060'></a>
129
+ <a name='538683506'></a>
127
130
  <div class='faq-title'>How do I do a database query? I need the result set object itself&#8230;</div>
128
131
  <div class='faq-answer'><p>Sometimes you don&#8217;t want all the rows at once, and yet you&#8217;d like to be able to iterate through the results. For instance, you may want to pass the results to some other function (or series of functions) and have them pull rows from the results on demand. This is more effecient for very large queries.</p>
129
132
 
@@ -131,6 +134,7 @@
131
134
 
132
135
  <p>You can do both internal and external iteration with the result set this way:</p>
133
136
 
137
+
134
138
  <pre>
135
139
  require 'sqlite'
136
140
 
@@ -165,30 +169,30 @@
165
169
  result.next
166
170
  end
167
171
  </pre>
168
-
169
172
  <p>In general, <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#query</a> is not a very good choice for such operations&#8230;</p></div>
170
- <a name='538599020'></a>
173
+ <a name='538683466'></a>
171
174
  <div class='faq-title'>How do I do a database query? I just want the first row of the result set&#8230;</div>
172
175
  <div class='faq-answer'><p>Easy. Just call <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#get_first_row</a>:</p>
173
176
 
177
+
174
178
  <pre>
175
179
  row = db.get_first_row( "select * from table" )
176
180
  </pre>
177
-
178
181
  <p>This also supports bind variables, just like <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a> and friends.</p></div>
179
- <a name='538598980'></a>
182
+ <a name='538683426'></a>
180
183
  <div class='faq-title'>How do I do a database query? I just want the first value of the first row of the result set&#8230;</div>
181
184
  <div class='faq-answer'><p>Also easy. Just call <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#get_first_value</a>:</p>
182
185
 
186
+
183
187
  <pre>
184
188
  count = db.get_first_value( "select count(*) from table" )
185
189
  </pre>
186
-
187
190
  <p>This also supports bind variables, just like <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a> and friends.</p></div>
188
- <a name='538598910'></a>
191
+ <a name='538683356'></a>
189
192
  <div class='faq-title'>How do I prepare a statement for repeated execution?</div>
190
193
  <div class='faq-answer'><p>If the same statement is going to be executed repeatedly, you can speed things up a bit by <em>preparing</em> the statement. You do this via the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#prepare</a> method. It returns a <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement</a> object, and you can then invoke #execute on that to get the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/ResultSet.html'>ResultSet</a>:</p>
191
194
 
195
+
192
196
  <pre>
193
197
  stmt = db.prepare( "select * from person" )
194
198
 
@@ -198,12 +202,10 @@
198
202
  end
199
203
  end
200
204
  </pre>
201
-
202
205
  <p>This is made more useful by the ability to bind variables to placeholders via the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement#bind_param</a> and <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement#bind_params</a> methods. (See the next <span class="caps">FAQ</span> for details.)</p></div>
203
- <a name='538598870'></a>
206
+ <a name='538683316'></a>
204
207
  <div class='faq-title'>How do I use placeholders in an <span class="caps">SQL</span> statement?</div>
205
208
  <div class='faq-answer'><p>Placeholders in an <span class="caps">SQL</span> statement take any of the following formats:</p>
206
-
207
209
  <ul>
208
210
  <li><code>?</code></li>
209
211
  <li><code>?<em>n</em></code></li>
@@ -215,6 +217,7 @@
215
217
 
216
218
  <p>For example, here is a query using these placeholder formats:</p>
217
219
 
220
+
218
221
  <pre>
219
222
  select *
220
223
  from table
@@ -223,31 +226,31 @@
223
226
  and e = :spouse:
224
227
  and f = :1
225
228
  </pre>
226
-
227
229
  <p>This defines 5 different placeholders: 1, 2, 3, &#8220;name&#8221;, and &#8220;spouse&#8221;.</p>
228
230
 
229
231
  <p>You replace these placeholders by <em>binding</em> them to values. This can be accomplished in a variety of ways.</p>
230
232
 
231
233
  <p>The <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a>, <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute2</a>, and <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#query</a> methods all accept additional arguments following the <span class="caps">SQL</span> statement. These arguments are assumed to be bind parameters, and they are bound (positionally) to their corresponding placeholders:</p>
232
234
 
235
+
233
236
  <pre>
234
237
  db.execute( "select * from table where a = ? and b = ?",
235
238
  "hello",
236
239
  "world" )
237
240
  </pre>
238
-
239
241
  <p>The above would replace the first question mark with &#8216;hello&#8217; and the second with &#8216;world&#8217;. If the placeholders have an explicit index given, they will be replaced with the bind parameter at that index (1-based).</p>
240
242
 
241
243
  <p>If a Hash is given as a bind parameter, then its key/value pairs are bound to the placeholders. This is how you bind by name:</p>
242
244
 
245
+
243
246
  <pre>
244
247
  db.execute( "select * from table where a = :name and b = :value",
245
248
  "name" =&gt; "bob",
246
249
  "value" =&gt; "priceless" )
247
250
  </pre>
248
-
249
251
  <p>You can also bind explicitly using the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement</a> object itself. Just do a <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#prepare</a> to get the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement</a>, and then use either <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement#bind_param</a> or <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement#bind_params</a>:</p>
250
252
 
253
+
251
254
  <pre>
252
255
  stmt = db.prepare( "select * from table where a = :name and b = ?" )
253
256
 
@@ -258,20 +261,21 @@
258
261
 
259
262
  stmt.bind_params( "value", "name" =&gt; "bob" )
260
263
  </pre></div>
261
- <a name='538598830'></a>
264
+ <a name='538683276'></a>
262
265
  <div class='faq-title'>How do I discover metadata about a query?</div>
263
266
  <div class='faq-answer'><p>If you ever want to know the names or types of the columns in a result set, you can do it in several ways.</p>
264
267
 
265
268
  <p>The first way is to ask the row object itself. Each row will have a property &#8220;fields&#8221; that returns an array of the column names. The row will also have a property &#8220;types&#8221; that returns an array of the column types:</p>
266
269
 
270
+
267
271
  <pre>
268
272
  rows = db.execute( "select * from table" )
269
273
  p rows[0].fields
270
274
  p rows[0].types
271
275
  </pre>
272
-
273
276
  <p>Obviously, this approach requires you to execute a statement that actually returns data. If you don&#8217;t know if the statement will return any rows, but you still need the metadata, you can use <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#query</a> and ask the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/ResultSet.html'>ResultSet</a> object itself:</p>
274
277
 
278
+
275
279
  <pre>
276
280
  db.query( "select * from table" ) do |result|
277
281
  p result.columns
@@ -279,20 +283,21 @@
279
283
  ...
280
284
  end
281
285
  </pre>
282
-
283
286
  <p>Lastly, you can use <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#prepare</a> and ask the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement</a> object what the metadata are:</p>
284
287
 
288
+
285
289
  <pre>
286
290
  stmt = db.prepare( "select * from table" )
287
291
  p stmt.columns
288
292
  p stmt.types
289
293
  </pre></div>
290
- <a name='538598790'></a>
294
+ <a name='538683236'></a>
291
295
  <div class='faq-title'>I&#8217;d like the rows to be indexible by column name.</div>
292
296
  <div class='faq-answer'><p>By default, each row from a query is returned as an Array of values. This means that you can only obtain values by their index. Sometimes, however, you would like to obtain values by their column name.</p>
293
297
 
294
298
  <p>The first way to do this is to set the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database</a> property &#8220;results_as_hash&#8221; to true. If you do this, then all rows will be returned as Hash objects, with the column names as the keys. (In this case, the &#8220;fields&#8221; property is unavailable on the row, although the &#8220;types&#8221; property remains.)</p>
295
299
 
300
+
296
301
  <pre>
297
302
  db.results_as_hash = true
298
303
  db.execute( "select * from table" ) do |row|
@@ -300,9 +305,9 @@
300
305
  p row['column2']
301
306
  end
302
307
  </pre>
303
-
304
308
  <p>The other way is to use Ara Howard&#8217;s <a href="http://rubyforge.org/projects/arrayfields">ArrayFields</a> module. Just require &#8220;arrayfields&#8221;, and all of your rows will be indexable by column name, even though they are still arrays!</p>
305
309
 
310
+
306
311
  <pre>
307
312
  require 'arrayfields'
308
313
 
@@ -312,21 +317,22 @@
312
317
  p row[1] == row['column2']
313
318
  end
314
319
  </pre></div>
315
- <a name='538598750'></a>
320
+ <a name='538683196'></a>
316
321
  <div class='faq-title'>I&#8217;d like the values from a query to be the correct types, instead of String.</div>
317
322
  <div class='faq-answer'><p>You can turn on &#8220;type translation&#8221; by setting <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#type_translation</a> to true:</p>
318
323
 
324
+
319
325
  <pre>
320
326
  db.type_translation = true
321
327
  db.execute( "select * from table" ) do |row|
322
328
  p row
323
329
  end
324
330
  </pre>
325
-
326
331
  <p>By doing this, each return value for each row will be translated to its correct type, based on its declared column type.</p>
327
332
 
328
333
  <p>You can even declare your own translation routines, if (for example) you are using an <span class="caps">SQL</span> type that is not handled by default:</p>
329
334
 
335
+
330
336
  <pre>
331
337
  # assume "objects" table has the following schema:
332
338
  # create table objects (
@@ -347,19 +353,21 @@
347
353
  obj = db.get_first_value( "select thing from objects where name='bob'" )
348
354
  p obj == h
349
355
  </pre></div>
350
- <a name='538598710'></a>
356
+ <a name='538683156'></a>
351
357
  <div class='faq-title'>How do I do a <span class="caps">DDL </span>(insert, update, delete) statement?</div>
352
358
  <div class='faq-answer'><p>You can actually do inserts, updates, and deletes in exactly the same way as selects, but in general the <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a> method will be most convenient:</p>
353
359
 
360
+
354
361
  <pre>
355
362
  db.execute( "insert into table values ( ?, ? )", *bind_vars )
356
363
  </pre></div>
357
- <a name='538598670'></a>
364
+ <a name='538683116'></a>
358
365
  <div class='faq-title'>How do I execute multiple statements in a single string?</div>
359
366
  <div class='faq-answer'><p>The standard query methods (<a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute</a>, <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute2</a>, <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#query</a>, and <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Statement.html'>Statement#execute</a>) will only execute the first statement in the string that is given to them. Thus, if you have a string with multiple <span class="caps">SQL</span> statements, each separated by a string, you can&#8217;t use those methods to execute them all at once.</p>
360
367
 
361
368
  <p>Instead, use <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute_batch</a>:</p>
362
369
 
370
+
363
371
  <pre>
364
372
  sql = &lt;&lt;SQL
365
373
  create table the_table (
@@ -374,17 +382,16 @@
374
382
 
375
383
  db.execute_batch( sql )
376
384
  </pre>
377
-
378
385
  <p>Unlike the other query methods, <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#execute_batch</a> accepts no block. It will also only ever return <ins>nil</ins>. Thus, it is really only suitable for batch processing of <span class="caps">DDL</span> statements.</p></div>
379
- <a name='538598630'></a>
386
+ <a name='538683076'></a>
380
387
  <div class='faq-title'>How do I begin/end a transaction?</div>
381
388
  <div class='faq-answer'><p>Use <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#transaction</a> to start a transaction. If you give it a block, the block will be automatically committed at the end of the block, unless an exception was raised, in which case the transaction will be rolled back. (Never explicitly call <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#commit</a> or <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#rollback</a> inside of a transaction block&#8212;you&#8217;ll get errors when the block terminates!)</p>
382
389
 
383
- <pre> database.transaction do |db| db.execute( "insert into table values ( 'a', 'b', 'c' )" ) ... end </pre>
384
390
 
391
+ <pre> database.transaction do |db| db.execute( "insert into table values ( 'a', 'b', 'c' )" ) ... end </pre>
385
392
  <p>Alternatively, if you don&#8217;t give a block to <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#transaction</a>, the transaction remains open until you explicitly call <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#commit</a> or <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#rollback</a>.</p>
386
393
 
387
- <pre> db.transaction db.execute( "insert into table values ( 'a', 'b', 'c' )" ) db.commit </pre>
388
394
 
395
+ <pre> db.transaction db.execute( "insert into table values ( 'a', 'b', 'c' )" ) db.commit </pre>
389
396
  <p>Note that SQLite does not allow nested transactions, so you&#8217;ll get errors if you try to open a new transaction while one is already active. Use <a href='http://sqlite-ruby.rubyforge.org/classes/SQLite/Database.html'>Database#transaction_active</a>? to determine whether a transaction is active or not.</p></div>
390
397
  </body></html>
@@ -176,13 +176,23 @@ module SQLite
176
176
 
177
177
  scanner = StringScanner.new( sql )
178
178
  variable_index = 0
179
+ allow_break = true
179
180
 
180
181
  until scanner.eos?
181
182
  tokens << " " unless tokens.empty? if scanner.scan( /\s+/ )
182
183
  break if scanner.eos?
183
184
 
184
185
  if scanner.scan( /;/ )
185
- break
186
+ break if allow_break
187
+ tokens << Token.new( ";" )
188
+ elsif scanner.scan( /\bbegin\s+transaction\b/i )
189
+ tokens << Token.new( "begin transaction" )
190
+ elsif scanner.scan( /\bbegin\b(?=\s*[^\s;]|$)/im )
191
+ tokens << Token.new( "begin" )
192
+ allow_break = false
193
+ elsif !allow_break && scanner.scan( /\bend\b/i )
194
+ tokens << Token.new( "end" )
195
+ allow_break = true
186
196
  elsif scanner.scan( /---.*$/ ) || scanner.scan( %r{/\*.*?\*/}m )
187
197
  # comments
188
198
  next
@@ -36,7 +36,7 @@ module SQLite
36
36
 
37
37
  MAJOR = 2
38
38
  MINOR = 2
39
- TINY = 1
39
+ TINY = 2
40
40
 
41
41
  STRING = [ MAJOR, MINOR, TINY ].join( "." )
42
42
 
@@ -157,4 +157,25 @@ class TC_ParsedStatement < Test::Unit::TestCase
157
157
  assert( ( [ "name", "spouse", 1, 5, 12, 15 ] - stmt.placeholders ).empty? )
158
158
  end
159
159
 
160
+ def test_begin_end
161
+ sql = %Q{begin\n delete blah;\n and blah;\nend; extra}
162
+ stmt = SQLite::ParsedStatement.new( sql )
163
+ assert_equal "begin delete blah; and blah; end", stmt.sql
164
+ assert_equal " extra", stmt.trailing
165
+ end
166
+
167
+ def test_begin
168
+ sql = %Q{begin ; end}
169
+ stmt = SQLite::ParsedStatement.new( sql )
170
+ assert_equal "begin", stmt.sql
171
+ assert_equal " end", stmt.trailing
172
+ end
173
+
174
+ def test_begin_transaction
175
+ sql = %Q{begin transaction; blah}
176
+ stmt = SQLite::ParsedStatement.new( sql )
177
+ assert_equal "begin transaction", stmt.sql
178
+ assert_equal " blah", stmt.trailing
179
+ end
180
+
160
181
  end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
3
3
  specification_version: 1
4
4
  name: sqlite-ruby
5
5
  version: !ruby/object:Gem::Version
6
- version: 2.2.1
7
- date: 2004-11-04
6
+ version: 2.2.2
7
+ date: 2004-11-15
8
8
  summary: SQLite/Ruby is a module to allow Ruby scripts to interface with a SQLite database.
9
9
  require_paths:
10
10
  - lib
@@ -42,7 +42,6 @@ files:
42
42
  - lib/sqlite/version.rb
43
43
  - lib/sqlite/pragmas.rb
44
44
  - test/db
45
- - test/lib
46
45
  - test/tc_parsed_statement.rb
47
46
  - test/tc_api_core.rb
48
47
  - test/tests.rb
@@ -52,16 +51,6 @@ files:
52
51
  - test/tc_type_translation.rb
53
52
  - test/tc_database.rb
54
53
  - test/db/fixtures.sql
55
- - test/lib/sqlite_api.so
56
- - test/lib/sqlite.rb
57
- - test/lib/sqlite
58
- - test/lib/sqlite/statement.rb
59
- - test/lib/sqlite/database.rb
60
- - test/lib/sqlite/parsed_statement.rb
61
- - test/lib/sqlite/translator.rb
62
- - test/lib/sqlite/resultset.rb
63
- - test/lib/sqlite/version.rb
64
- - test/lib/sqlite/pragmas.rb
65
54
  - README
66
55
  test_files:
67
56
  - test/tests.rb
data/test/lib/sqlite.rb DELETED
@@ -1,34 +0,0 @@
1
- #--
2
- # =============================================================================
3
- # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
- # All rights reserved.
5
- #
6
- # Redistribution and use in source and binary forms, with or without
7
- # modification, are permitted provided that the following conditions are met:
8
- #
9
- # * Redistributions of source code must retain the above copyright notice,
10
- # this list of conditions and the following disclaimer.
11
- #
12
- # * Redistributions in binary form must reproduce the above copyright
13
- # notice, this list of conditions and the following disclaimer in the
14
- # documentation and/or other materials provided with the distribution.
15
- #
16
- # * The names of its contributors may not be used to endorse or promote
17
- # products derived from this software without specific prior written
18
- # permission.
19
- #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
- # =============================================================================
31
- #++
32
-
33
- require 'sqlite/database'
34
- require 'sqlite/version'
@@ -1,682 +0,0 @@
1
- #--
2
- # =============================================================================
3
- # Copyright (c) 2004, Jamis Buck (jgb3@email.byu.edu)
4
- # All rights reserved.
5
- #
6
- # Redistribution and use in source and binary forms, with or without
7
- # modification, are permitted provided that the following conditions are met:
8
- #
9
- # * Redistributions of source code must retain the above copyright notice,
10
- # this list of conditions and the following disclaimer.
11
- #
12
- # * Redistributions in binary form must reproduce the above copyright
13
- # notice, this list of conditions and the following disclaimer in the
14
- # documentation and/or other materials provided with the distribution.
15
- #
16
- # * The names of its contributors may not be used to endorse or promote
17
- # products derived from this software without specific prior written
18
- # permission.
19
- #
20
- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
- # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
- # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
- # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
24
- # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
- # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
- # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
- # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
- # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
- # =============================================================================
31
- #++
32
-
33
- require 'base64'
34
- require 'sqlite_api'
35
- require 'sqlite/pragmas'
36
- require 'sqlite/statement'
37
- require 'sqlite/translator'
38
-
39
- module SQLite
40
-
41
- # The Database class encapsulates a single connection to a SQLite database.
42
- # Its usage is very straightforward:
43
- #
44
- # require 'sqlite'
45
- #
46
- # db = SQLite::Database.new( "data.db" )
47
- #
48
- # db.execute( "select * from table" ) do |row|
49
- # p row
50
- # end
51
- #
52
- # db.close
53
- #
54
- # It wraps the lower-level methods provides by the API module, include
55
- # includes the Pragmas module for access to various pragma convenience
56
- # methods.
57
- #
58
- # The Database class provides type translation services as well, by which
59
- # the SQLite data types (which are all represented as strings) may be
60
- # converted into their corresponding types (as defined in the schemas
61
- # for their tables). This translation only occurs when querying data from
62
- # the database--insertions and updates are all still typeless.
63
- #
64
- # Furthermore, the Database class has been designed to work well with the
65
- # ArrayFields module from Ara Howard. If you require the ArrayFields
66
- # module before performing a query, and if you have not enabled results as
67
- # hashes, then the results will all be indexible by field name.
68
- class Database
69
- include SQLite::Pragmas
70
-
71
- # Opens the database contained in the given file. This just calls #new,
72
- # passing 0 as the mode parameter. This returns the new Database
73
- # instance.
74
- def self.open( file_name )
75
- new( file_name, 0 )
76
- end
77
-
78
- # Quotes the given string, making it safe to use in an SQL statement.
79
- # It replaces all instances of the single-quote character with two
80
- # single-quote characters. The modified string is returned.
81
- def self.quote( string )
82
- string.gsub( /'/, "''" )
83
- end
84
-
85
- # Returns a string that represents the serialization of the given object.
86
- # The string may safely be used in an SQL statement.
87
- def self.encode( object )
88
- Base64.encode64( Marshal.dump( object ) ).strip
89
- end
90
-
91
- # Unserializes the object contained in the given string. The string must be
92
- # one that was returned by #encode.
93
- def self.decode( string )
94
- Marshal.load( Base64.decode64( string ) )
95
- end
96
-
97
- # Return +true+ if the string is a valid (ie, parsable) SQL statement, and
98
- # +false+ otherwise.
99
- def self.complete?( string )
100
- SQLite::API.complete( string )
101
- end
102
-
103
- # The low-level opaque database handle that this object wraps.
104
- attr_reader :handle
105
-
106
- # A boolean that indicates whether rows in result sets should be returned
107
- # as hashes or not. By default, rows are returned as arrays.
108
- attr_accessor :results_as_hash
109
-
110
- # Create a new Database object that opens the given file. The mode
111
- # parameter has no meaning yet, and may be omitted. If the file does not
112
- # exist, it will be created if possible.
113
- #
114
- # By default, the new database will return result rows as arrays
115
- # (#results_as_hash) and has type translation disabled (#type_translation=).
116
- def initialize( file_name, mode=0 )
117
- @handle = SQLite::API.open( file_name, mode )
118
- @closed = false
119
- @results_as_hash = false
120
- @type_translation = false
121
- @translator = nil
122
- end
123
-
124
- # Return the type translator employed by this database instance. Each
125
- # database instance has its own type translator; this allows for different
126
- # type handlers to be installed in each instance without affecting other
127
- # instances. Furthermore, the translators are instantiated lazily, so that
128
- # if a database does not use type translation, it will not be burdened by
129
- # the overhead of a useless type translator. (See the Translator class.)
130
- def translator
131
- @translator ||= Translator.new
132
- end
133
-
134
- # Returns +true+ if type translation is enabled for this database, or
135
- # +false+ otherwise.
136
- def type_translation
137
- @type_translation
138
- end
139
-
140
- # Enable or disable type translation for this database.
141
- def type_translation=( mode )
142
- @type_translation = mode
143
- end
144
-
145
- # Closes this database. No checks are done to ensure that a database is not
146
- # closed more than once, and closing a database more than once can be
147
- # catastrophic.
148
- def close
149
- SQLite::API.close( @handle )
150
- @closed = true
151
- end
152
-
153
- # Returns +true+ if this database instance has been closed (see #close).
154
- def closed?
155
- @closed
156
- end
157
-
158
- # Returns a Statement object representing the given SQL. This does not
159
- # execute the statement; it merely prepares the statement for execution.
160
- def prepare( sql )
161
- Statement.new( self, sql )
162
- end
163
-
164
- # Executes the given SQL statement. If additional parameters are given,
165
- # they are treated as bind variables, and are bound to the placeholders in
166
- # the query.
167
- #
168
- # Each placeholder must match one of the following formats:
169
- #
170
- # * <tt>?</tt>
171
- # * <tt>?nnn</tt>
172
- # * <tt>:word</tt>
173
- # * <tt>:word:</tt>
174
- #
175
- # where _nnn_ is an integer value indicating the index of the bind
176
- # variable to be bound at that position, and _word_ is an alphanumeric
177
- # identifier for that placeholder. For "<tt>?</tt>", an index is
178
- # automatically assigned of one greater than the previous index used
179
- # (or 1, if it is the first).
180
- #
181
- # Note that if any of the values passed to this are hashes, then the
182
- # key/value pairs are each bound separately, with the key being used as
183
- # the name of the placeholder to bind the value to.
184
- #
185
- # The block is optional. If given, it will be invoked for each row returned
186
- # by the query. Otherwise, any results are accumulated into an array and
187
- # returned wholesale.
188
- #
189
- # See also #execute2, #execute_batch and #query for additional ways of
190
- # executing statements.
191
- def execute( sql, *bind_vars )
192
- stmt = prepare( sql )
193
- stmt.bind_params( *bind_vars )
194
- result = stmt.execute
195
- begin
196
- if block_given?
197
- result.each { |row| yield row }
198
- else
199
- return result.inject( [] ) { |arr,row| arr << row; arr }
200
- end
201
- ensure
202
- result.close
203
- end
204
- end
205
-
206
- # Executes the given SQL statement, exactly as with #execute. However, the
207
- # first row returned (either via the block, or in the returned array) is
208
- # always the names of the columns. Subsequent rows correspond to the data
209
- # from the result set.
210
- #
211
- # Thus, even if the query itself returns no rows, this method will always
212
- # return at least one row--the names of the columns.
213
- #
214
- # See also #execute, #execute_batch and #query for additional ways of
215
- # executing statements.
216
- def execute2( sql, *bind_vars )
217
- stmt = prepare( sql )
218
- stmt.bind_params( *bind_vars )
219
- result = stmt.execute
220
- begin
221
- if block_given?
222
- yield result.columns
223
- result.each { |row| yield row }
224
- else
225
- return result.inject( [ result.columns ] ) { |arr,row| arr << row; arr }
226
- end
227
- ensure
228
- result.close
229
- end
230
- end
231
-
232
- # Executes all SQL statements in the given string. By contrast, the other
233
- # means of executing queries will only execute the first statement in the
234
- # string, ignoring all subsequent statements. This will execute each one
235
- # in turn. The same bind parameters, if given, will be applied to each
236
- # statement.
237
- #
238
- # This always returns +nil+, making it unsuitable for queries that return
239
- # rows.
240
- def execute_batch( sql, *bind_vars )
241
- loop do
242
- stmt = prepare( sql )
243
- stmt.bind_params *bind_vars
244
- stmt.execute
245
- sql = stmt.remainder
246
- break if sql.length < 1
247
- end
248
- nil
249
- end
250
-
251
- # This does like #execute and #execute2 (binding variables and so forth),
252
- # but instead of yielding each row from the result set, this will yield the
253
- # ResultSet instance itself (q.v.). If no block is given, the ResultSet
254
- # instance will be returned.
255
- def query( sql, *bind_vars, &block ) # :yields: result_set
256
- stmt = prepare( sql )
257
- stmt.bind_params( *bind_vars )
258
- stmt.execute( &block )
259
- end
260
-
261
- # A convenience method for obtaining the first row of a result set, and
262
- # discarding all others. It is otherwise identical to #execute.
263
- #
264
- # See also #get_first_value.
265
- def get_first_row( sql, *bind_vars )
266
- execute( sql, *bind_vars ) { |row| return row }
267
- nil
268
- end
269
-
270
- # A convenience method for obtaining the first value of the first row of a
271
- # result set, and discarding all other values and rows. It is otherwise
272
- # identical to #execute.
273
- #
274
- # See also #get_first_row.
275
- def get_first_value( sql, *bind_vars )
276
- execute( sql, *bind_vars ) { |row| return row[0] }
277
- nil
278
- end
279
-
280
- # Obtains the unique row ID of the last row to be inserted by this Database
281
- # instance.
282
- def last_insert_row_id
283
- SQLite::API.last_insert_row_id( @handle )
284
- end
285
-
286
- # Returns the number of changes made to this database instance by the last
287
- # operation performed. Note that a "delete from table" without a where
288
- # clause will not affect this value.
289
- def changes
290
- SQLite::API.changes( @handle )
291
- end
292
-
293
- # Interrupts the currently executing operation, causing it to abort.
294
- def interrupt
295
- SQLite::API.interrupt( @handle )
296
- end
297
-
298
- # Register a busy handler with this database instance. When a requested
299
- # resource is busy, this handler will be invoked. If the handler returns
300
- # +false+, the operation will be aborted; otherwise, the resource will
301
- # be requested again.
302
- #
303
- # The handler will be invoked with the name of the resource that was
304
- # busy, and the number of times it has been retried.
305
- #
306
- # See also #busy_timeout.
307
- def busy_handler( &block ) # :yields: resource, retries
308
- SQLite::API.busy_handler( @handle, block )
309
- end
310
-
311
- # Indicates that if a request for a resource terminates because that
312
- # resource is busy, SQLite should wait for the indicated number of
313
- # milliseconds before trying again. By default, SQLite does not retry
314
- # busy resources. To restore the default behavior, send 0 as the
315
- # +ms+ parameter.
316
- #
317
- # See also #busy_handler.
318
- def busy_timeout( ms )
319
- SQLite::API.busy_timeout( @handle, ms )
320
- end
321
-
322
- # Creates a new function for use in SQL statements. It will be added as
323
- # +name+, with the given +arity+. (For variable arity functions, use
324
- # -1 for the arity.) If +type+ is non-nil, it should either be an
325
- # integer (indicating that the type of the function is always the
326
- # type of the argument at that index), or one of the symbols
327
- # <tt>:numeric</tt>, <tt>:text</tt>, <tt>:args</tt> (in which case
328
- # the function is, respectively, numeric, textual, or the same type as
329
- # its arguments).
330
- #
331
- # The block should accept at least one parameter--the FunctionProxy
332
- # instance that wraps this function invocation--and any other
333
- # arguments it needs (up to its arity).
334
- #
335
- # The block does not return a value directly. Instead, it will invoke
336
- # the FunctionProxy#set_result method on the +func+ parameter and
337
- # indicate the return value that way.
338
- #
339
- # Example:
340
- #
341
- # db.create_function( "maim", 1, :text ) do |func, value|
342
- # if value.nil?
343
- # func.set_value nil
344
- # else
345
- # func.set_value value.split(//).sort.join
346
- # end
347
- # end
348
- #
349
- # puts db.get_first_value( "select maim(name) from table" )
350
- def create_function( name, arity, type=nil, &block ) # :yields: func, *args
351
- case type
352
- when :numeric
353
- type = SQLite::API::NUMERIC
354
- when :text
355
- type = SQLite::API::TEXT
356
- when :args
357
- type = SQLite::API::ARGS
358
- end
359
-
360
- callback = proc do |func,*args|
361
- begin
362
- block.call( FunctionProxy.new( func ), *args )
363
- rescue Exception => e
364
- SQLite::API.set_result_error( func, "#{e.message} (#{e.class})" )
365
- end
366
- end
367
-
368
- SQLite::API.create_function( @handle, name, arity, callback )
369
- SQLite::API.function_type( @handle, name, type ) if type
370
-
371
- self
372
- end
373
-
374
- # Creates a new aggregate function for use in SQL statements. Aggregate
375
- # functions are functions that apply over every row in the result set,
376
- # instead of over just a single row. (A very common aggregate function
377
- # is the "count" function, for determining the number of rows that match
378
- # a query.)
379
- #
380
- # The new function will be added as +name+, with the given +arity+. (For
381
- # variable arity functions, use -1 for the arity.) If +type+ is non-nil,
382
- # it should be a value as described in #create_function.
383
- #
384
- # The +step+ parameter must be a proc object that accepts as its first
385
- # parameter a FunctionProxy instance (representing the function
386
- # invocation), with any subsequent parameters (up to the function's arity).
387
- # The +step+ callback will be invoked once for each row of the result set.
388
- #
389
- # The +finalize+ parameter must be a +proc+ object that accepts only a
390
- # single parameter, the FunctionProxy instance representing the current
391
- # function invocation. It should invoke FunctionProxy#set_result to
392
- # store the result of the function.
393
- #
394
- # Example:
395
- #
396
- # step = proc do |func, value|
397
- # func[ :total ] ||= 0
398
- # func[ :total ] += ( value ? value.length : 0 )
399
- # end
400
- #
401
- # finalize = proc do |func|
402
- # func.set_result( func[ :total ] || 0 )
403
- # end
404
- #
405
- # db.create_aggregate( "lengths", 1, step, finalize, :numeric )
406
- #
407
- # puts db.get_first_value( "select lengths(name) from table" )
408
- #
409
- # See also #create_aggregate_handler for a more object-oriented approach to
410
- # aggregate functions.
411
- def create_aggregate( name, arity, step, finalize, type=nil )
412
- case type
413
- when :numeric
414
- type = SQLite::API::NUMERIC
415
- when :text
416
- type = SQLite::API::TEXT
417
- when :args
418
- type = SQLite::API::ARGS
419
- end
420
-
421
- step_callback = proc do |func,*args|
422
- ctx = SQLite::API.aggregate_context( func )
423
- unless ctx[:__error]
424
- begin
425
- step.call( FunctionProxy.new( func, ctx ), *args )
426
- rescue Exception => e
427
- ctx[:__error] = e
428
- end
429
- end
430
- end
431
-
432
- finalize_callback = proc do |func|
433
- ctx = SQLite::API.aggregate_context( func )
434
- unless ctx[:__error]
435
- begin
436
- finalize.call( FunctionProxy.new( func, ctx ) )
437
- rescue Exception => e
438
- SQLite::API.set_result_error( func, "#{e.message} (#{e.class})" )
439
- end
440
- else
441
- e = ctx[:__error]
442
- SQLite::API.set_result_error( func, "#{e.message} (#{e.class})" )
443
- end
444
- end
445
-
446
- SQLite::API.create_aggregate( @handle, name, arity,
447
- step_callback, finalize_callback )
448
-
449
- SQLite::API.function_type( @handle, name, type ) if type
450
-
451
- self
452
- end
453
-
454
- # This is another approach to creating an aggregate function (see
455
- # #create_aggregate). Instead of explicitly specifying the name,
456
- # callbacks, arity, and type, you specify a factory object
457
- # (the "handler") that knows how to obtain all of that information. The
458
- # handler should respond to the following messages:
459
- #
460
- # +function_type+:: corresponds to the +type+ parameter of
461
- # #create_aggregate. This is an optional message, and if
462
- # the handler does not respond to it, the function type
463
- # will not be set for this function.
464
- # +arity+:: corresponds to the +arity+ parameter of #create_aggregate. This
465
- # message is optional, and if the handler does not respond to it,
466
- # the function will have an arity of -1.
467
- # +name+:: this is the name of the function. The handler _must_ implement
468
- # this message.
469
- # +new+:: this must be implemented by the handler. It should return a new
470
- # instance of the object that will handle a specific invocation of
471
- # the function.
472
- #
473
- # The handler instance (the object returned by the +new+ message, described
474
- # above), must respond to the following messages:
475
- #
476
- # +step+:: this is the method that will be called for each step of the
477
- # aggregate function's evaluation. It should implement the same
478
- # signature as the +step+ callback for #create_aggregate.
479
- # +finalize+:: this is the method that will be called to finalize the
480
- # aggregate function's evaluation. It should implement the
481
- # same signature as the +finalize+ callback for
482
- # #create_aggregate.
483
- #
484
- # Example:
485
- #
486
- # class LengthsAggregateHandler
487
- # def self.function_type; :numeric; end
488
- # def self.arity; 1; end
489
- #
490
- # def initialize
491
- # @total = 0
492
- # end
493
- #
494
- # def step( ctx, name )
495
- # @total += ( name ? name.length : 0 )
496
- # end
497
- #
498
- # def finalize( ctx )
499
- # ctx.set_result( @total )
500
- # end
501
- # end
502
- #
503
- # db.create_aggregate_handler( LengthsAggregateHandler )
504
- # puts db.get_first_value( "select lengths(name) from A" )
505
- def create_aggregate_handler( handler )
506
- type = nil
507
- arity = -1
508
-
509
- type = handler.function_type if handler.respond_to?(:function_type)
510
- arity = handler.arity if handler.respond_to?(:arity)
511
- name = handler.name
512
-
513
- case type
514
- when :numeric
515
- type = SQLite::API::NUMERIC
516
- when :text
517
- type = SQLite::API::TEXT
518
- when :args
519
- type = SQLite::API::ARGS
520
- end
521
-
522
- step = proc do |func,*args|
523
- ctx = SQLite::API.aggregate_context( func )
524
- unless ctx[ :__error ]
525
- ctx[ :handler ] ||= handler.new
526
- begin
527
- ctx[ :handler ].step( FunctionProxy.new( func, ctx ), *args )
528
- rescue Exception => e
529
- ctx[ :__error ] = e
530
- end
531
- end
532
- end
533
-
534
- finalize = proc do |func|
535
- ctx = SQLite::API.aggregate_context( func )
536
- unless ctx[ :__error ]
537
- ctx[ :handler ] ||= handler.new
538
- begin
539
- ctx[ :handler ].finalize( FunctionProxy.new( func, ctx ) )
540
- rescue Exception => e
541
- ctx[ :__error ] = e
542
- end
543
- end
544
-
545
- if ctx[ :__error ]
546
- e = ctx[ :__error ]
547
- SQLite::API.set_result_error( func, "#{e.message} (#{e.class})" )
548
- end
549
- end
550
-
551
- SQLite::API.create_aggregate( @handle, name, arity, step, finalize )
552
- SQLite::API.function_type( @handle, name, type ) if type
553
-
554
- self
555
- end
556
-
557
- # Begins a new transaction. Note that nested transactions are not allowed
558
- # by SQLite, so attempting to nest a transaction will result in a runtime
559
- # exception.
560
- #
561
- # If a block is given, the database instance is yielded to it, and the
562
- # transaction is committed when the block terminates. If the block
563
- # raises an exception, a rollback will be performed instead. Note that if
564
- # a block is given, #commit and #rollback should never be called
565
- # explicitly or you'll get an error when the block terminates.
566
- #
567
- # If a block is not given, it is the caller's responsibility to end the
568
- # transaction explicitly, either by calling #commit, or by calling
569
- # #rollback.
570
- def transaction
571
- execute "begin transaction"
572
- @transaction_active = true
573
-
574
- if block_given?
575
- abort = false
576
- begin
577
- yield self
578
- rescue Exception
579
- abort = true
580
- raise
581
- ensure
582
- abort and rollback or commit
583
- end
584
- end
585
-
586
- true
587
- end
588
-
589
- # Commits the current transaction. If there is no current transaction,
590
- # this will cause an error to be raised. This returns +true+, in order
591
- # to allow it to be used in idioms like
592
- # <tt>abort? and rollback or commit</tt>.
593
- def commit
594
- execute "commit transaction"
595
- @transaction_active = false
596
- true
597
- end
598
-
599
- # Rolls the current transaction back. If there is no current transaction,
600
- # this will cause an error to be raised. This returns +true+, in order
601
- # to allow it to be used in idioms like
602
- # <tt>abort? and rollback or commit</tt>.
603
- def rollback
604
- execute "rollback transaction"
605
- @transaction_active = false
606
- true
607
- end
608
-
609
- # Returns +true+ if there is a transaction active, and +false+ otherwise.
610
- def transaction_active?
611
- @transaction_active
612
- end
613
-
614
- # A helper class for dealing with custom functions (see #create_function,
615
- # #create_aggregate, and #create_aggregate_handler). It encapsulates the
616
- # opaque function object that represents the current invocation. It also
617
- # provides more convenient access to the API functions that operate on
618
- # the function object.
619
- #
620
- # This class will almost _always_ be instantiated indirectly, by working
621
- # with the create methods mentioned above.
622
- class FunctionProxy
623
-
624
- # Create a new FunctionProxy that encapsulates the given +func+ object.
625
- # If context is non-nil, the functions context will be set to that. If
626
- # it is non-nil, it must quack like a Hash. If it is nil, then none of
627
- # the context functions will be available.
628
- def initialize( func, context=nil )
629
- @func = func
630
- @context = context
631
- end
632
-
633
- # Set the result of the function to the given value. The function will
634
- # then return this value.
635
- def set_result( result )
636
- SQLite::API.set_result( @func, result )
637
- end
638
-
639
- # Set the result of the function to the given error message, which must
640
- # be a string. The function will then return that error.
641
- def set_error( error )
642
- SQLite::API.set_result_error( @func, error )
643
- end
644
-
645
- # (Only available to aggregate functions.) Returns the number of rows
646
- # that the aggregate has processed so far. This will include the current
647
- # row, and so will always return at least 1.
648
- def count
649
- ensure_aggregate!
650
- SQLite::API.aggregate_count( @func )
651
- end
652
-
653
- # Returns the value with the given key from the context. This is only
654
- # available to aggregate functions.
655
- def []( key )
656
- ensure_aggregate!
657
- @context[ key ]
658
- end
659
-
660
- # Sets the value with the given key in the context. This is only
661
- # available to aggregate functions.
662
- def []=( key, value )
663
- ensure_aggregate!
664
- @context[ key ] = value
665
- end
666
-
667
- # A function for performing a sanity check, to ensure that the function
668
- # being invoked is an aggregate function. This is implied by the
669
- # existence of the context variable.
670
- def ensure_aggregate!
671
- unless @context
672
- raise Exceptions::MisuseException, "function is not an aggregate"
673
- end
674
- end
675
- private :ensure_aggregate!
676
-
677
- end
678
-
679
- end
680
-
681
- end
682
-