duckdb 1.5.2.0 → 1.5.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 (65) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/duckdb.gemspec +37 -0
  4. data/ext/duckdb/aggregate_function.c +62 -100
  5. data/ext/duckdb/aggregate_function.h +2 -2
  6. data/ext/duckdb/aggregate_function_set.c +86 -0
  7. data/ext/duckdb/aggregate_function_set.h +14 -0
  8. data/ext/duckdb/appender.c +121 -39
  9. data/ext/duckdb/appender.h +1 -1
  10. data/ext/duckdb/client_context.c +5 -5
  11. data/ext/duckdb/client_context.h +2 -2
  12. data/ext/duckdb/column.c +13 -13
  13. data/ext/duckdb/column.h +1 -1
  14. data/ext/duckdb/connection.c +63 -41
  15. data/ext/duckdb/connection.h +2 -2
  16. data/ext/duckdb/converter.h +1 -7
  17. data/ext/duckdb/conveter.c +6 -6
  18. data/ext/duckdb/data_chunk.c +22 -22
  19. data/ext/duckdb/data_chunk.h +2 -2
  20. data/ext/duckdb/database.c +10 -10
  21. data/ext/duckdb/database.h +1 -1
  22. data/ext/duckdb/duckdb.c +18 -17
  23. data/ext/duckdb/expression.c +8 -8
  24. data/ext/duckdb/expression.h +1 -1
  25. data/ext/duckdb/extconf.rb +32 -16
  26. data/ext/duckdb/extracted_statements.c +15 -15
  27. data/ext/duckdb/extracted_statements.h +1 -1
  28. data/ext/duckdb/instance_cache.c +10 -10
  29. data/ext/duckdb/instance_cache.h +1 -1
  30. data/ext/duckdb/logical_type.c +94 -133
  31. data/ext/duckdb/logical_type.h +2 -2
  32. data/ext/duckdb/memory_helper.c +28 -28
  33. data/ext/duckdb/pending_result.c +27 -27
  34. data/ext/duckdb/pending_result.h +2 -2
  35. data/ext/duckdb/prepared_statement.c +120 -103
  36. data/ext/duckdb/prepared_statement.h +2 -2
  37. data/ext/duckdb/result.c +24 -74
  38. data/ext/duckdb/result.h +2 -3
  39. data/ext/duckdb/ruby-duckdb.h +5 -0
  40. data/ext/duckdb/scalar_function.c +3 -3
  41. data/ext/duckdb/table_description.c +1 -1
  42. data/ext/duckdb/table_function.c +3 -3
  43. data/ext/duckdb/table_function_bind_info.c +1 -1
  44. data/ext/duckdb/value.c +62 -50
  45. data/ext/duckdb/value.h +2 -2
  46. data/ext/duckdb/vector.c +20 -20
  47. data/ext/duckdb/vector.h +2 -2
  48. data/lib/duckdb/aggregate_function.rb +208 -3
  49. data/lib/duckdb/aggregate_function_set.rb +29 -0
  50. data/lib/duckdb/appender.rb +148 -0
  51. data/lib/duckdb/connection.rb +86 -25
  52. data/lib/duckdb/converter.rb +5 -0
  53. data/lib/duckdb/logical_type.rb +1 -3
  54. data/lib/duckdb/prepared_statement.rb +19 -1
  55. data/lib/duckdb/result.rb +39 -2
  56. data/lib/duckdb/scalar_function.rb +9 -4
  57. data/lib/duckdb/scalar_function_set.rb +0 -1
  58. data/lib/duckdb/table_description.rb +7 -0
  59. data/lib/duckdb/table_function.rb +0 -1
  60. data/lib/duckdb/table_name_parser.rb +58 -0
  61. data/lib/duckdb/value.rb +19 -0
  62. data/lib/duckdb/version.rb +1 -1
  63. data/lib/duckdb.rb +2 -0
  64. metadata +7 -3
  65. data/lib/duckdb/duckdb_native.so +0 -0
