-
Notifications
You must be signed in to change notification settings - Fork 107
Fails value insertion if type unsupported by duckdb #471
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,45 @@ static bool ctas_skip_data = false; | |
static bool top_level_ddl = true; | ||
static ProcessUtility_hook_type prev_process_utility_hook = NULL; | ||
|
||
// Get precision and scale from postgres type modifier. | ||
static int | ||
GetPgNumericPrecision(int32 typmod) { | ||
return ((typmod - VARHDRSZ) >> 16) & 0xffff; | ||
} | ||
static int | ||
GetPgNumericScale(int32 typmod) { | ||
return (((typmod - VARHDRSZ) & 0x7ff) ^ 1024) - 1024; | ||
} | ||
|
||
// If column is of type "numeric", check whether it's acceptable for duckdb; | ||
// If not, exception is thrown via `elog`. | ||
static void | ||
ValidateColumnNumericType(Form_pg_attribute &attribute) { | ||
auto &type = attribute->atttypid; | ||
if (type != NUMERICOID) { | ||
return; | ||
} | ||
auto &typmod = attribute->atttypmod; | ||
auto precision = GetPgNumericPrecision(typmod); | ||
auto scale = GetPgNumericScale(typmod); | ||
// duckdb's "numeric" type's max supported precision is 38. | ||
if (typmod == -1 || precision < 0 || scale < 0 || precision > 38) { | ||
elog(ERROR, | ||
"Unsupported type when creating column: type precision %d with scale %d is not supported by duckdb, which " | ||
"only allows maximum precision 38", | ||
precision, scale); | ||
} | ||
} | ||
|
||
// Validate new relation creation, if invalid throw exception via `elog`. | ||
static void | ||
ValidateRelationCreation(TupleDesc desc) { | ||
for (int i = 0; i < desc->natts; i++) { | ||
Form_pg_attribute attr = &desc->attrs[i]; | ||
ValidateColumnNumericType(attr); | ||
} | ||
} | ||
|
||
static void | ||
DuckdbHandleDDL(Node *parsetree) { | ||
if (!pgduckdb::IsExtensionRegistered()) { | ||
|
@@ -253,6 +292,10 @@ DECLARE_PG_FUNCTION(duckdb_create_table_trigger) { | |
elog(ERROR, "Expected single table to be created, but found %" PRIu64, static_cast<uint64_t>(SPI_processed)); | ||
} | ||
|
||
// Check whether new table creation is supported in duckdb. | ||
// TODO(hjiang): Same type validation should be applied to other DDL as well. | ||
ValidateRelationCreation(SPI_tuptable->tupdesc); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: prob move this check to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it makes sense, my concern is, other DDL statements (i.e. ALTER TABLE) require the same validation logic. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I fully agree to place all validation logic into one function / one place. Would like to know how pg_duckdb's owner think about it. :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with @dpxcc. Let's put it into |
||
|
||
HeapTuple tuple = SPI_tuptable->vals[0]; | ||
bool isnull; | ||
Datum relid_datum = SPI_getbinval(tuple, SPI_tuptable->tupdesc, 1, &isnull); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -199,7 +199,7 @@ SELECT * FROM float8_array_1d; | |
(4 rows) | ||
|
||
-- NUMERIC (single dimension) | ||
CREATE TABLE numeric_array_1d(a NUMERIC[]); | ||
CREATE TABLE numeric_array_1d(a NUMERIC(2, 1)[]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it would be good to do this new test in addition to the old one. |
||
INSERT INTO numeric_array_1d SELECT CAST(a as NUMERIC[]) FROM (VALUES | ||
('{1.1, 2.2, 3.3}'), | ||
(NULL), | ||
|
@@ -373,7 +373,7 @@ SELECT * FROM float8_array_2d; | |
(5 rows) | ||
|
||
-- NUMERIC (two dimensions) | ||
CREATE TABLE numeric_array_2d(a NUMERIC[][]); | ||
CREATE TABLE numeric_array_2d(a NUMERIC(3, 1)[][]); | ||
INSERT INTO numeric_array_2d VALUES | ||
('{{1.1,2.2},{3.3,4.4}}'), | ||
('{{5.5,6.6,7.7},{8.8,9.9,10.1}}'), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
CREATE TEMP TABLE large_numeric_tbl (a NUMERIC) USING duckdb; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this CREATE TABLE command not failing? I thought the whole point of this PR was that this should not be allowed. |
||
INSERT INTO large_numeric_tbl VALUES(856324.111122223333::NUMERIC(40,12)); | ||
ERROR: (PGDuckDB/CreatePlan) Prepared query returned an error: 'Parser Error: Width must be between 1 and 38! |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,3 +26,4 @@ test: transaction_errors | |
test: secrets | ||
test: prepare | ||
test: function | ||
test: unsupported_types |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
CREATE TEMP TABLE large_numeric_tbl (a NUMERIC) USING duckdb; | ||
INSERT INTO large_numeric_tbl VALUES(856324.111122223333::NUMERIC(40,12)); |
Uh oh!
There was an error while loading. Please reload this page.