amalgalite 1.9.4-x86-mingw32 → 2.0.0-x86-mingw32

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/HISTORY.md +19 -2
  3. data/Manifest.txt +4 -54
  4. data/README.md +1 -1
  5. data/TODO.md +4 -3
  6. data/amalgalite.gemspec +39 -0
  7. data/ext/amalgalite/c/amalgalite.c +0 -1
  8. data/ext/amalgalite/c/amalgalite_constants.c +155 -10
  9. data/ext/amalgalite/c/extconf.rb +5 -2
  10. data/ext/amalgalite/c/gen_constants.rb +32 -1
  11. data/ext/amalgalite/c/sqlite3.c +19308 -9112
  12. data/ext/amalgalite/c/sqlite3.h +909 -296
  13. data/ext/amalgalite/c/sqlite3ext.h +11 -0
  14. data/lib/amalgalite/2.7/amalgalite.so +0 -0
  15. data/lib/amalgalite/3.0/amalgalite.so +0 -0
  16. data/lib/amalgalite/3.1/amalgalite.so +0 -0
  17. data/lib/amalgalite/3.2/amalgalite.so +0 -0
  18. data/lib/amalgalite/3.3/amalgalite.so +0 -0
  19. data/lib/amalgalite/3.4/amalgalite.so +0 -0
  20. data/lib/amalgalite/column.rb +20 -2
  21. data/lib/amalgalite/result/row.rb +83 -0
  22. data/lib/amalgalite/result.rb +15 -0
  23. data/lib/amalgalite/statement.rb +32 -24
  24. data/lib/amalgalite/type_maps/default_map.rb +48 -56
  25. data/lib/amalgalite/version.rb +1 -1
  26. metadata +36 -123
  27. data/Rakefile +0 -27
  28. data/bin/amalgalite-pack +0 -147
  29. data/examples/a.rb +0 -9
  30. data/examples/blob.rb +0 -88
  31. data/examples/bootstrap.rb +0 -36
  32. data/examples/define_aggregate.rb +0 -75
  33. data/examples/define_function.rb +0 -104
  34. data/examples/fts5.rb +0 -152
  35. data/examples/gem-db.rb +0 -94
  36. data/examples/require_me.rb +0 -11
  37. data/examples/requires.rb +0 -42
  38. data/examples/schema-info.rb +0 -34
  39. data/ext/amalgalite/c/amalgalite_requires_bootstrap.c +0 -283
  40. data/lib/amalgalite/2.4/amalgalite.so +0 -0
  41. data/lib/amalgalite/2.5/amalgalite.so +0 -0
  42. data/lib/amalgalite/2.6/amalgalite.so +0 -0
  43. data/lib/amalgalite/core_ext/kernel/require.rb +0 -21
  44. data/lib/amalgalite/packer.rb +0 -231
  45. data/lib/amalgalite/requires.rb +0 -151
  46. data/spec/aggregate_spec.rb +0 -158
  47. data/spec/amalgalite_spec.rb +0 -4
  48. data/spec/blob_spec.rb +0 -78
  49. data/spec/boolean_spec.rb +0 -24
  50. data/spec/busy_handler.rb +0 -157
  51. data/spec/data/iso-3166-country.txt +0 -242
  52. data/spec/data/iso-3166-schema.sql +0 -22
  53. data/spec/data/iso-3166-subcountry.txt +0 -3995
  54. data/spec/data/make-iso-db.sh +0 -12
  55. data/spec/database_spec.rb +0 -505
  56. data/spec/default_map_spec.rb +0 -92
  57. data/spec/function_spec.rb +0 -78
  58. data/spec/integeration_spec.rb +0 -97
  59. data/spec/iso_3166_database.rb +0 -58
  60. data/spec/json_spec.rb +0 -24
  61. data/spec/packer_spec.rb +0 -60
  62. data/spec/paths_spec.rb +0 -28
  63. data/spec/progress_handler_spec.rb +0 -91
  64. data/spec/requires_spec.rb +0 -54
  65. data/spec/rtree_spec.rb +0 -66
  66. data/spec/schema_spec.rb +0 -131
  67. data/spec/spec_helper.rb +0 -48
  68. data/spec/sqlite3/constants_spec.rb +0 -108
  69. data/spec/sqlite3/database_status_spec.rb +0 -36
  70. data/spec/sqlite3/status_spec.rb +0 -22
  71. data/spec/sqlite3/version_spec.rb +0 -28
  72. data/spec/sqlite3_spec.rb +0 -53
  73. data/spec/statement_spec.rb +0 -168
  74. data/spec/storage_map_spec.rb +0 -38
  75. data/spec/tap_spec.rb +0 -57
  76. data/spec/text_map_spec.rb +0 -20
  77. data/spec/type_map_spec.rb +0 -14
  78. data/spec/version_spec.rb +0 -8
  79. data/tasks/custom.rake +0 -101
  80. data/tasks/default.rake +0 -257
  81. data/tasks/extension.rake +0 -28
  82. data/tasks/this.rb +0 -208
  83. /data/{LICENSE → LICENSE.txt} +0 -0
