duckdb 0.8.2-dev2399.0 → 0.8.2-dev2509.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.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "duckdb",
3
3
  "main": "./lib/duckdb.js",
4
4
  "types": "./lib/duckdb.d.ts",
5
- "version": "0.8.2-dev2399.0",
5
+ "version": "0.8.2-dev2509.0",
6
6
  "description": "DuckDB node.js API",
7
7
  "gypfile": true,
8
8
  "dependencies": {
@@ -0,0 +1,78 @@
1
+ #include "duckdb/common/http_state.hpp"
2
+
3
+ namespace duckdb {
4
+
5
+ CachedFileHandle::CachedFileHandle(shared_ptr<CachedFile> &file_p) {
6
+ // If the file was not yet initialized, we need to grab a lock.
7
+ if (!file_p->initialized) {
8
+ lock = make_uniq<lock_guard<mutex>>(file_p->lock);
9
+ }
10
+ file = file_p;
11
+ }
12
+
13
+ void CachedFileHandle::SetInitialized() {
14
+ if (file->initialized) {
15
+ throw InternalException("Cannot set initialized on cached file that was already initialized");
16
+ }
17
+ if (!lock) {
18
+ throw InternalException("Cannot set initialized on cached file without lock");
19
+ }
20
+ file->initialized = true;
21
+ lock = nullptr;
22
+ }
23
+
24
+ void CachedFileHandle::AllocateBuffer(idx_t size) {
25
+ if (file->initialized) {
26
+ throw InternalException("Cannot allocate a buffer for a cached file that was already initialized");
27
+ }
28
+ file->data = std::shared_ptr<char>(new char[size], std::default_delete<char[]>());
29
+ file->capacity = size;
30
+ }
31
+
32
+ void CachedFileHandle::GrowBuffer(idx_t new_capacity, idx_t bytes_to_copy) {
33
+ // copy shared ptr to old data
34
+ auto old_data = file->data;
35
+ // allocate new buffer that can hold the new capacity
36
+ AllocateBuffer(new_capacity);
37
+ // copy the old data
38
+ Write(old_data.get(), bytes_to_copy);
39
+ }
40
+
41
+ void CachedFileHandle::Write(const char *buffer, idx_t length, idx_t offset) {
42
+ //! Only write to non-initialized files with a lock;
43
+ D_ASSERT(!file->initialized && lock);
44
+ memcpy(file->data.get() + offset, buffer, length);
45
+ }
46
+
47
+ void HTTPState::Reset() {
48
+ // Reset Counters
49
+ head_count = 0;
50
+ get_count = 0;
51
+ put_count = 0;
52
+ post_count = 0;
53
+ total_bytes_received = 0;
54
+ total_bytes_sent = 0;
55
+
56
+ // Reset cached files
57
+ cached_files.clear();
58
+ }
59
+
60
+ shared_ptr<HTTPState> HTTPState::TryGetState(FileOpener *opener) {
61
+ auto client_context = FileOpener::TryGetClientContext(opener);
62
+ if (client_context) {
63
+ return client_context->client_data->http_state;
64
+ }
65
+ return nullptr;
66
+ }
67
+
68
+ //! Get cache entry, create if not exists
69
+ shared_ptr<CachedFile> &HTTPState::GetCachedFile(const string &path) {
70
+ lock_guard<mutex> lock(cached_files_mutex);
71
+ auto &cache_entry_ref = cached_files[path];
72
+ if (!cache_entry_ref) {
73
+ cache_entry_ref = make_shared<CachedFile>();
74
+ }
75
+ return cache_entry_ref;
76
+ }
77
+
78
+ } // namespace duckdb
@@ -73,7 +73,7 @@ static StaticFunctionDefinition internal_functions[] = {
73
73
  DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayDistinctFun),
74
74
  DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayFilterFun),
75
75
  DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArrayReverseSortFun),
76
- DUCKDB_SCALAR_FUNCTION_ALIAS(ArraySliceFun),
76
+ DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArraySliceFun),
77
77
  DUCKDB_SCALAR_FUNCTION_SET_ALIAS(ArraySortFun),
