duckdb 0.8.2-dev3250.0 → 0.8.2-dev3300.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 +1 -1
- package/src/duckdb/extension/parquet/column_reader.cpp +18 -4
- package/src/duckdb/extension/parquet/include/parquet_timestamp.hpp +1 -0
- package/src/duckdb/extension/parquet/include/parquet_writer.hpp +4 -0
- package/src/duckdb/extension/parquet/parquet_extension.cpp +3 -0
- package/src/duckdb/extension/parquet/parquet_statistics.cpp +18 -2
- package/src/duckdb/extension/parquet/parquet_timestamp.cpp +6 -0
- package/src/duckdb/extension/parquet/parquet_writer.cpp +69 -15
- package/src/duckdb/src/common/enum_util.cpp +5 -0
- package/src/duckdb/src/common/operator/cast_operators.cpp +57 -0
- package/src/duckdb/src/common/operator/string_cast.cpp +45 -8
- package/src/duckdb/src/common/types/time.cpp +105 -0
- package/src/duckdb/src/common/types/value.cpp +7 -8
- package/src/duckdb/src/common/types/vector.cpp +1 -1
- package/src/duckdb/src/execution/column_binding_resolver.cpp +7 -0
- package/src/duckdb/src/execution/operator/schema/{physical_create_index.cpp → physical_create_art_index.cpp} +37 -46
- package/src/duckdb/src/execution/physical_plan/plan_create_index.cpp +12 -4
- package/src/duckdb/src/function/cast/string_cast.cpp +2 -1
- package/src/duckdb/src/function/cast/time_casts.cpp +7 -6
- package/src/duckdb/src/function/table/version/pragma_version.cpp +2 -2
- package/src/duckdb/src/include/duckdb/catalog/catalog_entry/index_catalog_entry.hpp +1 -0
- package/src/duckdb/src/include/duckdb/common/enums/index_type.hpp +3 -2
- package/src/duckdb/src/include/duckdb/common/operator/cast_operators.hpp +22 -1
- package/src/duckdb/src/include/duckdb/common/operator/string_cast.hpp +1 -1
- package/src/duckdb/src/include/duckdb/common/types/datetime.hpp +46 -3
- package/src/duckdb/src/include/duckdb/common/types/time.hpp +5 -0
- package/src/duckdb/src/include/duckdb/common/types/value.hpp +2 -1
- package/src/duckdb/src/include/duckdb/execution/operator/schema/{physical_create_index.hpp → physical_create_art_index.hpp} +5 -5
- package/src/duckdb/src/include/duckdb/function/copy_function.hpp +6 -1
- package/src/duckdb/src/include/duckdb/function/udf_function.hpp +2 -1
- package/src/duckdb/src/include/duckdb/parser/parsed_data/create_index_info.hpp +5 -0
- package/src/duckdb/src/include/duckdb/planner/operator/logical_extension_operator.hpp +3 -0
- package/src/duckdb/src/include/duckdb/storage/data_table.hpp +1 -1
- package/src/duckdb/src/main/appender.cpp +3 -1
- package/src/duckdb/src/main/capi/result-c.cpp +3 -1
- package/src/duckdb/src/parser/parsed_data/create_index_info.cpp +14 -0
- package/src/duckdb/src/parser/transform/statement/transform_create_index.cpp +27 -13
- package/src/duckdb/src/planner/binder/statement/bind_export.cpp +29 -4
- package/src/duckdb/src/planner/operator/logical_extension_operator.cpp +15 -0
- package/src/duckdb/src/storage/index.cpp +3 -25
- package/src/duckdb/src/storage/local_storage.cpp +0 -1
- package/src/duckdb/src/storage/serialization/serialize_create_info.cpp +4 -0
- package/src/duckdb/src/storage/storage_info.cpp +1 -1
- package/src/duckdb/ub_src_execution_operator_schema.cpp +1 -1
- package/test/test_all_types.test.ts +1 -1
package/package.json
CHANGED
@@ -507,13 +507,13 @@ idx_t ColumnReader::Read(uint64_t num_values, parquet_filter_t &filter, data_ptr
|
|
507
507
|
// TODO keep this in the state
|
508
508
|
auto read_buf = make_shared<ResizeableBuffer>();
|
509
509
|
|
510
|
-
switch (type
|
511
|
-
case
|
510
|
+
switch (schema.type) {
|
511
|
+
case duckdb_parquet::format::Type::INT32:
|
512
512
|
read_buf->resize(reader.allocator, sizeof(int32_t) * (read_now - null_count));
|
513
513
|
dbp_decoder->GetBatch<int32_t>(read_buf->ptr, read_now - null_count);
|
514
514
|
|
515
515
|
break;
|
516
|
-
case
|
516
|
+
case duckdb_parquet::format::Type::INT64:
|
517
517
|
read_buf->resize(reader.allocator, sizeof(int64_t) * (read_now - null_count));
|
518
518
|
dbp_decoder->GetBatch<int64_t>(read_buf->ptr, read_now - null_count);
|
519
519
|
break;
|
@@ -1389,7 +1389,6 @@ unique_ptr<ColumnReader> ColumnReader::CreateReader(ParquetReader &reader, const
|
|
1389
1389
|
return make_uniq<CallbackColumnReader<int32_t, date_t, ParquetIntToDate>>(reader, type_p, schema_p, file_idx_p,
|
1390
1390
|
max_define, max_repeat);
|
1391
1391
|
case LogicalTypeId::TIME:
|
1392
|
-
case LogicalTypeId::TIME_TZ:
|
1393
1392
|
if (schema_p.__isset.logicalType && schema_p.logicalType.__isset.TIME) {
|
1394
1393
|
if (schema_p.logicalType.TIME.unit.__isset.MILLIS) {
|
1395
1394
|
return make_uniq<CallbackColumnReader<int32_t, dtime_t, ParquetIntToTimeMs>>(
|
@@ -1413,6 +1412,21 @@ unique_ptr<ColumnReader> ColumnReader::CreateReader(ParquetReader &reader, const
|
|
1413
1412
|
break;
|
1414
1413
|
}
|
1415
1414
|
}
|
1415
|
+
case LogicalTypeId::TIME_TZ:
|
1416
|
+
if (schema_p.__isset.logicalType && schema_p.logicalType.__isset.TIME) {
|
1417
|
+
if (schema_p.logicalType.TIME.unit.__isset.MICROS) {
|
1418
|
+
return make_uniq<CallbackColumnReader<int64_t, dtime_tz_t, ParquetIntToTimeTZ>>(
|
1419
|
+
reader, type_p, schema_p, file_idx_p, max_define, max_repeat);
|
1420
|
+
}
|
1421
|
+
} else if (schema_p.__isset.converted_type) {
|
1422
|
+
switch (schema_p.converted_type) {
|
1423
|
+
case ConvertedType::TIME_MICROS:
|
1424
|
+
return make_uniq<CallbackColumnReader<int64_t, dtime_tz_t, ParquetIntToTimeTZ>>(
|
1425
|
+
reader, type_p, schema_p, file_idx_p, max_define, max_repeat);
|
1426
|
+
default:
|
1427
|
+
break;
|
1428
|
+
}
|
1429
|
+
}
|
1416
1430
|
case LogicalTypeId::BLOB:
|
1417
1431
|
case LogicalTypeId::VARCHAR:
|
1418
1432
|
return make_uniq<StringColumnReader>(reader, type_p, schema_p, file_idx_p, max_define, max_repeat);
|
@@ -25,5 +25,6 @@ date_t ParquetIntToDate(const int32_t &raw_date);
|
|
25
25
|
dtime_t ParquetIntToTimeMs(const int32_t &raw_time);
|
26
26
|
dtime_t ParquetIntToTime(const int64_t &raw_time);
|
27
27
|
dtime_t ParquetIntToTimeNs(const int64_t &raw_time);
|
28
|
+
dtime_tz_t ParquetIntToTimeTZ(const int64_t &raw_time);
|
28
29
|
|
29
30
|
} // namespace duckdb
|
@@ -75,7 +75,11 @@ public:
|
|
75
75
|
return *writer;
|
76
76
|
}
|
77
77
|
|
78
|
+
static bool TypeIsSupported(const LogicalType &type);
|
79
|
+
|
78
80
|
private:
|
81
|
+
static bool DuckDBTypeToParquetTypeInternal(const LogicalType &duckdb_type,
|
82
|
+
duckdb_parquet::format::Type::type &type);
|
79
83
|
string file_name;
|
80
84
|
vector<LogicalType> sql_types;
|
81
85
|
vector<string> column_names;
|
@@ -37,6 +37,7 @@
|
|
37
37
|
#include "duckdb/storage/table/row_group.hpp"
|
38
38
|
#include "duckdb/common/serializer/format_serializer.hpp"
|
39
39
|
#include "duckdb/common/serializer/format_deserializer.hpp"
|
40
|
+
|
40
41
|
#endif
|
41
42
|
|
42
43
|
namespace duckdb {
|
@@ -826,6 +827,7 @@ unique_ptr<FunctionData> ParquetWriteBind(ClientContext &context, CopyInfo &info
|
|
826
827
|
if (!row_group_size_bytes_set) {
|
827
828
|
bind_data->row_group_size_bytes = bind_data->row_group_size * ParquetWriteBindData::BYTES_PER_ROW;
|
828
829
|
}
|
830
|
+
|
829
831
|
bind_data->sql_types = sql_types;
|
830
832
|
bind_data->column_names = names;
|
831
833
|
return std::move(bind_data);
|
@@ -1003,6 +1005,7 @@ void ParquetExtension::Load(DuckDB &db) {
|
|
1003
1005
|
function.desired_batch_size = ParquetWriteDesiredBatchSize;
|
1004
1006
|
function.serialize = ParquetCopySerialize;
|
1005
1007
|
function.deserialize = ParquetCopyDeserialize;
|
1008
|
+
function.supports_type = ParquetWriter::TypeIsSupported;
|
1006
1009
|
|
1007
1010
|
function.extension = "parquet";
|
1008
1011
|
ExtensionUtil::RegisterFunction(db_instance, function);
|
@@ -154,8 +154,7 @@ Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type,
|
|
154
154
|
throw InternalException("Incorrect stats size for type DATE");
|
155
155
|
}
|
156
156
|
return Value::DATE(date_t(Load<int32_t>(stats_data)));
|
157
|
-
case LogicalTypeId::TIME:
|
158
|
-
case LogicalTypeId::TIME_TZ: {
|
157
|
+
case LogicalTypeId::TIME: {
|
159
158
|
int64_t val;
|
160
159
|
if (stats.size() == sizeof(int32_t)) {
|
161
160
|
val = Load<int32_t>(stats_data);
|
@@ -182,6 +181,23 @@ Value ParquetStatisticsUtils::ConvertValue(const LogicalType &type,
|
|
182
181
|
return Value::TIME(dtime_t(val));
|
183
182
|
}
|
184
183
|
}
|
184
|
+
case LogicalTypeId::TIME_TZ: {
|
185
|
+
int64_t val;
|
186
|
+
if (stats.size() == sizeof(int64_t)) {
|
187
|
+
val = Load<int64_t>(stats_data);
|
188
|
+
} else {
|
189
|
+
throw InternalException("Incorrect stats size for type TIMETZ");
|
190
|
+
}
|
191
|
+
if (schema_ele.__isset.logicalType && schema_ele.logicalType.__isset.TIME) {
|
192
|
+
// logical type
|
193
|
+
if (schema_ele.logicalType.TIME.unit.__isset.MICROS) {
|
194
|
+
return Value::TIMETZ(ParquetIntToTimeTZ(val));
|
195
|
+
} else {
|
196
|
+
throw InternalException("Time With Time Zone logicalType is set but unit is not defined");
|
197
|
+
}
|
198
|
+
}
|
199
|
+
return Value::TIMETZ(ParquetIntToTimeTZ(val));
|
200
|
+
}
|
185
201
|
case LogicalTypeId::TIMESTAMP:
|
186
202
|
case LogicalTypeId::TIMESTAMP_TZ: {
|
187
203
|
if (schema_ele.type == Type::INT96) {
|
@@ -66,4 +66,10 @@ dtime_t ParquetIntToTimeNs(const int64_t &raw_time) {
|
|
66
66
|
return Time::FromTimeNs(raw_time);
|
67
67
|
}
|
68
68
|
|
69
|
+
dtime_tz_t ParquetIntToTimeTZ(const int64_t &raw_time) {
|
70
|
+
dtime_tz_t result;
|
71
|
+
result.bits = raw_time;
|
72
|
+
return result;
|
73
|
+
}
|
74
|
+
|
69
75
|
} // namespace duckdb
|
@@ -76,27 +76,32 @@ private:
|
|
76
76
|
Serializer &serializer;
|
77
77
|
};
|
78
78
|
|
79
|
-
|
79
|
+
bool ParquetWriter::DuckDBTypeToParquetTypeInternal(const LogicalType &duckdb_type, Type::type &parquet_type) {
|
80
80
|
switch (duckdb_type.id()) {
|
81
81
|
case LogicalTypeId::BOOLEAN:
|
82
|
-
|
82
|
+
parquet_type = Type::BOOLEAN;
|
83
|
+
break;
|
83
84
|
case LogicalTypeId::TINYINT:
|
84
85
|
case LogicalTypeId::SMALLINT:
|
85
86
|
case LogicalTypeId::INTEGER:
|
86
87
|
case LogicalTypeId::DATE:
|
87
|
-
|
88
|
+
parquet_type = Type::INT32;
|
89
|
+
break;
|
88
90
|
case LogicalTypeId::BIGINT:
|
89
|
-
|
91
|
+
parquet_type = Type::INT64;
|
92
|
+
break;
|
90
93
|
case LogicalTypeId::FLOAT:
|
91
|
-
|
94
|
+
parquet_type = Type::FLOAT;
|
95
|
+
break;
|
92
96
|
case LogicalTypeId::DOUBLE:
|
93
97
|
case LogicalTypeId::HUGEINT:
|
94
|
-
|
98
|
+
parquet_type = Type::DOUBLE;
|
99
|
+
break;
|
95
100
|
case LogicalTypeId::ENUM:
|
96
101
|
case LogicalTypeId::BLOB:
|
97
102
|
case LogicalTypeId::VARCHAR:
|
98
|
-
|
99
|
-
|
103
|
+
parquet_type = Type::BYTE_ARRAY;
|
104
|
+
break;
|
100
105
|
case LogicalTypeId::TIME:
|
101
106
|
case LogicalTypeId::TIME_TZ:
|
102
107
|
case LogicalTypeId::TIMESTAMP:
|
@@ -104,31 +109,80 @@ Type::type ParquetWriter::DuckDBTypeToParquetType(const LogicalType &duckdb_type
|
|
104
109
|
case LogicalTypeId::TIMESTAMP_MS:
|
105
110
|
case LogicalTypeId::TIMESTAMP_NS:
|
106
111
|
case LogicalTypeId::TIMESTAMP_SEC:
|
107
|
-
|
112
|
+
parquet_type = Type::INT64;
|
113
|
+
break;
|
108
114
|
case LogicalTypeId::UTINYINT:
|
109
115
|
case LogicalTypeId::USMALLINT:
|
110
116
|
case LogicalTypeId::UINTEGER:
|
111
|
-
|
117
|
+
parquet_type = Type::INT32;
|
118
|
+
break;
|
112
119
|
case LogicalTypeId::UBIGINT:
|
113
|
-
|
120
|
+
parquet_type = Type::INT64;
|
121
|
+
break;
|
114
122
|
case LogicalTypeId::INTERVAL:
|
115
123
|
case LogicalTypeId::UUID:
|
116
|
-
|
124
|
+
parquet_type = Type::FIXED_LEN_BYTE_ARRAY;
|
125
|
+
break;
|
117
126
|
case LogicalTypeId::DECIMAL:
|
118
127
|
switch (duckdb_type.InternalType()) {
|
119
128
|
case PhysicalType::INT16:
|
120
129
|
case PhysicalType::INT32:
|
121
|
-
|
130
|
+
parquet_type = Type::INT32;
|
131
|
+
break;
|
122
132
|
case PhysicalType::INT64:
|
123
|
-
|
133
|
+
parquet_type = Type::INT64;
|
134
|
+
break;
|
124
135
|
case PhysicalType::INT128:
|
125
|
-
|
136
|
+
parquet_type = Type::FIXED_LEN_BYTE_ARRAY;
|
137
|
+
break;
|
126
138
|
default:
|
127
139
|
throw InternalException("Unsupported internal decimal type");
|
128
140
|
}
|
141
|
+
break;
|
129
142
|
default:
|
143
|
+
// Anything that is not supported returns false
|
144
|
+
return false;
|
145
|
+
}
|
146
|
+
return true;
|
147
|
+
}
|
148
|
+
|
149
|
+
Type::type ParquetWriter::DuckDBTypeToParquetType(const LogicalType &duckdb_type) {
|
150
|
+
Type::type result;
|
151
|
+
if (!DuckDBTypeToParquetTypeInternal(duckdb_type, result)) {
|
130
152
|
throw NotImplementedException("Unimplemented type for Parquet \"%s\"", duckdb_type.ToString());
|
131
153
|
}
|
154
|
+
return result;
|
155
|
+
}
|
156
|
+
|
157
|
+
bool ParquetWriter::TypeIsSupported(const LogicalType &type) {
|
158
|
+
Type::type unused;
|
159
|
+
auto id = type.id();
|
160
|
+
if (id == LogicalTypeId::LIST) {
|
161
|
+
auto &child_type = ListType::GetChildType(type);
|
162
|
+
return TypeIsSupported(child_type);
|
163
|
+
}
|
164
|
+
if (id == LogicalTypeId::STRUCT) {
|
165
|
+
auto &children = StructType::GetChildTypes(type);
|
166
|
+
for (auto &child : children) {
|
167
|
+
auto &child_type = child.second;
|
168
|
+
if (!TypeIsSupported(child_type)) {
|
169
|
+
return false;
|
170
|
+
}
|
171
|
+
}
|
172
|
+
return true;
|
173
|
+
}
|
174
|
+
if (id == LogicalTypeId::MAP) {
|
175
|
+
auto &key_type = MapType::KeyType(type);
|
176
|
+
auto &value_type = MapType::ValueType(type);
|
177
|
+
if (!TypeIsSupported(key_type)) {
|
178
|
+
return false;
|
179
|
+
}
|
180
|
+
if (!TypeIsSupported(value_type)) {
|
181
|
+
return false;
|
182
|
+
}
|
183
|
+
return true;
|
184
|
+
}
|
185
|
+
return DuckDBTypeToParquetTypeInternal(type, unused);
|
132
186
|
}
|
133
187
|
|
134
188
|
void ParquetWriter::SetSchemaProperties(const LogicalType &duckdb_type,
|
@@ -2345,6 +2345,8 @@ const char* EnumUtil::ToChars<IndexType>(IndexType value) {
|
|
2345
2345
|
return "INVALID";
|
2346
2346
|
case IndexType::ART:
|
2347
2347
|
return "ART";
|
2348
|
+
case IndexType::EXTENSION:
|
2349
|
+
return "EXTENSION";
|
2348
2350
|
default:
|
2349
2351
|
throw NotImplementedException(StringUtil::Format("Enum value: '%d' not implemented", value));
|
2350
2352
|
}
|
@@ -2358,6 +2360,9 @@ IndexType EnumUtil::FromString<IndexType>(const char *value) {
|
|
2358
2360
|
if (StringUtil::Equals(value, "ART")) {
|
2359
2361
|
return IndexType::ART;
|
2360
2362
|
}
|
2363
|
+
if (StringUtil::Equals(value, "EXTENSION")) {
|
2364
|
+
return IndexType::EXTENSION;
|
2365
|
+
}
|
2361
2366
|
throw NotImplementedException(StringUtil::Format("Enum value: '%s' not implemented", value));
|
2362
2367
|
}
|
2363
2368
|
|
@@ -1272,6 +1272,27 @@ bool TryCast::Operation(dtime_t input, dtime_t &result, bool strict) {
|
|
1272
1272
|
return true;
|
1273
1273
|
}
|
1274
1274
|
|
1275
|
+
template <>
|
1276
|
+
bool TryCast::Operation(dtime_t input, dtime_tz_t &result, bool strict) {
|
1277
|
+
result = dtime_tz_t(input, 0);
|
1278
|
+
return true;
|
1279
|
+
}
|
1280
|
+
|
1281
|
+
//===--------------------------------------------------------------------===//
|
1282
|
+
// Cast From Time With Time Zone (Offset)
|
1283
|
+
//===--------------------------------------------------------------------===//
|
1284
|
+
template <>
|
1285
|
+
bool TryCast::Operation(dtime_tz_t input, dtime_tz_t &result, bool strict) {
|
1286
|
+
result = input;
|
1287
|
+
return true;
|
1288
|
+
}
|
1289
|
+
|
1290
|
+
template <>
|
1291
|
+
bool TryCast::Operation(dtime_tz_t input, dtime_t &result, bool strict) {
|
1292
|
+
result = input.time();
|
1293
|
+
return true;
|
1294
|
+
}
|
1295
|
+
|
1275
1296
|
//===--------------------------------------------------------------------===//
|
1276
1297
|
// Cast From Timestamps
|
1277
1298
|
//===--------------------------------------------------------------------===//
|
@@ -1296,6 +1317,15 @@ bool TryCast::Operation(timestamp_t input, timestamp_t &result, bool strict) {
|
|
1296
1317
|
return true;
|
1297
1318
|
}
|
1298
1319
|
|
1320
|
+
template <>
|
1321
|
+
bool TryCast::Operation(timestamp_t input, dtime_tz_t &result, bool strict) {
|
1322
|
+
if (!Timestamp::IsFinite(input)) {
|
1323
|
+
return false;
|
1324
|
+
}
|
1325
|
+
result = dtime_tz_t(Timestamp::GetTime(input), 0);
|
1326
|
+
return true;
|
1327
|
+
}
|
1328
|
+
|
1299
1329
|
//===--------------------------------------------------------------------===//
|
1300
1330
|
// Cast from Interval
|
1301
1331
|
//===--------------------------------------------------------------------===//
|
@@ -1583,6 +1613,33 @@ dtime_t Cast::Operation(string_t input) {
|
|
1583
1613
|
return Time::FromCString(input.GetData(), input.GetSize());
|
1584
1614
|
}
|
1585
1615
|
|
1616
|
+
//===--------------------------------------------------------------------===//
|
1617
|
+
// Cast To TimeTZ
|
1618
|
+
//===--------------------------------------------------------------------===//
|
1619
|
+
template <>
|
1620
|
+
bool TryCastErrorMessage::Operation(string_t input, dtime_tz_t &result, string *error_message, bool strict) {
|
1621
|
+
if (!TryCast::Operation<string_t, dtime_tz_t>(input, result, strict)) {
|
1622
|
+
HandleCastError::AssignError(Time::ConversionError(input), error_message);
|
1623
|
+
return false;
|
1624
|
+
}
|
1625
|
+
return true;
|
1626
|
+
}
|
1627
|
+
|
1628
|
+
template <>
|
1629
|
+
bool TryCast::Operation(string_t input, dtime_tz_t &result, bool strict) {
|
1630
|
+
idx_t pos;
|
1631
|
+
return Time::TryConvertTimeTZ(input.GetData(), input.GetSize(), pos, result, strict);
|
1632
|
+
}
|
1633
|
+
|
1634
|
+
template <>
|
1635
|
+
dtime_tz_t Cast::Operation(string_t input) {
|
1636
|
+
dtime_tz_t result;
|
1637
|
+
if (!TryCast::Operation(input, result, false)) {
|
1638
|
+
throw ConversionException(Time::ConversionError(input));
|
1639
|
+
}
|
1640
|
+
return result;
|
1641
|
+
}
|
1642
|
+
|
1586
1643
|
//===--------------------------------------------------------------------===//
|
1587
1644
|
// Cast To Timestamp
|
1588
1645
|
//===--------------------------------------------------------------------===//
|
@@ -161,24 +161,61 @@ duckdb::string_t StringCast::Operation(duckdb::string_t input, Vector &result) {
|
|
161
161
|
}
|
162
162
|
|
163
163
|
template <>
|
164
|
-
string_t StringCastTZ::Operation(
|
164
|
+
string_t StringCastTZ::Operation(dtime_tz_t input, Vector &vector) {
|
165
165
|
int32_t time[4];
|
166
|
-
Time::Convert(input, time[0], time[1], time[2], time[3]);
|
166
|
+
Time::Convert(input.time(), time[0], time[1], time[2], time[3]);
|
167
167
|
|
168
|
-
// format for timetz is TIME+00
|
169
168
|
char micro_buffer[10];
|
170
169
|
const auto time_length = TimeToStringCast::Length(time, micro_buffer);
|
171
|
-
|
170
|
+
idx_t length = time_length;
|
171
|
+
|
172
|
+
const auto offset = input.offset();
|
173
|
+
const bool negative = (offset < 0);
|
174
|
+
++length;
|
175
|
+
|
176
|
+
auto ss = std::abs(offset);
|
177
|
+
const auto hh = ss / Interval::SECS_PER_HOUR;
|
178
|
+
|
179
|
+
const auto hh_length = (hh < 100) ? 2 : NumericHelper::UnsignedLength(uint32_t(hh));
|
180
|
+
length += hh_length;
|
181
|
+
|
182
|
+
ss %= Interval::SECS_PER_HOUR;
|
183
|
+
const auto mm = ss / Interval::SECS_PER_MINUTE;
|
184
|
+
if (mm) {
|
185
|
+
length += 3;
|
186
|
+
}
|
187
|
+
|
188
|
+
ss %= Interval::SECS_PER_MINUTE;
|
189
|
+
if (ss) {
|
190
|
+
length += 3;
|
191
|
+
}
|
172
192
|
|
173
193
|
string_t result = StringVector::EmptyString(vector, length);
|
174
194
|
auto data = result.GetDataWriteable();
|
175
195
|
|
176
196
|
idx_t pos = 0;
|
177
|
-
TimeToStringCast::Format(data + pos,
|
197
|
+
TimeToStringCast::Format(data + pos, time_length, time, micro_buffer);
|
178
198
|
pos += time_length;
|
179
|
-
|
180
|
-
data[pos++] = '
|
181
|
-
|
199
|
+
|
200
|
+
data[pos++] = negative ? '-' : '+';
|
201
|
+
if (hh < 100) {
|
202
|
+
TimeToStringCast::FormatTwoDigits(data + pos, hh);
|
203
|
+
} else {
|
204
|
+
NumericHelper::FormatUnsigned(hh, data + pos + hh_length);
|
205
|
+
}
|
206
|
+
pos += hh_length;
|
207
|
+
|
208
|
+
if (mm) {
|
209
|
+
data[pos++] = ':';
|
210
|
+
TimeToStringCast::FormatTwoDigits(data + pos, mm);
|
211
|
+
pos += 2;
|
212
|
+
}
|
213
|
+
|
214
|
+
if (ss) {
|
215
|
+
data[pos++] = ':';
|
216
|
+
TimeToStringCast::FormatTwoDigits(data + pos, ss);
|
217
|
+
pos += 2;
|
218
|
+
}
|
182
219
|
|
183
220
|
result.Finalize();
|
184
221
|
return result;
|
@@ -129,6 +129,111 @@ bool Time::TryConvertTime(const char *buf, idx_t len, idx_t &pos, dtime_t &resul
|
|
129
129
|
return true;
|
130
130
|
}
|
131
131
|
|
132
|
+
bool Time::TryParseUTCOffset(const char *str, idx_t &pos, idx_t len, int32_t &offset) {
|
133
|
+
offset = 0;
|
134
|
+
if (pos == len || StringUtil::CharacterIsSpace(str[pos])) {
|
135
|
+
return true;
|
136
|
+
}
|
137
|
+
|
138
|
+
idx_t curpos = pos;
|
139
|
+
// Minimum of 3 characters
|
140
|
+
if (curpos + 3 > len) {
|
141
|
+
// no characters left to parse
|
142
|
+
return false;
|
143
|
+
}
|
144
|
+
|
145
|
+
const auto sign_char = str[curpos];
|
146
|
+
if (sign_char != '+' && sign_char != '-') {
|
147
|
+
// expected either + or -
|
148
|
+
return false;
|
149
|
+
}
|
150
|
+
curpos++;
|
151
|
+
|
152
|
+
int32_t hh = 0;
|
153
|
+
idx_t start = curpos;
|
154
|
+
for (; curpos < len; ++curpos) {
|
155
|
+
const auto c = str[curpos];
|
156
|
+
if (!StringUtil::CharacterIsDigit(c)) {
|
157
|
+
break;
|
158
|
+
}
|
159
|
+
hh = hh * 10 + (c - '0');
|
160
|
+
}
|
161
|
+
// HH is in [-1559,+1559] and must be at least two digits
|
162
|
+
if (curpos - start < 2 || hh > 1559) {
|
163
|
+
return false;
|
164
|
+
}
|
165
|
+
|
166
|
+
// optional minute specifier: expected ":MM"
|
167
|
+
int32_t mm = 0;
|
168
|
+
if (curpos + 3 <= len && str[curpos] == ':') {
|
169
|
+
++curpos;
|
170
|
+
if (!Date::ParseDoubleDigit(str, len, curpos, mm) || mm >= Interval::MINS_PER_HOUR) {
|
171
|
+
return false;
|
172
|
+
}
|
173
|
+
}
|
174
|
+
|
175
|
+
// optional seconds specifier: expected ":SS"
|
176
|
+
int32_t ss = 0;
|
177
|
+
if (curpos + 3 <= len && str[curpos] == ':') {
|
178
|
+
++curpos;
|
179
|
+
if (!Date::ParseDoubleDigit(str, len, curpos, ss) || ss >= Interval::SECS_PER_MINUTE) {
|
180
|
+
return false;
|
181
|
+
}
|
182
|
+
}
|
183
|
+
|
184
|
+
// Assemble the offset now that we know nothing went wrong
|
185
|
+
offset += hh * Interval::SECS_PER_HOUR;
|
186
|
+
offset += mm * Interval::SECS_PER_MINUTE;
|
187
|
+
offset += ss;
|
188
|
+
if (sign_char == '-') {
|
189
|
+
offset = -offset;
|
190
|
+
}
|
191
|
+
|
192
|
+
pos = curpos;
|
193
|
+
|
194
|
+
return true;
|
195
|
+
}
|
196
|
+
|
197
|
+
bool Time::TryConvertTimeTZ(const char *buf, idx_t len, idx_t &pos, dtime_tz_t &result, bool strict) {
|
198
|
+
dtime_t time_part;
|
199
|
+
if (!Time::TryConvertInternal(buf, len, pos, time_part, false)) {
|
200
|
+
if (!strict) {
|
201
|
+
// last chance, check if we can parse as timestamp
|
202
|
+
timestamp_t timestamp;
|
203
|
+
if (Timestamp::TryConvertTimestamp(buf, len, timestamp) == TimestampCastResult::SUCCESS) {
|
204
|
+
if (!Timestamp::IsFinite(timestamp)) {
|
205
|
+
return false;
|
206
|
+
}
|
207
|
+
result = dtime_tz_t(Timestamp::GetTime(timestamp), 0);
|
208
|
+
return true;
|
209
|
+
}
|
210
|
+
}
|
211
|
+
return false;
|
212
|
+
}
|
213
|
+
|
214
|
+
// We can't use Timestamp::TryParseUTCOffset because the colon is optional there but required here.
|
215
|
+
int32_t offset = 0;
|
216
|
+
if (!TryParseUTCOffset(buf, pos, len, offset)) {
|
217
|
+
return false;
|
218
|
+
}
|
219
|
+
|
220
|
+
// in strict mode, check remaining string for non-space characters
|
221
|
+
if (strict) {
|
222
|
+
// skip trailing spaces
|
223
|
+
while (pos < len && StringUtil::CharacterIsSpace(buf[pos])) {
|
224
|
+
pos++;
|
225
|
+
}
|
226
|
+
// check position. if end was not reached, non-space chars remaining
|
227
|
+
if (pos < len) {
|
228
|
+
return false;
|
229
|
+
}
|
230
|
+
}
|
231
|
+
|
232
|
+
result = dtime_tz_t(time_part, offset);
|
233
|
+
|
234
|
+
return true;
|
235
|
+
}
|
236
|
+
|
132
237
|
string Time::ConversionError(const string &str) {
|
133
238
|
return StringUtil::Format("time field value out of range: \"%s\", "
|
134
239
|
"expected format is ([YYYY-MM-DD ]HH:MM:SS[.MS])",
|
@@ -231,7 +231,7 @@ Value Value::MinimumValue(const LogicalType &type) {
|
|
231
231
|
case LogicalTypeId::TIMESTAMP_NS:
|
232
232
|
return Value::TIMESTAMPNS(timestamp_t(NumericLimits<int64_t>::Minimum()));
|
233
233
|
case LogicalTypeId::TIME_TZ:
|
234
|
-
return Value::TIMETZ(dtime_t(0));
|
234
|
+
return Value::TIMETZ(dtime_tz_t(dtime_t(0), dtime_tz_t::MIN_OFFSET));
|
235
235
|
case LogicalTypeId::TIMESTAMP_TZ:
|
236
236
|
return Value::TIMESTAMPTZ(Timestamp::FromDatetime(
|
237
237
|
Date::FromDate(Timestamp::MIN_YEAR, Timestamp::MIN_MONTH, Timestamp::MIN_DAY), dtime_t(0)));
|
@@ -300,7 +300,8 @@ Value Value::MaximumValue(const LogicalType &type) {
|
|
300
300
|
case LogicalTypeId::TIMESTAMP_SEC:
|
301
301
|
return MaximumValue(LogicalType::TIMESTAMP).DefaultCastAs(LogicalType::TIMESTAMP_S);
|
302
302
|
case LogicalTypeId::TIME_TZ:
|
303
|
-
return Value::TIMETZ(
|
303
|
+
return Value::TIMETZ(
|
304
|
+
dtime_tz_t(dtime_t(Interval::SECS_PER_DAY * Interval::MICROS_PER_SEC - 1), dtime_tz_t::MAX_OFFSET));
|
304
305
|
case LogicalTypeId::TIMESTAMP_TZ:
|
305
306
|
return MaximumValue(LogicalType::TIMESTAMP);
|
306
307
|
case LogicalTypeId::FLOAT:
|
@@ -587,9 +588,9 @@ Value Value::TIME(dtime_t value) {
|
|
587
588
|
return result;
|
588
589
|
}
|
589
590
|
|
590
|
-
Value Value::TIMETZ(
|
591
|
+
Value Value::TIMETZ(dtime_tz_t value) {
|
591
592
|
Value result(LogicalType::TIME_TZ);
|
592
|
-
result.value_.
|
593
|
+
result.value_.timetz = value;
|
593
594
|
result.is_null = false;
|
594
595
|
return result;
|
595
596
|
}
|
@@ -955,8 +956,9 @@ T Value::GetValueInternal() const {
|
|
955
956
|
case LogicalTypeId::DATE:
|
956
957
|
return Cast::Operation<date_t, T>(value_.date);
|
957
958
|
case LogicalTypeId::TIME:
|
958
|
-
case LogicalTypeId::TIME_TZ:
|
959
959
|
return Cast::Operation<dtime_t, T>(value_.time);
|
960
|
+
case LogicalTypeId::TIME_TZ:
|
961
|
+
return Cast::Operation<dtime_tz_t, T>(value_.timetz);
|
960
962
|
case LogicalTypeId::TIMESTAMP:
|
961
963
|
case LogicalTypeId::TIMESTAMP_TZ:
|
962
964
|
return Cast::Operation<timestamp_t, T>(value_.timestamp);
|
@@ -1028,7 +1030,6 @@ int64_t Value::GetValue() const {
|
|
1028
1030
|
case LogicalTypeId::TIMESTAMP_NS:
|
1029
1031
|
case LogicalTypeId::TIMESTAMP_MS:
|
1030
1032
|
case LogicalTypeId::TIME:
|
1031
|
-
case LogicalTypeId::TIME_TZ:
|
1032
1033
|
case LogicalTypeId::TIMESTAMP_TZ:
|
1033
1034
|
return value_.bigint;
|
1034
1035
|
default:
|
@@ -1146,8 +1147,6 @@ Value Value::Numeric(const LogicalType &type, int64_t value) {
|
|
1146
1147
|
return Value::TIMESTAMPMS(timestamp_t(value));
|
1147
1148
|
case LogicalTypeId::TIMESTAMP_SEC:
|
1148
1149
|
return Value::TIMESTAMPSEC(timestamp_t(value));
|
1149
|
-
case LogicalTypeId::TIME_TZ:
|
1150
|
-
return Value::TIMETZ(dtime_t(value));
|
1151
1150
|
case LogicalTypeId::TIMESTAMP_TZ:
|
1152
1151
|
return Value::TIMESTAMPTZ(timestamp_t(value));
|
1153
1152
|
case LogicalTypeId::ENUM:
|
@@ -477,7 +477,7 @@ Value Vector::GetValueInternal(const Vector &v_p, idx_t index_p) {
|
|
477
477
|
case LogicalTypeId::TIME:
|
478
478
|
return Value::TIME(reinterpret_cast<dtime_t *>(data)[index]);
|
479
479
|
case LogicalTypeId::TIME_TZ:
|
480
|
-
return Value::TIMETZ(reinterpret_cast<
|
480
|
+
return Value::TIMETZ(reinterpret_cast<dtime_tz_t *>(data)[index]);
|
481
481
|
case LogicalTypeId::BIGINT:
|
482
482
|
return Value::BIGINT(reinterpret_cast<int64_t *>(data)[index]);
|
483
483
|
case LogicalTypeId::UTINYINT:
|
@@ -4,6 +4,7 @@
|
|
4
4
|
#include "duckdb/planner/operator/logical_any_join.hpp"
|
5
5
|
#include "duckdb/planner/operator/logical_create_index.hpp"
|
6
6
|
#include "duckdb/planner/operator/logical_insert.hpp"
|
7
|
+
#include "duckdb/planner/operator/logical_extension_operator.hpp"
|
7
8
|
|
8
9
|
#include "duckdb/planner/expression/bound_columnref_expression.hpp"
|
9
10
|
#include "duckdb/planner/expression/bound_reference_expression.hpp"
|
@@ -91,6 +92,12 @@ void ColumnBindingResolver::VisitOperator(LogicalOperator &op) {
|
|
91
92
|
bindings = op.GetColumnBindings();
|
92
93
|
return;
|
93
94
|
}
|
95
|
+
break;
|
96
|
+
}
|
97
|
+
case LogicalOperatorType::LOGICAL_EXTENSION_OPERATOR: {
|
98
|
+
auto &ext_op = op.Cast<LogicalExtensionOperator>();
|
99
|
+
ext_op.ResolveColumnBindings(*this, bindings);
|
100
|
+
return;
|
94
101
|
}
|
95
102
|
default:
|
96
103
|
break;
|