@@ -366,6 +366,12 @@ struct sqlite3_api_routines {
366
366
  /* Version 3.44.0 and later */
367
367
  void *(*get_clientdata)(sqlite3*,const char*);
368
368
  int (*set_clientdata)(sqlite3*, const char*, void*, void(*)(void*));
369
+ /* Version 3.50.0 and later */
370
+ int (*setlk_timeout)(sqlite3*,int,int);
371
+ /* Version 3.51.0 and later */
372
+ int (*set_errmsg)(sqlite3*,int,const char*);
373
+ int (*db_status64)(sqlite3*,int,sqlite3_int64*,sqlite3_int64*,int);
374
+
369
375
  };
370
376
 
371
377
  /*
@@ -699,6 +705,11 @@ typedef int (*sqlite3_loadext_entry)(
699
705
  /* Version 3.44.0 and later */
700
706
  #define sqlite3_get_clientdata sqlite3_api->get_clientdata
701
707
  #define sqlite3_set_clientdata sqlite3_api->set_clientdata
708
+ /* Version 3.50.0 and later */
709
+ #define sqlite3_setlk_timeout sqlite3_api->setlk_timeout
710
+ /* Version 3.51.0 and later */
711
+ #define sqlite3_set_errmsg sqlite3_api->set_errmsg
712
+ #define sqlite3_db_status64 sqlite3_api->db_status64
702
713
  #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */
703
714
 
704
715
  #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION)
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -27,6 +27,10 @@ module Amalgalite
27
27
  # the column name
28
28
  attr_accessor :name
29
29
 
30
+ # The column "as" name. This is what its name is in the query, if this is
31
+ # part of the query, then this is the result, otherwise it is the name
32
+ attr_accessor :as_name
33
+
30
34
  # the default value of the column. This may not have a value and that
31
35
  # either means that there is no default value, or one could not be
32
36
  # determined.
@@ -35,7 +39,10 @@ module Amalgalite
35
39
 
36
40
  # the declared data type of the column in the original sql that created the
37
41
  # column
38
- attr_accessor :declared_data_type
42
+ attr_reader :declared_data_type
43
+
44
+ # the declared data type that is tokenized and then downcased
45
+ attr_reader :normalized_declared_data_type
39
46
 
40
47
  # the collation sequence name of the column
41
48
  attr_accessor :collation_sequence_name
@@ -47,15 +54,26 @@ module Amalgalite
47
54
  ##
48
55
  # Create a column with its name and associated table
49
56
  #
50
- def initialize( db, table, name, order)
57
+ def initialize( db, table, name, order, as_name = nil)
51
58
  @db = db
52
59
  @table = table
53
60
  @name = name
54
61
  @order = Float(order).to_i
62
+ @as_name = as_name || name
55
63
  @declared_data_type = nil
64
+ @normalized_declared_data_type = nil
56
65
  @default_value = nil
57
66
  end
58
67
 
68
+ def declared_data_type=(input)
69
+ return nil if input.nil?
70
+ @declared_data_type = input
71
+
72
+ # just the first word token
73
+ @normalized_declared_data_type = input[/^\w+/]&.downcase
74
+ return @declared_data_type
75
+ end
76
+
59
77
  # true if the column has a default value
60
78
  def has_default_value?
61
79
  not default_value.nil?
