sqlite3-ffi 0.1.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.
@@ -0,0 +1,599 @@
1
+ require "sqlite3/errors"
2
+
3
+ module SQLite3
4
+ # This module is intended for inclusion solely by the Database class. It
5
+ # defines convenience methods for the various pragmas supported by SQLite3.
6
+ #
7
+ # For a detailed description of these pragmas, see the SQLite3 documentation
8
+ # at http://sqlite.org/pragma.html.
9
+ module Pragmas
10
+ # Returns +true+ or +false+ depending on the value of the named pragma.
11
+ def get_boolean_pragma(name)
12
+ get_first_value("PRAGMA #{name}") != 0
13
+ end
14
+
15
+ # Sets the given pragma to the given boolean value. The value itself
16
+ # may be +true+ or +false+, or any other commonly used string or
17
+ # integer that represents truth.
18
+ def set_boolean_pragma(name, mode)
19
+ case mode
20
+ when String
21
+ case mode.downcase
22
+ when "on", "yes", "true", "y", "t" then mode = "'ON'"
23
+ when "off", "no", "false", "n", "f" then mode = "'OFF'"
24
+ else
25
+ raise SQLite3::Exception, "unrecognized pragma parameter #{mode.inspect}"
26
+ end
27
+ when true, 1
28
+ mode = "ON"
29
+ when false, 0, nil
30
+ mode = "OFF"
31
+ else
32
+ raise SQLite3::Exception, "unrecognized pragma parameter #{mode.inspect}"
33
+ end
34
+
35
+ execute("PRAGMA #{name}=#{mode}")
36
+ end
37
+
38
+ # Requests the given pragma (and parameters), and if the block is given,
39
+ # each row of the result set will be yielded to it. Otherwise, the results
40
+ # are returned as an array.
41
+ def get_query_pragma(name, *params, &block) # :yields: row
42
+ if params.empty?
43
+ execute("PRAGMA #{name}", &block)
44
+ else
45
+ args = "'" + params.join("','") + "'"
46
+ execute("PRAGMA #{name}( #{args} )", &block)
47
+ end
48
+ end
49
+
50
+ # Return the value of the given pragma.
51
+ def get_enum_pragma(name)
52
+ get_first_value("PRAGMA #{name}")
53
+ end
54
+
55
+ # Set the value of the given pragma to +mode+. The +mode+ parameter must
56
+ # conform to one of the values in the given +enum+ array. Each entry in
57
+ # the array is another array comprised of elements in the enumeration that
58
+ # have duplicate values. See #synchronous, #default_synchronous,
59
+ # #temp_store, and #default_temp_store for usage examples.
60
+ def set_enum_pragma(name, mode, enums)
61
+ match = enums.find { |p| p.find { |i| i.to_s.downcase == mode.to_s.downcase } }
62
+ unless match
63
+ raise SQLite3::Exception, "unrecognized #{name} #{mode.inspect}"
64
+ end
65
+ execute("PRAGMA #{name}='#{match.first.upcase}'")
66
+ end
67
+
68
+ # Returns the value of the given pragma as an integer.
69
+ def get_int_pragma(name)
70
+ get_first_value("PRAGMA #{name}").to_i
71
+ end
72
+
73
+ # Set the value of the given pragma to the integer value of the +value+
74
+ # parameter.
75
+ def set_int_pragma(name, value)
76
+ execute("PRAGMA #{name}=#{value.to_i}")
77
+ end
78
+
79
+ # The enumeration of valid synchronous modes.
80
+ SYNCHRONOUS_MODES = [["full", 2], ["normal", 1], ["off", 0]]
81
+
82
+ # The enumeration of valid temp store modes.
83
+ TEMP_STORE_MODES = [["default", 0], ["file", 1], ["memory", 2]]
84
+
85
+ # The enumeration of valid auto vacuum modes.
86
+ AUTO_VACUUM_MODES = [["none", 0], ["full", 1], ["incremental", 2]]
87
+
88
+ # The list of valid journaling modes.
89
+ JOURNAL_MODES = [["delete"], ["truncate"], ["persist"], ["memory"],
90
+ ["wal"], ["off"]]
91
+
92
+ # The list of valid locking modes.
93
+ LOCKING_MODES = [["normal"], ["exclusive"]]
94
+
95
+ # The list of valid encodings.
96
+ ENCODINGS = [["utf-8"], ["utf-16"], ["utf-16le"], ["utf-16be"]]
97
+
98
+ # The list of valid WAL checkpoints.
99
+ WAL_CHECKPOINTS = [["passive"], ["full"], ["restart"], ["truncate"]]
100
+
101
+ def application_id
102
+ get_int_pragma "application_id"
103
+ end
104
+
105
+ def application_id=(integer)
106
+ set_int_pragma "application_id", integer
107
+ end
108
+
109
+ def auto_vacuum
110
+ get_enum_pragma "auto_vacuum"
111
+ end
112
+
113
+ def auto_vacuum=(mode)
114
+ set_enum_pragma "auto_vacuum", mode, AUTO_VACUUM_MODES
115
+ end
116
+
117
+ def automatic_index
118
+ get_boolean_pragma "automatic_index"
119
+ end
120
+
121
+ def automatic_index=(mode)
122
+ set_boolean_pragma "automatic_index", mode
123
+ end
124
+
125
+ def busy_timeout
126
+ get_int_pragma "busy_timeout"
127
+ end
128
+
129
+ def busy_timeout=(milliseconds)
130
+ set_int_pragma "busy_timeout", milliseconds
131
+ end
132
+
133
+ def cache_size
134
+ get_int_pragma "cache_size"
135
+ end
136
+
137
+ def cache_size=(size)
138
+ set_int_pragma "cache_size", size
139
+ end
140
+
141
+ def cache_spill
142
+ get_boolean_pragma "cache_spill"
143
+ end
144
+
145
+ def cache_spill=(mode)
146
+ set_boolean_pragma "cache_spill", mode
147
+ end
148
+
149
+ def case_sensitive_like=(mode)
150
+ set_boolean_pragma "case_sensitive_like", mode
151
+ end
152
+
153
+ def cell_size_check
154
+ get_boolean_pragma "cell_size_check"
155
+ end
156
+
157
+ def cell_size_check=(mode)
158
+ set_boolean_pragma "cell_size_check", mode
159
+ end
160
+
161
+ def checkpoint_fullfsync
162
+ get_boolean_pragma "checkpoint_fullfsync"
163
+ end
164
+
165
+ def checkpoint_fullfsync=(mode)
166
+ set_boolean_pragma "checkpoint_fullfsync", mode
167
+ end
168
+
169
+ def collation_list(&block) # :yields: row
170
+ get_query_pragma "collation_list", &block
171
+ end
172
+
173
+ def compile_options(&block) # :yields: row
174
+ get_query_pragma "compile_options", &block
175
+ end
176
+
177
+ def count_changes
178
+ get_boolean_pragma "count_changes"
179
+ end
180
+
181
+ def count_changes=(mode)
182
+ set_boolean_pragma "count_changes", mode
183
+ end
184
+
185
+ def data_version
186
+ get_int_pragma "data_version"
187
+ end
188
+
189
+ def database_list(&block) # :yields: row
190
+ get_query_pragma "database_list", &block
191
+ end
192
+
193
+ def default_cache_size
194
+ get_int_pragma "default_cache_size"
195
+ end
196
+
197
+ def default_cache_size=(size)
198
+ set_int_pragma "default_cache_size", size
199
+ end
200
+
201
+ def default_synchronous
202
+ get_enum_pragma "default_synchronous"
203
+ end
204
+
205
+ def default_synchronous=(mode)
206
+ set_enum_pragma "default_synchronous", mode, SYNCHRONOUS_MODES
207
+ end
208
+
209
+ def default_temp_store
210
+ get_enum_pragma "default_temp_store"
211
+ end
212
+
213
+ def default_temp_store=(mode)
214
+ set_enum_pragma "default_temp_store", mode, TEMP_STORE_MODES
215
+ end
216
+
217
+ def defer_foreign_keys
218
+ get_boolean_pragma "defer_foreign_keys"
219
+ end
220
+
221
+ def defer_foreign_keys=(mode)
222
+ set_boolean_pragma "defer_foreign_keys", mode
223
+ end
224
+
225
+ def encoding
226
+ get_enum_pragma "encoding"
227
+ end
228
+
229
+ def encoding=(mode)
230
+ set_enum_pragma "encoding", mode, ENCODINGS
231
+ end
232
+
233
+ def foreign_key_check(*table, &block) # :yields: row
234
+ get_query_pragma "foreign_key_check", *table, &block
235
+ end
236
+
237
+ def foreign_key_list(table, &block) # :yields: row
238
+ get_query_pragma "foreign_key_list", table, &block
239
+ end
240
+
241
+ def foreign_keys
242
+ get_boolean_pragma "foreign_keys"
243
+ end
244
+
245
+ def foreign_keys=(mode)
246
+ set_boolean_pragma "foreign_keys", mode
247
+ end
248
+
249
+ def freelist_count
250
+ get_int_pragma "freelist_count"
251
+ end
252
+
253
+ def full_column_names
254
+ get_boolean_pragma "full_column_names"
255
+ end
256
+
257
+ def full_column_names=(mode)
258
+ set_boolean_pragma "full_column_names", mode
259
+ end
260
+
261
+ def fullfsync
262
+ get_boolean_pragma "fullfsync"
263
+ end
264
+
265
+ def fullfsync=(mode)
266
+ set_boolean_pragma "fullfsync", mode
267
+ end
268
+
269
+ def ignore_check_constraints=(mode)
270
+ set_boolean_pragma "ignore_check_constraints", mode
271
+ end
272
+
273
+ def incremental_vacuum(pages, &block) # :yields: row
274
+ get_query_pragma "incremental_vacuum", pages, &block
275
+ end
276
+
277
+ def index_info(index, &block) # :yields: row
278
+ get_query_pragma "index_info", index, &block
279
+ end
280
+
281
+ def index_list(table, &block) # :yields: row
282
+ get_query_pragma "index_list", table, &block
283
+ end
284
+
285
+ def index_xinfo(index, &block) # :yields: row
286
+ get_query_pragma "index_xinfo", index, &block
287
+ end
288
+
289
+ def integrity_check(*num_errors, &block) # :yields: row
290
+ get_query_pragma "integrity_check", *num_errors, &block
291
+ end
292
+
293
+ def journal_mode
294
+ get_enum_pragma "journal_mode"
295
+ end
296
+
297
+ def journal_mode=(mode)
298
+ set_enum_pragma "journal_mode", mode, JOURNAL_MODES
299
+ end
300
+
301
+ def journal_size_limit
302
+ get_int_pragma "journal_size_limit"
303
+ end
304
+
305
+ def journal_size_limit=(size)
306
+ set_int_pragma "journal_size_limit", size
307
+ end
308
+
309
+ def legacy_file_format
310
+ get_boolean_pragma "legacy_file_format"
311
+ end
312
+
313
+ def legacy_file_format=(mode)
314
+ set_boolean_pragma "legacy_file_format", mode
315
+ end
316
+
317
+ def locking_mode
318
+ get_enum_pragma "locking_mode"
319
+ end
320
+
321
+ def locking_mode=(mode)
322
+ set_enum_pragma "locking_mode", mode, LOCKING_MODES
323
+ end
324
+
325
+ def max_page_count
326
+ get_int_pragma "max_page_count"
327
+ end
328
+
329
+ def max_page_count=(size)
330
+ set_int_pragma "max_page_count", size
331
+ end
332
+
333
+ def mmap_size
334
+ get_int_pragma "mmap_size"
335
+ end
336
+
337
+ def mmap_size=(size)
338
+ set_int_pragma "mmap_size", size
339
+ end
340
+
341
+ # Attempt to optimize the database.
342
+ #
343
+ # To customize the optimization options, pass +bitmask+ with a combination
344
+ # of the Constants::Optimize masks.
345
+ #
346
+ # See https://www.sqlite.org/pragma.html#pragma_optimize for more information.
347
+ def optimize(bitmask = nil)
348
+ if bitmask
349
+ set_int_pragma "optimize", bitmask
350
+ else
351
+ execute("PRAGMA optimize")
352
+ end
353
+ end
354
+
355
+ def page_count
356
+ get_int_pragma "page_count"
357
+ end
358
+
359
+ def page_size
360
+ get_int_pragma "page_size"
361
+ end
362
+
363
+ def page_size=(size)
364
+ set_int_pragma "page_size", size
365
+ end
366
+
367
+ def parser_trace=(mode)
368
+ set_boolean_pragma "parser_trace", mode
369
+ end
370
+
371
+ def query_only
372
+ get_boolean_pragma "query_only"
373
+ end
374
+
375
+ def query_only=(mode)
376
+ set_boolean_pragma "query_only", mode
377
+ end
378
+
379
+ def quick_check(*num_errors, &block) # :yields: row
380
+ get_query_pragma "quick_check", *num_errors, &block
381
+ end
382
+
383
+ def read_uncommitted
384
+ get_boolean_pragma "read_uncommitted"
385
+ end
386
+
387
+ def read_uncommitted=(mode)
388
+ set_boolean_pragma "read_uncommitted", mode
389
+ end
390
+
391
+ def recursive_triggers
392
+ get_boolean_pragma "recursive_triggers"
393
+ end
394
+
395
+ def recursive_triggers=(mode)
396
+ set_boolean_pragma "recursive_triggers", mode
397
+ end
398
+
399
+ def reverse_unordered_selects
400
+ get_boolean_pragma "reverse_unordered_selects"
401
+ end
402
+
403
+ def reverse_unordered_selects=(mode)
404
+ set_boolean_pragma "reverse_unordered_selects", mode
405
+ end
406
+
407
+ def schema_cookie
408
+ get_int_pragma "schema_cookie"
409
+ end
410
+
411
+ def schema_cookie=(cookie)
412
+ set_int_pragma "schema_cookie", cookie
413
+ end
414
+
415
+ def schema_version
416
+ get_int_pragma "schema_version"
417
+ end
418
+
419
+ def schema_version=(version)
420
+ set_int_pragma "schema_version", version
421
+ end
422
+
423
+ def secure_delete
424
+ get_boolean_pragma "secure_delete"
425
+ end
426
+
427
+ def secure_delete=(mode)
428
+ set_boolean_pragma "secure_delete", mode
429
+ end
430
+
431
+ def short_column_names
432
+ get_boolean_pragma "short_column_names"
433
+ end
434
+
435
+ def short_column_names=(mode)
436
+ set_boolean_pragma "short_column_names", mode
437
+ end
438
+
439
+ def shrink_memory
440
+ execute("PRAGMA shrink_memory")
441
+ end
442
+
443
+ def soft_heap_limit
444
+ get_int_pragma "soft_heap_limit"
445
+ end
446
+
447
+ def soft_heap_limit=(mode)
448
+ set_int_pragma "soft_heap_limit", mode
449
+ end
450
+
451
+ def stats(&block) # :yields: row
452
+ get_query_pragma "stats", &block
453
+ end
454
+
455
+ def synchronous
456
+ get_enum_pragma "synchronous"
457
+ end
458
+
459
+ def synchronous=(mode)
460
+ set_enum_pragma "synchronous", mode, SYNCHRONOUS_MODES
461
+ end
462
+
463
+ def temp_store
464
+ get_enum_pragma "temp_store"
465
+ end
466
+
467
+ def temp_store=(mode)
468
+ set_enum_pragma "temp_store", mode, TEMP_STORE_MODES
469
+ end
470
+
471
+ def threads
472
+ get_int_pragma "threads"
473
+ end
474
+
475
+ def threads=(count)
476
+ set_int_pragma "threads", count
477
+ end
478
+
479
+ def user_cookie
480
+ get_int_pragma "user_cookie"
481
+ end
482
+
483
+ def user_cookie=(cookie)
484
+ set_int_pragma "user_cookie", cookie
485
+ end
486
+
487
+ def user_version
488
+ get_int_pragma "user_version"
489
+ end
490
+
491
+ def user_version=(version)
492
+ set_int_pragma "user_version", version
493
+ end
494
+
495
+ def vdbe_addoptrace=(mode)
496
+ set_boolean_pragma "vdbe_addoptrace", mode
497
+ end
498
+
499
+ def vdbe_debug=(mode)
500
+ set_boolean_pragma "vdbe_debug", mode
501
+ end
502
+
503
+ def vdbe_listing=(mode)
504
+ set_boolean_pragma "vdbe_listing", mode
505
+ end
506
+
507
+ def vdbe_trace
508
+ get_boolean_pragma "vdbe_trace"
509
+ end
510
+
511
+ def vdbe_trace=(mode)
512
+ set_boolean_pragma "vdbe_trace", mode
513
+ end
514
+
515
+ def wal_autocheckpoint
516
+ get_int_pragma "wal_autocheckpoint"
517
+ end
518
+
519
+ def wal_autocheckpoint=(mode)
520
+ set_int_pragma "wal_autocheckpoint", mode
521
+ end
522
+
523
+ def wal_checkpoint
524
+ get_enum_pragma "wal_checkpoint"
525
+ end
526
+
527
+ def wal_checkpoint=(mode)
528
+ set_enum_pragma "wal_checkpoint", mode, WAL_CHECKPOINTS
529
+ end
530
+
531
+ def writable_schema=(mode)
532
+ set_boolean_pragma "writable_schema", mode
533
+ end
534
+
535
+ ###
536
+ # Returns information about +table+. Yields each row of table information
537
+ # if a block is provided.
538
+ def table_info table
539
+ stmt = prepare "PRAGMA table_info(#{table})"
540
+ columns = stmt.columns
541
+
542
+ needs_tweak_default =
543
+ version_compare(SQLite3.libversion.to_s, "3.3.7") > 0
544
+
545
+ result = [] unless block_given?
546
+ stmt.each do |row|
547
+ new_row = columns.zip(row).to_h
548
+
549
+ tweak_default(new_row) if needs_tweak_default
550
+
551
+ # Ensure the type value is downcased. On Mac and Windows
552
+ # platforms this value is now being returned as all upper
553
+ # case.
554
+ if new_row["type"]
555
+ new_row["type"] = new_row["type"].downcase
556
+ end
557
+
558
+ if block_given?
559
+ yield new_row
560
+ else
561
+ result << new_row
562
+ end
563
+ end
564
+ stmt.close
565
+
566
+ result
567
+ end
568
+
569
+ private
570
+
571
+ # Compares two version strings
572
+ def version_compare(v1, v2)
573
+ v1 = v1.split(".").map { |i| i.to_i }
574
+ v2 = v2.split(".").map { |i| i.to_i }
575
+ parts = [v1.length, v2.length].max
576
+ v1.push 0 while v1.length < parts
577
+ v2.push 0 while v2.length < parts
578
+ v1.zip(v2).each do |a, b|
579
+ return -1 if a < b
580
+ return 1 if a > b
581
+ end
582
+ 0
583
+ end
584
+
585
+ # Since SQLite 3.3.8, the table_info pragma has returned the default
586
+ # value of the row as a quoted SQL value. This method essentially
587
+ # unquotes those values.
588
+ def tweak_default(hash)
589
+ case hash["dflt_value"]
590
+ when /^null$/i
591
+ hash["dflt_value"] = nil
592
+ when /^'(.*)'$/m
593
+ hash["dflt_value"] = $1.gsub("''", "'")
594
+ when /^"(.*)"$/m
595
+ hash["dflt_value"] = $1.gsub('""', '"')
596
+ end
597
+ end
598
+ end
599
+ end
@@ -0,0 +1,96 @@
1
+ require "sqlite3/constants"
2
+ require "sqlite3/errors"
3
+
4
+ module SQLite3
5
+ # The ResultSet object encapsulates the enumerability of a query's output.
6
+ # It is a simple cursor over the data that the query returns. It will
7
+ # very rarely (if ever) be instantiated directly. Instead, clients should
8
+ # obtain a ResultSet instance via Statement#execute.
9
+ class ResultSet
10
+ include Enumerable
11
+
12
+ # Create a new ResultSet attached to the given database, using the
13
+ # given sql text.
14
+ def initialize db, stmt
15
+ @db = db
16
+ @stmt = stmt
17
+ end
18
+
19
+ # Reset the cursor, so that a result set which has reached end-of-file
20
+ # can be rewound and reiterated.
21
+ def reset(*bind_params)
22
+ @stmt.reset!
23
+ @stmt.bind_params(*bind_params)
24
+ end
25
+
26
+ # Query whether the cursor has reached the end of the result set or not.
27
+ def eof?
28
+ @stmt.done?
29
+ end
30
+
31
+ # Obtain the next row from the cursor. If there are no more rows to be
32
+ # had, this will return +nil+.
33
+ #
34
+ # The returned value will be an array, unless Database#results_as_hash has
35
+ # been set to +true+, in which case the returned value will be a hash.
36
+ #
37
+ # For arrays, the column names are accessible via the +fields+ property,
38
+ # and the column types are accessible via the +types+ property.
39
+ #
40
+ # For hashes, the column names are the keys of the hash, and the column
41
+ # types are accessible via the +types+ property.
42
+ def next
43
+ @stmt.step
44
+ end
45
+
46
+ # Required by the Enumerable mixin. Provides an internal iterator over the
47
+ # rows of the result set.
48
+ def each
49
+ while (node = self.next)
50
+ yield node
51
+ end
52
+ end
53
+
54
+ # Provides an internal iterator over the rows of the result set where
55
+ # each row is yielded as a hash.
56
+ def each_hash
57
+ while (node = next_hash)
58
+ yield node
59
+ end
60
+ end
61
+
62
+ # Closes the statement that spawned this result set.
63
+ # <em>Use with caution!</em> Closing a result set will automatically
64
+ # close any other result sets that were spawned from the same statement.
65
+ def close
66
+ @stmt.close
67
+ end
68
+
69
+ # Queries whether the underlying statement has been closed or not.
70
+ def closed?
71
+ @stmt.closed?
72
+ end
73
+
74
+ # Returns the types of the columns returned by this result set.
75
+ def types
76
+ @stmt.types
77
+ end
78
+
79
+ # Returns the names of the columns returned by this result set.
80
+ def columns
81
+ @stmt.columns
82
+ end
83
+
84
+ # Return the next row as a hash
85
+ def next_hash
86
+ row = @stmt.step
87
+ return nil if @stmt.done?
88
+
89
+ @stmt.columns.zip(row).to_h
90
+ end
91
+ end
92
+
93
+ class HashResultSet < ResultSet # :nodoc:
94
+ alias_method :next, :next_hash
95
+ end
96
+ end
@@ -0,0 +1,14 @@
1
+ require "ffi"
2
+
3
+ require_relative "ffi/c_api"
4
+
5
+ require_relative "ffi/aggregator"
6
+ require_relative "ffi/backup"
7
+ require_relative "ffi/core_ext"
8
+ require_relative "ffi/database"
9
+ require_relative "ffi/exception"
10
+ require_relative "ffi/functions"
11
+ require_relative "ffi/sqlite3"
12
+ require_relative "ffi/statement"
13
+ require_relative "ffi/utils"
14
+ require_relative "ffi/version"