@@ -250,6 +250,24 @@ module DuckDB
250
250
  _bind_timestamp(index, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
251
251
  end
252
252
 
253
+ # binds i-th parameter of TIMESTAMP WITH TIME ZONE (TIMESTAMPTZ) type with SQL prepared statement.
254
+ # The first argument is index of parameter.
255
+ # The index of first parameter is 1 not 0.
256
+ # The second argument value is to expected time value.
257
+ #
258
+ # require 'duckdb'
259
+ # db = DuckDB::Database.open('duckdb_database')
260
+ # con = db.connect
261
+ # sql ='SELECT name FROM users WHERE created_at = ?'
262
+ # stmt = PreparedStatement.new(con, sql)
263
+ # stmt.bind_timestamp_tz(1, Time.now)
264
+ # # or you can specify timestamp string.
265
+ # # stmt.bind_timestamp_tz(1, '2022-02-23 07:39:45+00')
266
+ def bind_timestamp_tz(index, value)
267
+ time = _parse_time(value).utc
268
+ _bind_timestamp_tz(index, time.year, time.month, time.day, time.hour, time.min, time.sec, time.usec)
269
+ end
270
+
253
271
  # binds i-th parameter with SQL prepared statement.
254
272
  # The first argument is index of parameter.
255
273
  # The index of first parameter is 1 not 0.
@@ -281,7 +299,7 @@ module DuckDB
281
299
  def bind_decimal(index, value)
282
300
  decimal = _parse_deciaml(value)
283
301
  lower, upper = decimal_to_hugeint(decimal)
284
- width = decimal.to_s('F').gsub(/[^0-9]/, '').length
302
+ width = _decimal_width(decimal)
285
303
  _bind_decimal(index, lower, upper, width, decimal.scale)
286
304
  end
287
305
 
data/lib/duckdb/result.rb CHANGED
@@ -81,11 +81,48 @@ module DuckDB
81
81
  # result = con.query('SELECT * FROM enums')
82
82
  # result.enum_dictionary_values(1) # => ['sad', 'ok', 'happy', '𝘾𝝾օɭ 😎']
83
83
  def enum_dictionary_values(col_index)
84
+ column = columns[col_index]
85
+
86
+ raise ArgumentError, "Invalid index: #{col_index}" if column.nil? || col_index.negative?
87
+
88
+ lt = column.logical_type
89
+
90
+ raise DuckDB::Error, "Column[#{col_index}] type is not enum" if lt.type != :enum
91
+
84
92
  values = []
85
- _enum_dictionary_size(col_index).times do |i|
86
- values << _enum_dictionary_value(col_index, i)
93
+ lt.dictionary_size.times do |i|
94
+ values << lt.dictionary_value_at(i)
87
95
  end
88
96
  values
89
97
  end
98
+
99
+ private
100
+
101
+ def _enum_dictionary_size(idx)
102
+ warn(":_enum_dictionary_size is deprecated. use columns[#{idx}].logical_type.dictionary_size instead.")
103
+
104
+ raise ArgumentError, "Invalid index: #{idx}" if idx.negative?
105
+
106
+ columns[idx]&.logical_type&.dictionary_size
107
+ end
108
+
109
+ def _enum_dictionary_value(col_index, idx)
110
+ warn(":_enum_dictionary_value is deprecated.\
111
+ use columns[#{col_index}].logical_type.dictionary_value_at(#{idx}) instead.")
112
+
113
+ raise ArgumentError, "Invalid index: #{col_index}" if col_index.negative?
114
+
115
+ lt = columns[col_index]&.logical_type
116
+
117
+ raise DuckDB::Error, "Column[#{col_index}] type is not enum" if lt&.type != :enum
118
+
119
+ lt.dictionary_value_at(idx)
120
+ end
121
+
122
+ def _column_type(idx)
123
+ warn(":_column_type is deprecated. use columns[#{idx}].send(:_type) instead.")
124
+
125
+ columns[idx].send(:_type)
126
+ end
90
127
  end
91
128
  end
@@ -7,8 +7,7 @@ module DuckDB
7
7
  class ScalarFunction
8
8
  # Create and configure a scalar function in one call
9
9
  #
10
- # @param name [String, Symbol, nil] the function name; use +nil+ when creating overloads
11
- # intended for use in a +DuckDB::ScalarFunctionSet+ (the set provides the name)
10
+ # @param name [String, Symbol] the function name (required)
12
11
  # @param return_type [DuckDB::LogicalType|:logical_type_symbol] the return type
13
12
  # @param parameter_type [DuckDB::LogicalType|:logical_type_symbol, nil] single fixed parameter type
14
13
  # @param parameter_types [Array<DuckDB::LogicalType|:logical_type_symbol>, nil] multiple fixed parameter types
@@ -64,7 +63,7 @@ module DuckDB
64
63
  # null_handling: true
65
64
  # ) { |v| v.nil? ? 0 : v }
66
65
  def self.create( # rubocop:disable Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity,Metrics/ParameterLists
67
- return_type:, name: nil, parameter_type: nil, parameter_types: nil, varargs_type: nil, null_handling: false, &
66
+ name:, return_type:, parameter_type: nil, parameter_types: nil, varargs_type: nil, null_handling: false, &
68
67
  )
69
68
  raise ArgumentError, 'Block required' unless block_given?
70
69
  raise ArgumentError, 'Cannot specify both parameter_type and parameter_types' if parameter_type && parameter_types
@@ -78,7 +77,7 @@ module DuckDB
78
77
  end
79
78
 
80
79
  sf = new
81
- sf.name = name.to_s if name
80
+ sf.name = name
82
81
  sf.return_type = return_type
83
82
  params.each { |type| sf.add_parameter(type) }
84
83
  sf.varargs_type = varargs_type if varargs_type
@@ -87,6 +86,12 @@ module DuckDB
87
86
  sf
88
87
  end
89
88
 
89
+ def name=(value)
90
+ set_name(value.to_s)
91
+ end
92
+
93
+ private :set_name
94
+
90
95
  include FunctionTypeValidation
91
96
 
92
97
  # Adds a parameter to the scalar function.
@@ -24,7 +24,6 @@ module DuckDB
24
24
  raise TypeError, "#{scalar_function.class} is not a DuckDB::ScalarFunction"
25
25
  end
26
26
 
27
- scalar_function.name = @name
28
27
  _add(scalar_function)
29
28
  end
30
29
  end
@@ -21,11 +21,17 @@ module DuckDB
21
21
  # # id: integer, default=false
22
22
  # # name: varchar, default=true
23
23
  class TableDescription
24
+ include DuckDB::TableNameParser
25
+
24
26
  # Creates a new TableDescription for the given table.
25
27
  #
26
28
  # +con+ must be a DuckDB::Connection. +table+ is the table name (String).
27
29
  # Optionally pass +schema:+ and/or +catalog:+ to qualify the table.
28
30
  #
31
+ # The +table+ argument supports dot-notation and quoting:
32
+ # - <tt>'schema.table'</tt> — interpreted as schema-qualified (deprecated; use +schema:+ instead)
33
+ # - <tt>'"a.b"'</tt> or <tt>"'a.b'"</tt> — treated as a literal table name containing a dot
34
+ #
29
35
  # Raises DuckDB::Error if the connection is invalid, the table name is nil,
30
36
  # or the table (or schema/catalog) does not exist.
31
37
  #
@@ -40,6 +46,7 @@ module DuckDB
40
46
  raise DuckDB::Error, '1st argument must be DuckDB::Connection object.' unless con.is_a?(DuckDB::Connection)
41
47
  raise DuckDB::Error, '2nd argument must be table name.' if table.nil?
42
48
 
49
+ table, schema, catalog = parse_table_name(table, schema, catalog)
43
50
  raise DuckDB::Error, error_message unless _initialize(con, catalog, schema, table)
44
51
  end
45
52
 
@@ -163,7 +163,6 @@ module DuckDB
163
163
  #
164
164
  # # Register and use:
165
165
  # DuckDB::TableFunction.add_table_adapter(CSV, CSVTableAdapter.new)
166
- # con.execute('SET threads=1')
167
166
  # con.expose_as_table(csv, 'csv_table')
168
167
  # con.query('SELECT * FROM csv_table()').to_a
169
168
  #
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DuckDB
4
+ # DuckDB::TableNameParser provides shared table name parsing for classes that
5
+ # accept a table name argument, such as DuckDB::Appender and DuckDB::TableDescription.
6
+ #
7
+ # It handles:
8
+ # - Dot-notation: <tt>'schema.table'</tt> is split into schema and table (deprecated).
9
+ # - Quoting: <tt>'"a.b"'</tt> or <tt>"'a.b'"</tt> strips the quotes and treats the name literally.
10
+ module TableNameParser
11
+ private
12
+
13
+ # Parses +table+, +schema+, and +catalog+, handling quoting and dot-notation.
14
+ # Returns <tt>[table, schema, catalog]</tt>.
15
+ def parse_table_name(table, schema, catalog)
16
+ if quoted_table_name?(table)
17
+ [unquote_table_name(table), schema, catalog]
18
+ elsif table.include?('.')
19
+ warn_dot_notation_deprecated(table)
20
+ dot_notation_split(table, schema, catalog)
21
+ else
22
+ [table, schema, catalog]
23
+ end
24
+ end
25
+
26
+ def quoted_table_name?(name) # :nodoc:
27
+ name.match?(/\A(["']).*\1\z/)
28
+ end
29
+
30
+ def unquote_table_name(name) # :nodoc:
31
+ name[1..-2]
32
+ end
33
+
34
+ # Splits a dot-notation string into [table, schema, catalog].
35
+ # Explicit keyword args take precedence over dot-notation parts.
36
+ def dot_notation_split(table, schema, catalog) # :nodoc:
37
+ parts = table.split('.')
38
+ raise ArgumentError, "Too many dot-separated segments in '#{table}'" if parts.length > 3
39
+
40
+ case parts.length
41
+ when 2 then [parts[1], schema || parts[0], catalog]
42
+ when 3 then [parts[2], schema || parts[1], catalog || parts[0]]
43
+ else raise ArgumentError, "Unexpected segment count in '#{table}'"
44
+ end
45
+ end
46
+
47
+ def warn_dot_notation_deprecated(table) # :nodoc:
48
+ class_name = self.class.name
49
+ warn(
50
+ "Passing dot-notation '#{table}' to #{class_name}.new is deprecated. " \
51
+ "If '#{table}' is a schema-qualified table, use #{class_name}.new(con, table, schema: schema) instead. " \
52
+ "If '#{table}' is a literal table name containing a dot, " \
53
+ "use #{class_name}.new(con, '\"#{table}\"') instead.",
54
+ category: :deprecated
55
+ )
56
+ end
57
+ end
58
+ end
data/lib/duckdb/value.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'bigdecimal'
4
+
3
5
  module DuckDB
4
6
  class Value
5
7
  class << self
@@ -219,6 +221,23 @@ module DuckDB
219
221
  _create_uhugeint(lower, upper)
220
222
  end
221
223
 
224
+ # Creates a DuckDB::Value of DECIMAL type.
225
+ #
226
+ # value = DuckDB::Value.create_decimal(BigDecimal('12345.678'))
227
+ #
228
+ # @param value [BigDecimal] the decimal value.
229
+ # @return [DuckDB::Value] the created Value object.
230
+ # @raise [ArgumentError] if +value+ is not a BigDecimal or its width is out of range (1..38).
231
+ def create_decimal(value)
232
+ check_type!(value, BigDecimal)
233
+
234
+ width = _decimal_width(value)
235
+ check_range!(width, RANGE_DECIMAL_WIDTH, 'DECIMAL width')
236
+
237
+ lower, upper = decimal_to_hugeint(value)
238
+ _create_decimal(lower, upper, width, value.scale)
239
+ end
240
+
222
241
  private
223
242
 
224
243
  def check_range!(value, range, type_name)
@@ -3,5 +3,5 @@
3
3
  module DuckDB
4
4
  # The version string of ruby-duckdb.
5
5
  # Currently, ruby-duckdb is NOT semantic versioning.
6
- VERSION = '1.5.2.0'
6
+ VERSION = '1.5.3.0'
7
7
  end
data/lib/duckdb.rb CHANGED
@@ -4,6 +4,7 @@ require 'duckdb/duckdb_native'
4
4
  require 'duckdb/library_version'
5
5
  require 'duckdb/version'
6
6
  require 'duckdb/converter'
7
+ require 'duckdb/table_name_parser'
7
8
  require 'duckdb/database'
8
9
  require 'duckdb/connection'
9
10
  require 'duckdb/extracted_statements'
@@ -18,6 +19,7 @@ require 'duckdb/function_type_validation'
18
19
  require 'duckdb/scalar_function'
19
20
  require 'duckdb/scalar_function_set'
20
21
  require 'duckdb/aggregate_function'
22
+ require 'duckdb/aggregate_function_set'
21
23
  require 'duckdb/expression'
22
24
  require 'duckdb/client_context'
23
25
  require 'duckdb/scalar_function/bind_info'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: duckdb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2.0
4
+ version: 1.5.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Masaki Suketa
@@ -40,8 +40,11 @@ files:
40
40
  - Rakefile
41
41
  - bin/console
42
42
  - bin/setup
43
+ - duckdb.gemspec
43
44
  - ext/duckdb/aggregate_function.c
44
45
  - ext/duckdb/aggregate_function.h
46
+ - ext/duckdb/aggregate_function_set.c
47
+ - ext/duckdb/aggregate_function_set.h
45
48
  - ext/duckdb/appender.c
46
49
  - ext/duckdb/appender.h
47
50
  - ext/duckdb/blob.c
@@ -109,6 +112,7 @@ files:
109
112
  - ext/duckdb/vector.h
110
113
  - lib/duckdb.rb
111
114
  - lib/duckdb/aggregate_function.rb
115
+ - lib/duckdb/aggregate_function_set.rb
112
116
  - lib/duckdb/appender.rb
113
117
  - lib/duckdb/casting.rb
114
118
  - lib/duckdb/client_context.rb
@@ -120,7 +124,6 @@ files:
120
124
  - lib/duckdb/converter/int_to_sym.rb
121
125
  - lib/duckdb/data_chunk.rb
122
126
  - lib/duckdb/database.rb
123
- - lib/duckdb/duckdb_native.so
124
127
  - lib/duckdb/expression.rb
125
128
  - lib/duckdb/extracted_statements.rb
126
129
  - lib/duckdb/function_type_validation.rb
@@ -140,6 +143,7 @@ files:
140
143
  - lib/duckdb/table_function/bind_info.rb
141
144
  - lib/duckdb/table_function/function_info.rb
142
145
  - lib/duckdb/table_function/init_info.rb
146
+ - lib/duckdb/table_name_parser.rb
143
147
  - lib/duckdb/value.rb
144
148
  - lib/duckdb/vector.rb
145
149
  - lib/duckdb/version.rb
@@ -165,7 +169,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
165
169
  - !ruby/object:Gem::Version
166
170
  version: '0'
167
171
  requirements: []
168
- rubygems_version: 4.0.6
172
+ rubygems_version: 4.0.10
169
173
  specification_version: 4
170
174
  summary: Ruby bindings for the DuckDB database engine.
171
175
  test_files: []
Binary file