@@ -0,0 +1,83 @@
1
+ #--
2
+ # Copyright (c) 2025 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ class Result
8
+ ##
9
+ # The class that represents a single row from a query.
10
+ #
11
+ class Row
12
+ # The result object this row is retrivved from, nil if all values
13
+ # are materialized
14
+ attr_reader :result
15
+
16
+ # A Hash that maps the field names to indexes in values
17
+ # This may be linked to shared field from the result
18
+ attr_reader :field_map
19
+
20
+ # An array containing the values from the row
21
+ attr_reader :values
22
+ alias to_a values
23
+
24
+ def initialize(result: nil, field_map:, values:)
25
+ @result = result
26
+ @field_map = field_map
27
+ @values = values
28
+ self.freeze
29
+ end
30
+
31
+ def fields
32
+ @field_map.keys
33
+ end
34
+
35
+ def store_by_index(index, value)
36
+ @values[index] = value
37
+ end
38
+
39
+ def store(field_name_or_index, value)
40
+ index = field_name_or_index_to_index(field_name_or_index)
41
+ @values[index] = value
42
+ end
43
+ alias []= store
44
+
45
+ def fetch(field_name_or_index)
46
+ case field_name_or_index
47
+ when Integer
48
+ @values[field_name_or_index]
49
+ when Symbol, String
50
+ @values[field_map[field_name_or_index]]
51
+ else
52
+ raise Amalgalite::Error, "Unknown type (#{field_name_or_index.class}) of key for a Row value: #{field_name_or_index}"
53
+ end
54
+ end
55
+ alias [] fetch
56
+
57
+ def first
58
+ fetch(0)
59
+ end
60
+
61
+ def length
62
+ @values.size
63
+ end
64
+
65
+ def to_h
66
+ Hash[@field_map.keys.zip(values)]
67
+ end
68
+
69
+ private
70
+
71
+ def field_name_or_index_to_index(field_name_or_index)
72
+ case field_name_or_index
73
+ when Integer
74
+ field_name_or_index
75
+ when Symbol, String
76
+ @values[@field_map[field_name_or_index]]
77
+ else
78
+ raise Amalgalite::Error, "Unknown type (#{field_name_or_index.class}) of key for a Row value: #{field_name_or_index}"
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,15 @@
1
+ #--
2
+ # Copyright (c) 2025 Jeremy Hinegardner
3
+ # All rights reserved. See LICENSE and/or COPYING for details.
4
+ #++
5
+
6
+ module Amalgalite
7
+ ##
8
+ # The class to that represents the query result.
9
+ #
10
+ class Result
11
+
12
+ end
13
+ end
14
+
15
+ require 'amalgalite/result/row'
@@ -4,8 +4,7 @@
4
4
  #++
5
5
  #
6
6
  require 'date'
7
- require 'arrayfields'
8
- require 'ostruct'
7
+ require 'amalgalite/result'
9
8
 
10
9
  module Amalgalite
11
10
  class Statement
@@ -258,10 +257,11 @@ module Amalgalite
258
257
  # Database#type_map
259
258
  #
260
259
  def next_row
261
- row = []
260
+ row = nil
262
261
  case rc = @stmt_api.step
263
262
  when ResultCode::ROW
264
- result_meta.each_with_index do |col, idx|
263
+ row = ::Amalgalite::Result::Row.new(field_map: result_field_map, values: Array.new(result_meta.size))
264
+ result_meta.each.with_index do |col, idx|
265
265
  value = nil
266
266
  column_type = @stmt_api.column_type( idx )
267
267
  case column_type
@@ -278,28 +278,26 @@ module Amalgalite
278
278
  # blob api, otherwise we have to use the all at once version.
279
279
  if using_rowid_column? then
280
280
  value = Amalgalite::Blob.new( :db_blob => SQLite3::Blob.new( db.api,
281
- col.schema.db,
282
- col.schema.table,
283
- col.schema.name,
281
+ col.db,
282
+ col.table,
283
+ col.name,
284
284
  @stmt_api.column_int64( @rowid_index ),
285
285
  "r"),
286
- :column => col.schema)
286
+ :column => col)
287
287
  else
288
- value = Amalgalite::Blob.new( :string => @stmt_api.column_blob( idx ), :column => col.schema )
288
+ value = Amalgalite::Blob.new( :string => @stmt_api.column_blob( idx ), :column => col )
289
289
  end
290
290
  else