78
78
  DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayTransformFun),
79
79
  DUCKDB_SCALAR_FUNCTION_ALIAS(ArrayUniqueFun),
@@ -200,7 +200,7 @@ static StaticFunctionDefinition internal_functions[] = {
200
200
  DUCKDB_SCALAR_FUNCTION(ListFilterFun),
201
201
  DUCKDB_SCALAR_FUNCTION_ALIAS(ListPackFun),
202
202
  DUCKDB_SCALAR_FUNCTION_SET(ListReverseSortFun),
203
- DUCKDB_SCALAR_FUNCTION(ListSliceFun),
203
+ DUCKDB_SCALAR_FUNCTION_SET(ListSliceFun),
204
204
  DUCKDB_SCALAR_FUNCTION_SET(ListSortFun),
205
205
  DUCKDB_SCALAR_FUNCTION(ListTransformFun),
206
206
  DUCKDB_SCALAR_FUNCTION(ListUniqueFun),
@@ -1,14 +1,62 @@
1
1
  #include "duckdb/core_functions/scalar/list_functions.hpp"
2
- #include "duckdb/common/pair.hpp"
3
2
  #include "duckdb/common/string_util.hpp"
3
+ #include "duckdb/common/swap.hpp"
4
4
  #include "duckdb/common/types/data_chunk.hpp"
5
5
  #include "duckdb/function/scalar/nested_functions.hpp"
6
6
  #include "duckdb/function/scalar/string_functions.hpp"
7
- #include "duckdb/parser/expression/bound_expression.hpp"
8
7
  #include "duckdb/planner/expression/bound_function_expression.hpp"
8
+ #include "duckdb/planner/expression/bound_constant_expression.hpp"
9
9
 
10
10
  namespace duckdb {
11
11
 
12
+ struct ListSliceBindData : public FunctionData {
13
+ ListSliceBindData(const LogicalType &return_type_p, bool begin_is_empty_p, bool end_is_empty_p)
14
+ : return_type(return_type_p), begin_is_empty(begin_is_empty_p), end_is_empty(end_is_empty_p) {
15
+ }
16
+ ~ListSliceBindData() override;
17
+
18
+ LogicalType return_type;
19
+
20
+ bool begin_is_empty;
21
+ bool end_is_empty;
22
+
23
+ public:
24
+ bool Equals(const FunctionData &other_p) const override;
25
+ unique_ptr<FunctionData> Copy() const override;
26
+ };
27
+
28
+ ListSliceBindData::~ListSliceBindData() {
29
+ }
30
+
31
+ bool ListSliceBindData::Equals(const FunctionData &other_p) const {
32
+ auto &other = other_p.Cast<ListSliceBindData>();
33
+ return return_type == other.return_type && begin_is_empty == other.begin_is_empty &&
34
+ end_is_empty == other.end_is_empty;
35
+ }
36
+
37
+ unique_ptr<FunctionData> ListSliceBindData::Copy() const {
38
+ return make_uniq<ListSliceBindData>(return_type, begin_is_empty, end_is_empty);
39
+ }
40
+
41
+ template <typename INDEX_TYPE>
42
+ static int CalculateSliceLength(idx_t begin, idx_t end, INDEX_TYPE step, bool svalid) {
43
+ if (step < 0) {
44
+ step = abs(step);
45
+ }
46
+ if (step == 0 && svalid) {
47
+ throw InvalidInputException("Slice step cannot be zero");
48
+ }
49
+ if (step == 1) {
50
+ return end - begin;
51
+ } else if (static_cast<idx_t>(step) >= (end - begin)) {
52
+ return 1;
53
+ }
54
+ if ((end - begin) % step != 0) {
55
+ return (end - begin) / step + 1;
56
+ }
57
+ return (end - begin) / step;
58
+ }
59
+
12
60
  template <typename INPUT_TYPE, typename INDEX_TYPE>
13
61
  INDEX_TYPE ValueLength(const INPUT_TYPE &value) {
14
62
  return 0;
@@ -20,33 +68,44 @@ int64_t ValueLength(const list_entry_t &value) {
20
68
  }
21
69
 
22
70
  template <>
23
- int32_t ValueLength(const string_t &value) {
24
- return LengthFun::Length<string_t, int32_t>(value);
71
+ int64_t ValueLength(const string_t &value) {
72
+ return LengthFun::Length<string_t, int64_t>(value);
25
73
  }
26
74
 
27
75
  template <typename INPUT_TYPE, typename INDEX_TYPE>
28
- bool ClampIndex(INDEX_TYPE &index, const INPUT_TYPE &value) {
29
- const auto length = ValueLength<INPUT_TYPE, INDEX_TYPE>(value);
76
+ static void ClampIndex(INDEX_TYPE &index, const INPUT_TYPE &value, const INDEX_TYPE length, bool is_min) {
30
77
  if (index < 0) {
31
- if (index < -length) {
32
- return false;
33
- }
78
+ index = (!is_min) ? index + 1 : index;
34
79
  index = length + index;
80
+ return;
35
81
  } else if (index > length) {
36
82
  index = length;
37
83
  }
38
- return true;
84
+ return;
39
85
  }
40
86
 
41
87
  template <typename INPUT_TYPE, typename INDEX_TYPE>
42
- static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &end, bool begin_valid, bool end_valid) {
88
+ static bool ClampSlice(const INPUT_TYPE &value, INDEX_TYPE &begin, INDEX_TYPE &end) {
43
89
  // Clamp offsets
44
- begin = begin_valid ? begin : 0;
45
- begin = (begin > 0) ? begin - 1 : begin;
46
- end = end_valid ? end : ValueLength<INPUT_TYPE, INDEX_TYPE>(value);
47
- if (!ClampIndex(begin, value) || !ClampIndex(end, value)) {
48
- return false;
90
+ begin = (begin != 0 && begin != (INDEX_TYPE)NumericLimits<int64_t>::Minimum()) ? begin - 1 : begin;
91
+
92
+ bool is_min = false;
93
+ if (begin == (INDEX_TYPE)NumericLimits<int64_t>::Minimum()) {
94
+ begin++;
95
+ is_min = true;
96
+ }
97
+
98
+ const auto length = ValueLength<INPUT_TYPE, INDEX_TYPE>(value);
99
+ if (begin < 0 && -begin > length && end < 0 && -end > length) {
100
+ begin = 0;
101
+ end = 0;
102
+ return true;
103
+ }
104
+ if (begin < 0 && -begin > length) {
105
+ begin = 0;
49
106
  }
107
+ ClampIndex(begin, value, length, is_min);
108
+ ClampIndex(end, value, length, false);
50
109
  end = MaxValue<INDEX_TYPE>(begin, end);
51
110
 
52
111
  return true;
@@ -65,108 +124,262 @@ list_entry_t SliceValue(Vector &result, list_entry_t input, int64_t begin, int64
65
124
  }
66
125
 
67
126
  template <>
68
- string_t SliceValue(Vector &result, string_t input, int32_t begin, int32_t end) {
127
+ string_t SliceValue(Vector &result, string_t input, int64_t begin, int64_t end) {
69
128
  // one-based - zero has strange semantics
70
129
  return SubstringFun::SubstringUnicode(result, input, begin + 1, end - begin);
71
130
  }
72
131
 
73
132
  template <typename INPUT_TYPE, typename INDEX_TYPE>
74
- static void ExecuteSlice(Vector &result, Vector &s, Vector &b, Vector &e, const idx_t count) {
75
- if (result.GetVectorType() == VectorType::CONSTANT_VECTOR) {
76
- auto rdata = ConstantVector::GetData<INPUT_TYPE>(result);
77
- auto sdata = ConstantVector::GetData<INPUT_TYPE>(s);
78
- auto bdata = ConstantVector::GetData<INDEX_TYPE>(b);
79
- auto edata = ConstantVector::GetData<INDEX_TYPE>(e);
80
-
81
- auto sliced = sdata[0];
82
- auto begin = bdata[0];
83
- auto end = edata[0];
84
-
85
- auto svalid = !ConstantVector::IsNull(s);
86
- auto bvalid = !ConstantVector::IsNull(b);
87
- auto evalid = !ConstantVector::IsNull(e);
88
-
89
- // Try to slice
90
- if (!svalid || !ClampSlice(sliced, begin, end, bvalid, evalid)) {
91
- ConstantVector::SetNull(result, true);
92
- } else {
93
- rdata[0] = SliceValue<INPUT_TYPE, INDEX_TYPE>(result, sliced, begin, end);
94
- }
133
+ INPUT_TYPE SliceValueWithSteps(Vector &result, SelectionVector &sel, INPUT_TYPE input, INDEX_TYPE begin, INDEX_TYPE end,
134
+ INDEX_TYPE step, idx_t &sel_idx) {
135
+ return input;
136
+ }
137
+
138
+ template <>
139
+ list_entry_t SliceValueWithSteps(Vector &result, SelectionVector &sel, list_entry_t input, int64_t begin, int64_t end,
140
+ int64_t step, idx_t &sel_idx) {
141
+ if (end - begin == 0) {
142
+ input.length = 0;
143
+ input.offset = sel_idx;
144
+ return input;
145
+ }
146
+ input.length = CalculateSliceLength(begin, end, step, true);
147
+ idx_t child_idx = input.offset + begin;
148
+ if (step < 0) {
149
+ child_idx = input.offset + end - 1;
150
+ }
151
+ input.offset = sel_idx;
152
+ for (idx_t i = 0; i < input.length; i++) {
153
+ sel.set_index(sel_idx, child_idx);
154
+ child_idx += step;
155
+ sel_idx++;
156
+ }
157
+ return input;
158
+ }
159
+
160
+ template <typename INPUT_TYPE, typename INDEX_TYPE>
161
+ static void ExecuteConstantSlice(Vector &result, Vector &str_vector, Vector &begin_vector, Vector &end_vector,
162
+ optional_ptr<Vector> step_vector, const idx_t count, SelectionVector &sel,
163
+ idx_t &sel_idx, optional_ptr<Vector> result_child_vector, bool begin_is_empty,
164
+ bool end_is_empty) {
165
+ auto result_data = ConstantVector::GetData<INPUT_TYPE>(result);
166
+ auto str_data = ConstantVector::GetData<INPUT_TYPE>(str_vector);
167
+ auto begin_data = ConstantVector::GetData<INDEX_TYPE>(begin_vector);
168
+ auto end_data = ConstantVector::GetData<INDEX_TYPE>(end_vector);
169
+ auto step_data = step_vector ? ConstantVector::GetData<INDEX_TYPE>(*step_vector) : nullptr;
170
+
171
+ auto str = str_data[0];
172
+ auto begin = begin_is_empty ? 0 : begin_data[0];
173
+ auto end = end_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(str) : end_data[0];
174
+ auto step = step_data ? step_data[0] : 1;
175
+
176
+ if (step < 0) {
177
+ swap(begin, end);
178
+ begin = end_is_empty ? 0 : begin;
179
+ end = begin_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(str) : end;
180
+ }
181
+
182
+ auto str_valid = !ConstantVector::IsNull(str_vector);
183
+ auto begin_valid = !ConstantVector::IsNull(begin_vector);
184
+ auto end_valid = !ConstantVector::IsNull(end_vector);
185
+ auto step_valid = step_vector && !ConstantVector::IsNull(*step_vector);
186
+
187
+ // Clamp offsets
188
+ bool clamp_result = false;
189
+ if (str_valid && begin_valid && end_valid && (step_valid || step == 1)) {
190
+ clamp_result = ClampSlice(str, begin, end);
191
+ }
192
+
193
+ auto sel_length = 0;
194
+ if (step_vector && step_valid && str_valid && begin_valid && end_valid && step != 1 && end - begin > 0) {
195
+ sel_length = CalculateSliceLength(begin, end, step, step_valid);
196
+ sel.Initialize(sel_length);
197
+ }
198
+
199
+ // Try to slice
200
+ if (!str_valid || !begin_valid || !end_valid || (step_vector && !step_valid) || !clamp_result) {
201
+ ConstantVector::SetNull(result, true);
202
+ } else if (step == 1) {
203
+ result_data[0] = SliceValue<INPUT_TYPE, INDEX_TYPE>(result, str, begin, end);
95
204
  } else {
96
- UnifiedVectorFormat sdata, bdata, edata;
205
+ result_data[0] = SliceValueWithSteps<INPUT_TYPE, INDEX_TYPE>(result, sel, str, begin, end, step, sel_idx);
206
+ }
207
+
208
+ if (step_vector && step != 0 && end - begin > 0) {
209
+ result_child_vector->Slice(sel, sel_length);
210
+ }
211
+ }
212
+
213
+ template <typename INPUT_TYPE, typename INDEX_TYPE>
214
+ static void ExecuteFlatSlice(Vector &result, Vector &list_vector, Vector &begin_vector, Vector &end_vector,
215
+ optional_ptr<Vector> step_vector, const idx_t count, SelectionVector &sel, idx_t &sel_idx,
216
+ optional_ptr<Vector> result_child_vector, bool begin_is_empty, bool end_is_empty) {
217
+ UnifiedVectorFormat list_data, begin_data, end_data, step_data;
218
+ idx_t sel_length = 0;
97
219
 
98
- s.ToUnifiedFormat(count, sdata);
99
- b.ToUnifiedFormat(count, bdata);
100
- e.ToUnifiedFormat(count, edata);
220
+ list_vector.ToUnifiedFormat(count, list_data);
221
+ begin_vector.ToUnifiedFormat(count, begin_data);
222
+ end_vector.ToUnifiedFormat(count, end_data);
223
+ if (step_vector) {
224
+ step_vector->ToUnifiedFormat(count, step_data);
225
+ sel.Initialize(ListVector::GetListSize(list_vector));
226
+ }
101
227
 
102
- auto rdata = FlatVector::GetData<INPUT_TYPE>(result);
103
- auto &rmask = FlatVector::Validity(result);
228
+ auto result_data = FlatVector::GetData<INPUT_TYPE>(result);
229
+ auto &result_mask = FlatVector::Validity(result);
104
230
 
105
- for (idx_t i = 0; i < count; ++i) {
106
- auto sidx = sdata.sel->get_index(i);
107
- auto bidx = bdata.sel->get_index(i);
108
- auto eidx = edata.sel->get_index(i);
231
+ for (idx_t i = 0; i < count; ++i) {
232
+ auto list_idx = list_data.sel->get_index(i);
233
+ auto begin_idx = begin_data.sel->get_index(i);
234
+ auto end_idx = end_data.sel->get_index(i);
235
+ auto step_idx = step_vector ? step_data.sel->get_index(i) : 0;
109
236
 
110
- auto sliced = (UnifiedVectorFormat::GetData<INPUT_TYPE>(sdata))[sidx];
111
- auto begin = (UnifiedVectorFormat::GetData<INDEX_TYPE>(bdata))[bidx];
112
- auto end = (UnifiedVectorFormat::GetData<INDEX_TYPE>(edata))[eidx];
237
+ auto sliced = reinterpret_cast<INPUT_TYPE *>(list_data.data)[list_idx];
238
+ auto begin = begin_is_empty ? 0 : reinterpret_cast<INDEX_TYPE *>(begin_data.data)[begin_idx];
239
+ auto end = end_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(sliced)
240
+ : reinterpret_cast<INDEX_TYPE *>(end_data.data)[end_idx];
241
+ auto step = step_vector ? reinterpret_cast<INDEX_TYPE *>(step_data.data)[step_idx] : 1;
113
242
 
114
- auto svalid = sdata.validity.RowIsValid(sidx);
115
- auto bvalid = bdata.validity.RowIsValid(bidx);
116
- auto evalid = edata.validity.RowIsValid(eidx);
243
+ if (step < 0) {
244
+ swap(begin, end);
245
+ begin = end_is_empty ? 0 : begin;
246
+ end = begin_is_empty ? ValueLength<INPUT_TYPE, INDEX_TYPE>(sliced) : end;
247
+ }
248
+ auto list_valid = list_data.validity.RowIsValid(list_idx);
249
+ auto begin_valid = begin_data.validity.RowIsValid(begin_idx);
250
+ auto end_valid = end_data.validity.RowIsValid(end_idx);
251
+ auto step_valid = step_vector && step_data.validity.RowIsValid(step_idx);
117
252
 
118
- // Try to slice
119
- if (!svalid || !ClampSlice(sliced, begin, end, bvalid, evalid)) {
120
- rmask.SetInvalid(i);
121
- } else {
122
- rdata[i] = SliceValue<INPUT_TYPE, INDEX_TYPE>(result, sliced, begin, end);
123
- }
253
+ bool clamp_result = false;
254
+ if (list_valid && begin_valid && end_valid && (step_valid || step == 1)) {
255
+ clamp_result = ClampSlice(sliced, begin, end);
124
256
  }
257
+
258
+ auto length = 0;
259
+ if (step_vector && step_valid && list_valid && begin_valid && end_valid && end - begin > 0) {
260
+ length = CalculateSliceLength(begin, end, step, step_valid);
261
+ }
262
+ sel_length += length;
263
+
264
+ if (!list_valid || !begin_valid || !end_valid || (step_vector && !step_valid) || !clamp_result) {
265
+ result_mask.SetInvalid(i);
266
+ } else if (!step_vector) {
267
+ result_data[i] = SliceValue<INPUT_TYPE, INDEX_TYPE>(result, sliced, begin, end);
268
+ } else {
269
+ result_data[i] =
270
+ SliceValueWithSteps<INPUT_TYPE, INDEX_TYPE>(result, sel, sliced, begin, end, step, sel_idx);
271
+ }
272
+ }
273
+ if (step_vector) {
274
+ SelectionVector new_sel(sel_length);
275
+ for (idx_t i = 0; i < sel_length; ++i) {
276
+ new_sel.set_index(i, sel.get_index(i));
277
+ }
278
+ result_child_vector->Slice(new_sel, sel_length);
279
+ }
280
+ }
281
+
282
+ template <typename INPUT_TYPE, typename INDEX_TYPE>
283
+ static void ExecuteSlice(Vector &result, Vector &list_or_str_vector, Vector &begin_vector, Vector &end_vector,
284
+ optional_ptr<Vector> step_vector, const idx_t count, bool begin_is_empty, bool end_is_empty) {
285
+ optional_ptr<Vector> result_child_vector;
286
+ if (step_vector) {
287
+ result_child_vector = &ListVector::GetEntry(result);
125
288
  }
126
289
 
290
+ SelectionVector sel;
291
+ idx_t sel_idx = 0;
292
+
293
+ if (result.GetVectorType() == VectorType::CONSTANT_VECTOR) {
294
+ ExecuteConstantSlice<INPUT_TYPE, INDEX_TYPE>(result, list_or_str_vector, begin_vector, end_vector, step_vector,
295
+ count, sel, sel_idx, result_child_vector, begin_is_empty,
296
+ end_is_empty);
297
+ } else {
298
+ ExecuteFlatSlice<INPUT_TYPE, INDEX_TYPE>(result, list_or_str_vector, begin_vector, end_vector, step_vector,
299
+ count, sel, sel_idx, result_child_vector, begin_is_empty,
300
+ end_is_empty);
301
+ }
127
302
  result.Verify(count);
128
303
  }
129
304
 
130
305
  static void ArraySliceFunction(DataChunk &args, ExpressionState &state, Vector &result) {
131
- D_ASSERT(args.ColumnCount() == 3);
132
- D_ASSERT(args.data.size() == 3);
306
+ D_ASSERT(args.ColumnCount() == 3 || args.ColumnCount() == 4);
307
+ D_ASSERT(args.data.size() == 3 || args.data.size() == 4);
133
308
  auto count = args.size();
134
309
 
135
- Vector &s = args.data[0];
136
- Vector &b = args.data[1];
137
- Vector &e = args.data[2];
310
+ Vector &list_or_str_vector = args.data[0];
311
+ Vector &begin_vector = args.data[1];
312
+ Vector &end_vector = args.data[2];
313
+
314
+ optional_ptr<Vector> step_vector;
315
+ if (args.ColumnCount() == 4) {
316
+ step_vector = &args.data[3];
317
+ }
318
+
319
+ auto &func_expr = state.expr.Cast<BoundFunctionExpression>();
320
+ auto &info = func_expr.bind_info->Cast<ListSliceBindData>();
321
+ auto begin_is_empty = info.begin_is_empty;
322
+ auto end_is_empty = info.end_is_empty;
138
323
 
139
324
  result.SetVectorType(args.AllConstant() ? VectorType::CONSTANT_VECTOR : VectorType::FLAT_VECTOR);
140
325
  switch (result.GetType().id()) {
141
- case LogicalTypeId::LIST:
326
+ case LogicalTypeId::LIST: {
142
327
  // Share the value dictionary as we are just going to slice it
143
- if (s.GetVectorType() != VectorType::FLAT_VECTOR && s.GetVectorType() != VectorType::CONSTANT_VECTOR) {
144
- s.Flatten(count);
328
+ if (list_or_str_vector.GetVectorType() != VectorType::FLAT_VECTOR &&
329
+ list_or_str_vector.GetVectorType() != VectorType::CONSTANT_VECTOR) {
330
+ list_or_str_vector.Flatten(count);
145
331
  }
146
- ListVector::ReferenceEntry(result, s);
147
- ExecuteSlice<list_entry_t, int64_t>(result, s, b, e, count);
332
+ ListVector::ReferenceEntry(result, list_or_str_vector);
333
+ ExecuteSlice<list_entry_t, int64_t>(result, list_or_str_vector, begin_vector, end_vector, step_vector, count,
334
+ begin_is_empty, end_is_empty);
148
335
  break;
149
- case LogicalTypeId::VARCHAR:
150
- ExecuteSlice<string_t, int32_t>(result, s, b, e, count);
336
+ }
337
+ case LogicalTypeId::VARCHAR: {
338
+ ExecuteSlice<string_t, int64_t>(result, list_or_str_vector, begin_vector, end_vector, step_vector, count,
339
+ begin_is_empty, end_is_empty);
151
340
  break;
341
+ }
152
342
  default:
153
343
  throw NotImplementedException("Specifier type not implemented");
154
344
  }
155
345
  }
156
346
 
347
+ static bool CheckIfParamIsEmpty(duckdb::unique_ptr<duckdb::Expression> &param) {
348
+ bool is_empty = false;
349
+ if (param->return_type.id() == LogicalTypeId::LIST) {
350
+ auto empty_list = make_uniq<BoundConstantExpression>(Value::LIST(LogicalType::INTEGER, vector<Value>()));
351
+ is_empty = param->Equals(*empty_list);
352
+ if (!is_empty) {
353
+ // if the param is not empty, the user has entered a list instead of a BIGINT
354
+ throw BinderException("The upper and lower bounds of the slice must be a BIGINT");
355
+ }
356
+ }
357
+ return is_empty;
358
+ }
359
+
157
360
  static unique_ptr<FunctionData> ArraySliceBind(ClientContext &context, ScalarFunction &bound_function,
158
361
  vector<unique_ptr<Expression>> &arguments) {
159
- D_ASSERT(bound_function.arguments.size() == 3);
362
+ D_ASSERT(arguments.size() == 3 || arguments.size() == 4);
363
+ D_ASSERT(bound_function.arguments.size() == 3 || bound_function.arguments.size() == 4);
364
+
160
365
  switch (arguments[0]->return_type.id()) {
161
366
  case LogicalTypeId::LIST:
162
367
  // The result is the same type
163
368
  bound_function.return_type = arguments[0]->return_type;
164
369
  break;
165
370
  case LogicalTypeId::VARCHAR:
166
- // string slice returns a string, but can only accept 32 bit integers
371
+ // string slice returns a string
372
+ if (bound_function.arguments.size() == 4) {
373
+ throw NotImplementedException(
374
+ "Slice with steps has not been implemented for string types, you can consider rewriting your query as "
375
+ "follows:\n SELECT array_to_string((str_split(string, '')[begin:end:step], '');");
376
+ }
167
377
  bound_function.return_type = arguments[0]->return_type;
168
- bound_function.arguments[1] = LogicalType::INTEGER;
169
- bound_function.arguments[2] = LogicalType::INTEGER;
378
+ for (idx_t i = 1; i < 3; i++) {
379
+ if (arguments[i]->return_type.id() != LogicalTypeId::LIST) {
380
+ bound_function.arguments[i] = LogicalType::BIGINT;
381
+ }
382
+ }
170
383
  break;
171
384
  case LogicalTypeId::SQLNULL:
172
385
  case LogicalTypeId::UNKNOWN:
@@ -177,16 +390,29 @@ static unique_ptr<FunctionData> ArraySliceBind(ClientContext &context, ScalarFun
177
390
  throw BinderException("ARRAY_SLICE can only operate on LISTs and VARCHARs");
178
391
  }
179
392
 
180
- return make_uniq<VariableReturnBindData>(bound_function.return_type);
393
+ bool begin_is_empty = CheckIfParamIsEmpty(arguments[1]);
394
+ if (!begin_is_empty) {
395
+ bound_function.arguments[1] = LogicalType::BIGINT;
396
+ }
397
+ bool end_is_empty = CheckIfParamIsEmpty(arguments[2]);
398
+ if (!end_is_empty) {
399
+ bound_function.arguments[2] = LogicalType::BIGINT;
400
+ }
401
+
402
+ return make_uniq<ListSliceBindData>(bound_function.return_type, begin_is_empty, end_is_empty);
181
403
  }
182
404
 
183
- ScalarFunction ListSliceFun::GetFunction() {
405
+ ScalarFunctionSet ListSliceFun::GetFunctions() {
184
406
  // the arguments and return types are actually set in the binder function
185
- ScalarFunction fun({LogicalType::ANY, LogicalType::BIGINT, LogicalType::BIGINT}, LogicalType::ANY,
186
- ArraySliceFunction, ArraySliceBind);
187
- fun.varargs = LogicalType::ANY;
407
+ ScalarFunction fun({LogicalType::ANY, LogicalType::ANY, LogicalType::ANY}, LogicalType::ANY, ArraySliceFunction,
408
+ ArraySliceBind);
188
409
  fun.null_handling = FunctionNullHandling::SPECIAL_HANDLING;
189
- return fun;
410
+
411
+ ScalarFunctionSet set;
412
+ set.AddFunction(fun);
413
+ fun.arguments.push_back(LogicalType::BIGINT);
414
+ set.AddFunction(fun);
415
+ return set;
190
416
  }
191
417
 
192
418
  } // namespace duckdb
@@ -1,8 +1,8 @@
1
1
  #ifndef DUCKDB_VERSION
2
- #define DUCKDB_VERSION "0.8.2-dev2399"
2
+ #define DUCKDB_VERSION "0.8.2-dev2509"
3
3
  #endif
4
4
  #ifndef DUCKDB_SOURCE_ID
5
- #define DUCKDB_SOURCE_ID "20ad35b3fa"
5
+ #define DUCKDB_SOURCE_ID "785b11edd5"
6
6
  #endif
7
7
  #include "duckdb/function/table/system_functions.hpp"
8
8
  #include "duckdb/main/database.hpp"