|
12 | 12 | #include "duckdb/main/client_context.hpp"
|
13 | 13 | #include "duckdb/main/config.hpp"
|
14 | 14 | #include "duckdb/storage/storage_extension.hpp"
|
15 |
| - |
| 15 | +#include "duckdb/common/operator/cast_operators.hpp" |
16 | 16 | #include <cmath>
|
17 | 17 |
|
18 | 18 | namespace duckdb {
|
@@ -204,6 +204,15 @@ static unique_ptr<GlobalTableFunctionState> SqliteInitGlobalState(ClientContext
|
204 | 204 | return std::move(result);
|
205 | 205 | }
|
206 | 206 |
|
| 207 | +static timestamp_t ConvertTimestampInteger(sqlite3_value *val) { |
| 208 | + return Timestamp::FromEpochSeconds(sqlite3_value_int64(val)); |
| 209 | +} |
| 210 | + |
| 211 | +static timestamp_t ConvertTimestampFloat(sqlite3_value *val) { |
| 212 | + int64_t timestamp_micros = Cast::Operation<double, int64_t>(sqlite3_value_double(val) * 1000000.0); |
| 213 | + return Timestamp::FromEpochMicroSeconds(timestamp_micros); |
| 214 | +} |
| 215 | + |
207 | 216 | static void SqliteScan(ClientContext &context, TableFunctionInput &data, DataChunk &output) {
|
208 | 217 | auto &state = data.local_state->Cast<SqliteLocalState>();
|
209 | 218 | auto &gstate = data.global_state->Cast<SqliteGlobalState>();
|
@@ -255,14 +264,43 @@ static void SqliteScan(ClientContext &context, TableFunctionInput &data, DataChu
|
255 | 264 | out_vec, (const char *)sqlite3_value_text(val), sqlite3_value_bytes(val));
|
256 | 265 | break;
|
257 | 266 | case LogicalTypeId::DATE:
|
258 |
| - stmt.CheckTypeMatches(bind_data, val, sqlite_column_type, SQLITE_TEXT, col_idx); |
259 |
| - FlatVector::GetData<date_t>(out_vec)[out_idx] = |
260 |
| - Date::FromCString((const char *)sqlite3_value_text(val), sqlite3_value_bytes(val)); |
| 267 | + if (sqlite_column_type == SQLITE_INTEGER) { |
| 268 | + // unix timestamp |
| 269 | + FlatVector::GetData<date_t>(out_vec)[out_idx] = |
| 270 | + Timestamp::GetDate(ConvertTimestampInteger(val)); |
| 271 | + } else if (sqlite_column_type == SQLITE_FLOAT) { |
| 272 | + FlatVector::GetData<date_t>(out_vec)[out_idx] = Timestamp::GetDate(ConvertTimestampFloat(val)); |
| 273 | + } else if (sqlite_column_type == SQLITE_TEXT) { |
| 274 | + FlatVector::GetData<date_t>(out_vec)[out_idx] = |
| 275 | + Date::FromCString((const char *)sqlite3_value_text(val), sqlite3_value_bytes(val)); |
| 276 | + } else { |
| 277 | + throw NotImplementedException( |
| 278 | + "Unimplemented SQLite type for column of type DATE\n* SET sqlite_all_varchar=true to " |
| 279 | + "load all columns as VARCHAR and skip type conversions"); |
| 280 | + } |
261 | 281 | break;
|
262 | 282 | case LogicalTypeId::TIMESTAMP:
|
263 |
| - stmt.CheckTypeMatches(bind_data, val, sqlite_column_type, SQLITE_TEXT, col_idx); |
264 |
| - FlatVector::GetData<timestamp_t>(out_vec)[out_idx] = |
265 |
| - Timestamp::FromCString((const char *)sqlite3_value_text(val), sqlite3_value_bytes(val)); |
| 283 | + // SQLite does not have a timestamp type - but it has "conventions" |
| 284 | + // See https://www.sqlite.org/lang_datefunc.html |
| 285 | + // The conventions are: |
| 286 | + // A text string that is an ISO 8601 date/time value |
| 287 | + // The number of days including fractional days since -4713-11-24 12:00:00 |
| 288 | + // The number of seconds including fractional seconds since 1970-01-01 00:00:00 |
| 289 | + // for now we only support ISO-8601 and unix timestamps |
| 290 | + if (sqlite_column_type == SQLITE_INTEGER) { |
| 291 | + // unix timestamp |
| 292 | + FlatVector::GetData<timestamp_t>(out_vec)[out_idx] = ConvertTimestampInteger(val); |
| 293 | + } else if (sqlite_column_type == SQLITE_FLOAT) { |
| 294 | + FlatVector::GetData<timestamp_t>(out_vec)[out_idx] = ConvertTimestampFloat(val); |
| 295 | + } else if (sqlite_column_type == SQLITE_TEXT) { |
| 296 | + // ISO-8601 |
| 297 | + FlatVector::GetData<timestamp_t>(out_vec)[out_idx] = |
| 298 | + Timestamp::FromCString((const char *)sqlite3_value_text(val), sqlite3_value_bytes(val)); |
| 299 | + } else { |
| 300 | + throw NotImplementedException( |
| 301 | + "Unimplemented SQLite type for column of type TIMESTAMP\n* SET sqlite_all_varchar=true to " |
| 302 | + "load all columns as VARCHAR and skip type conversions"); |
| 303 | + } |
266 | 304 | break;
|
267 | 305 | case LogicalTypeId::BLOB:
|
268 | 306 | FlatVector::GetData<string_t>(out_vec)[out_idx] = StringVector::AddStringOrBlob(
|
|
0 commit comments