291
291
  raise ::Amalgalite::Error, "BUG! : Unknown SQLite column type of #{column_type}"
292
292
  end
293
293
 
294
- row << db.type_map.result_value_of( col.schema.declared_data_type, value )
294
+ row.store_by_index(idx, db.type_map.result_value_of( col.normalized_declared_data_type, value ))
295
295
  end
296
- row.fields = result_fields
297
296
  when ResultCode::DONE
298
- row = nil
299
297
  write_blobs
300
298
  else
301
299
  self.close # must close so that the error message is guaranteed to be pushed into the database handler
302
- # and we can can call last_error_message on it
300
+ # and we can call last_error_message on it
303
301
  msg = "SQLITE ERROR #{rc} (#{Amalgalite::SQLite3::Constants::ResultCode.name_from_value( rc )}) : #{@db.api.last_error_message}"
304
302
  raise Amalgalite::SQLite3::Error, msg
305
303
  end
@@ -326,23 +324,24 @@ module Amalgalite
326
324
  # The full meta information from the origin column is also obtained for help
327
325
  # in doing type conversion.
328
326
  #
329
- # As iteration over the row meta informatio happens, record if the special
327
+ # As iteration over the row meta information happens, record if the special
330
328
  # "ROWID", "OID", or "_ROWID_" column is encountered. If that column is
331
329
  # encountered then we make note of it.
332
330
  #
331
+ # This method cannot be called until after the @stmt_api has returne from
332
+ # `step` at least once
333
+ #
333
334
  def result_meta
334
335
  unless @result_meta
335
336
  meta = []
336
337
  column_count.times do |idx|
337
- column_meta = ::OpenStruct.new
338
- column_meta.name = @stmt_api.column_name( idx )
339
-
340
- db_name = @stmt_api.column_database_name( idx )
341
- tbl_name = @stmt_api.column_table_name( idx )
342
- col_name = @stmt_api.column_origin_name( idx )
338
+ as_name = @stmt_api.column_name( idx )
339
+ db_name = @stmt_api.column_database_name( idx )
340
+ tbl_name = @stmt_api.column_table_name( idx )
341
+ col_name = @stmt_api.column_origin_name( idx )
343
342
 
344
- column_meta.schema = ::Amalgalite::Column.new( db_name, tbl_name, col_name, idx )
345
- column_meta.schema.declared_data_type = @stmt_api.column_declared_type( idx )
343
+ column_meta = ::Amalgalite::Column.new( db_name, tbl_name, col_name, idx, as_name )
344
+ column_meta.declared_data_type = @stmt_api.column_declared_type( idx )
346
345
 
347
346
  # only check for rowid if we have a table name and it is not one of the
348
347
  # sqlite_master tables. We could get recursion in those cases.
@@ -351,7 +350,7 @@ module Amalgalite
351
350
  @rowid_index = idx
352
351
  end
353
352
 
354
- meta << column_meta
353
+ meta << column_meta
355
354
  end
356
355
 
357
356
  @result_meta = meta
@@ -382,7 +381,16 @@ module Amalgalite
382
381
  # all strings
383
382
  #
384
383
  def result_fields
385
- @fields ||= result_meta.collect { |m| m.name }
384
+ @fields ||= result_meta.collect { |m| m.as_name }
385
+ end
386
+
387
+ def result_field_map
388
+ @result_field_map ||= {}.tap do |map|
389
+ result_meta.each do |column|
390
+ map[column.as_name.to_s] = column.order
391
+ map[column.as_name.to_sym] = column.order
392
+ end
393
+ end
386
394
  end
387
395
 
388
396
  ##
@@ -15,47 +15,42 @@ module Amalgalite::TypeMaps
15
15
  # out the best way to convert between populate SQL 'types' and ruby classes
16
16
  #
17
17
  class DefaultMap
18
- class << self
19
- def methods_handling_sql_types # :nodoc:
20
- @methods_handling_sql_types ||= {
21
- 'date' => %w[ date ],
22
- 'datetime' => %w[ datetime ],
23
- 'time' => %w[ timestamp time ],
24
- 'float' => %w[ double float real numeric decimal ],
25
- 'integer' => %w[ integer tinyint smallint int int2 int4 int8 bigint serial bigserial ],
26
- 'string' => %w[ text char string varchar character json ],
27
- 'boolean' => %w[ bool boolean ],
28
- 'blob' => %w[ binary blob ],
29
- }
30
- end
18
+ SQL_TO_METHOD = {
19
+ 'date' => 'date',
20
+ 'datetime' => 'datetime',
21
+ 'timestamp' => 'time',
22
+ 'time' => 'time',
31
23
 
32
- # say what method to call to convert an sql type to a ruby type
33
- #
34
- def sql_to_method( sql_type ) # :nodoc:
35
- unless defined? @sql_to_method
36
- @sql_to_method = {}
37
- methods_handling_sql_types.each_pair do |method, sql_types|
38
- sql_types.each { |t| @sql_to_method[t] = method }
39
- end
40
- end
41
- return_method = @sql_to_method[sql_type]
42
-
43
- # the straight lookup didn't work, try iterating through the types and
44
- # see what is found
45
- unless return_method
46
- @sql_to_method.each_pair do |sql, method|
47
- if sql_type.index(sql) then
48
- return_method = method
49
- break
50
- end
51
- end
52
- end
53
- return return_method
54
- end
55
- end
24
+ 'double' => 'float',
25
+ 'float' => 'float',
26
+ 'real' => 'float',
27
+ 'numeric' => 'float',
28
+ 'decimal' => 'float',
56
29
 
57
- def initialize
58
- end
30
+ 'integer' => 'integer',
31
+ 'tinyint' => 'integer',
32
+ 'smallint' => 'integer',
33
+ 'int' => 'integer',
34
+ 'int2' => 'integer',
35
+ 'int4' => 'integer',
36
+ 'int8' => 'integer',
37
+ 'bigint' => 'integer',
38
+ 'serial' => 'integer',
39
+ 'bigserial' => 'integer',
40
+
41
+ 'text' => 'string',
42
+ 'char' => 'string',
43
+ 'string' => 'string',
44
+ 'varchar' => 'string',
45
+ 'character' => 'string',
46
+ 'json' => 'string',
47
+
48
+ 'bool' => 'boolean',
49
+ 'boolean' => 'boolean',
50
+
51
+ 'blob' => 'blob',
52
+ 'binary' => 'blob',
53
+ }.freeze
59
54
 
60
55
  ##
61
56
  # A straight logical mapping (for me at least) of basic Ruby classes to SQLite types, if
@@ -79,29 +74,26 @@ module Amalgalite::TypeMaps
79
74
  ##
80
75
  # Map the incoming value to an outgoing value. For some incoming values,
81
76
  # there will be no change, but for some (i.e. Dates and Times) there is some
82
- # conversion
77
+ # conversion.
78
+ #
79
+ # It is assumed that `normalized_declared_type` is a downcased string. This
80
+ # assumption is made for performance reasons as this method is called many
81
+ # times during the returning of data from a query.
83
82
  #
84
- def result_value_of( declared_type, value )
83
+ def result_value_of( normalized_declared_type, value )
85
84
  case value
86
- when Numeric
87
- return value
88
- when NilClass
89
- return value
90
- when Amalgalite::Blob
85
+ when Numeric, NilClass, Amalgalite::Blob
91
86
  return value
92
87
  when String
93
- if declared_type then
94
- conversion_method = DefaultMap.sql_to_method( declared_type.downcase )
95
- if conversion_method then
96
- return send(conversion_method, value)
97
- else
98
- raise ::Amalgalite::Error, "Unable to convert SQL type of #{declared_type} to a Ruby class"
99
- end
88
+ return value unless normalized_declared_type
89
+
90
+ conversion_method = DefaultMap::SQL_TO_METHOD[normalized_declared_type]
91
+ if conversion_method then
92
+ return send(conversion_method, value)
100
93
  else
101
- # unable to do any other conversion, just return what we have.
102
- return value
94
+ raise ::Amalgalite::Error, "Unable to convert SQL type of #{normalized_declared_type} to a Ruby class"
103
95
  end
104
- else
96
+ else
105
97
  raise ::Amalgalite::Error, "Unable to convert a class #{value.class.name} with value #{value.inspect}"
106
98
  end
107
99
  end
@@ -4,5 +4,5 @@
4
4
  #++
5
5
 
6
6
  module Amalgalite
7
- VERSION = "1.9.4"
7
+ VERSION = "2.0.0"
8
8
  end