diff --git a/.github/workflows/MainDistributionPipeline.yml b/.github/workflows/MainDistributionPipeline.yml index 766cc1851..5e87a6850 100644 --- a/.github/workflows/MainDistributionPipeline.yml +++ b/.github/workflows/MainDistributionPipeline.yml @@ -16,8 +16,8 @@ jobs: name: Build extension binaries uses: duckdb/extension-ci-tools/.github/workflows/_extension_distribution.yml@v1.3.0 with: - duckdb_version: main - ci_tools_version: main + duckdb_version: v1.3.0 + ci_tools_version: v1.3.0 extension_name: postgres_scanner exclude_archs: 'wasm_mvp;wasm_eh;wasm_threads;windows_amd64_mingw' @@ -27,8 +27,8 @@ jobs: uses: duckdb/extension-ci-tools/.github/workflows/_extension_deploy.yml@v1.3.0 secrets: inherit with: - duckdb_version: main - ci_tools_version: main + duckdb_version: v1.3.0 + ci_tools_version: v1.3.0 extension_name: postgres_scanner exclude_archs: 'wasm_mvp;wasm_eh;wasm_threads;windows_amd64_mingw' deploy_latest: ${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' }} diff --git a/src/include/postgres_utils.hpp b/src/include/postgres_utils.hpp index 34e5ee5cd..be448cc5c 100644 --- a/src/include/postgres_utils.hpp +++ b/src/include/postgres_utils.hpp @@ -54,6 +54,8 @@ struct PostgresCopyState { void Initialize(ClientContext &context); }; +enum class PostgresIsolationLevel { READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE }; + class PostgresUtils { public: static PGconn *PGConnect(const string &dsn); diff --git a/src/include/storage/postgres_catalog.hpp b/src/include/storage/postgres_catalog.hpp index e7a5cc547..a49f31b9f 100644 --- a/src/include/storage/postgres_catalog.hpp +++ b/src/include/storage/postgres_catalog.hpp @@ -21,12 +21,13 @@ class PostgresSchemaEntry; class PostgresCatalog : public Catalog { public: explicit PostgresCatalog(AttachedDatabase &db_p, string connection_string, string attach_path, - AccessMode access_mode, string schema_to_load); + AccessMode access_mode, string schema_to_load, PostgresIsolationLevel isolation_level); ~PostgresCatalog(); string connection_string; string attach_path; AccessMode access_mode; + PostgresIsolationLevel isolation_level; public: void Initialize(bool load_builtin) override; diff --git a/src/include/storage/postgres_transaction.hpp b/src/include/storage/postgres_transaction.hpp index e20cc0a15..f81697627 100644 --- a/src/include/storage/postgres_transaction.hpp +++ b/src/include/storage/postgres_transaction.hpp @@ -43,11 +43,14 @@ class PostgresTransaction : public Transaction { PostgresPoolConnection connection; PostgresTransactionState transaction_state; AccessMode access_mode; + PostgresIsolationLevel isolation_level; string temporary_schema; private: //! Retrieves the connection **without** starting a transaction if none is active PostgresConnection &GetConnectionRaw(); + + string GetBeginTransactionQuery(); }; } // namespace duckdb diff --git a/src/postgres_binary_copy.cpp b/src/postgres_binary_copy.cpp index 9c0212f84..bce7d2260 100644 --- a/src/postgres_binary_copy.cpp +++ b/src/postgres_binary_copy.cpp @@ -101,4 +101,4 @@ void PostgresBinaryCopyFunction::PostgresBinaryWriteFinalize(ClientContext &cont gstate.Flush(); } -} // namespace duckdb \ No newline at end of file +} // namespace duckdb diff --git a/src/postgres_execute.cpp b/src/postgres_execute.cpp index 831ebacdc..ea9f6bbc1 100644 --- a/src/postgres_execute.cpp +++ b/src/postgres_execute.cpp @@ -66,7 +66,7 @@ static void PGExecuteFunction(ClientContext &context, TableFunctionInput &data_p PostgresExecuteFunction::PostgresExecuteFunction() : TableFunction("postgres_execute", {LogicalType::VARCHAR, LogicalType::VARCHAR}, PGExecuteFunction, PGExecuteBind) { - named_parameters["use_transaction"] = LogicalType::BOOLEAN; + named_parameters["use_transaction"] = LogicalType::BOOLEAN; } } // namespace duckdb diff --git a/src/postgres_extension.cpp b/src/postgres_extension.cpp index d8f46e8c8..5e54b69e5 100644 --- a/src/postgres_extension.cpp +++ b/src/postgres_extension.cpp @@ -173,9 +173,8 @@ static void LoadInternal(DatabaseInstance &db) { LogicalType::BOOLEAN, Value::BOOLEAN(false), PostgresClearCacheFunction::ClearCacheOnSetting); config.AddExtensionOption("pg_connection_cache", "Whether or not to use the connection cache", LogicalType::BOOLEAN, Value::BOOLEAN(true), PostgresConnectionPool::PostgresSetConnectionCache); - config.AddExtensionOption("pg_experimental_filter_pushdown", - "Whether or not to use filter pushdown", LogicalType::BOOLEAN, - Value::BOOLEAN(true)); + config.AddExtensionOption("pg_experimental_filter_pushdown", "Whether or not to use filter pushdown", + LogicalType::BOOLEAN, Value::BOOLEAN(true)); config.AddExtensionOption("pg_null_byte_replacement", "When writing NULL bytes to Postgres, replace them with the given character", LogicalType::VARCHAR, Value(), SetPostgresNullByteReplacement); diff --git a/src/postgres_filter_pushdown.cpp b/src/postgres_filter_pushdown.cpp index adc989533..c163a330b 100644 --- a/src/postgres_filter_pushdown.cpp +++ b/src/postgres_filter_pushdown.cpp @@ -45,7 +45,7 @@ string TransformBlob(const string &val) { char const HEX_DIGITS[] = "0123456789ABCDEF"; string result = "'\\x"; - for(idx_t i = 0; i < val.size(); i++) { + for (idx_t i = 0; i < val.size(); i++) { uint8_t byte_val = static_cast(val[i]); result += HEX_DIGITS[(byte_val >> 4) & 0xf]; result += HEX_DIGITS[byte_val & 0xf]; @@ -96,7 +96,7 @@ string PostgresFilterPushdown::TransformFilter(string &column_name, TableFilter case TableFilterType::IN_FILTER: { auto &in_filter = filter.Cast(); string in_list; - for(auto &val : in_filter.values) { + for (auto &val : in_filter.values) { if (!in_list.empty()) { in_list += ", "; } diff --git a/src/postgres_scanner.cpp b/src/postgres_scanner.cpp index 9b2d0623d..be14320d2 100644 --- a/src/postgres_scanner.cpp +++ b/src/postgres_scanner.cpp @@ -251,15 +251,15 @@ static void PostgresInitInternal(ClientContext &context, const PostgresBindData } if (bind_data->table_name.empty()) { D_ASSERT(!bind_data->sql.empty()); - lstate.sql = StringUtil::Format( - R"(COPY (SELECT %s FROM (%s) AS __unnamed_subquery %s%s) TO STDOUT (FORMAT "binary");)", - col_names, bind_data->sql, filter, bind_data->limit); + lstate.sql = + StringUtil::Format(R"(COPY (SELECT %s FROM (%s) AS __unnamed_subquery %s%s) TO STDOUT (FORMAT "binary");)", + col_names, bind_data->sql, filter, bind_data->limit); } else { - lstate.sql = StringUtil::Format( - R"(COPY (SELECT %s FROM %s.%s %s%s) TO STDOUT (FORMAT "binary");)", - col_names, KeywordHelper::WriteQuoted(bind_data->schema_name, '"'), - KeywordHelper::WriteQuoted(bind_data->table_name, '"'), filter, bind_data->limit); + lstate.sql = + StringUtil::Format(R"(COPY (SELECT %s FROM %s.%s %s%s) TO STDOUT (FORMAT "binary");)", col_names, + KeywordHelper::WriteQuoted(bind_data->schema_name, '"'), + KeywordHelper::WriteQuoted(bind_data->table_name, '"'), filter, bind_data->limit); } lstate.exec = false; lstate.done = false; diff --git a/src/postgres_storage.cpp b/src/postgres_storage.cpp index 9c461780f..9a28ca3c9 100644 --- a/src/postgres_storage.cpp +++ b/src/postgres_storage.cpp @@ -18,6 +18,7 @@ static unique_ptr PostgresAttach(StorageExtensionInfo *storage_info, Cl string secret_name; string schema_to_load; + PostgresIsolationLevel isolation_level = PostgresIsolationLevel::REPEATABLE_READ; for (auto &entry : info.options) { auto lower_name = StringUtil::Lower(entry.first); if (lower_name == "type" || lower_name == "read_only") { @@ -26,12 +27,27 @@ static unique_ptr PostgresAttach(StorageExtensionInfo *storage_info, Cl secret_name = entry.second.ToString(); } else if (lower_name == "schema") { schema_to_load = entry.second.ToString(); + } else if (lower_name == "isolation_level") { + auto param = entry.second.ToString(); + auto lparam = StringUtil::Lower(param); + if (lparam == "read committed") { + isolation_level = PostgresIsolationLevel::READ_COMMITTED; + } else if (lparam == "repeatable read") { + isolation_level = PostgresIsolationLevel::REPEATABLE_READ; + } else if (lparam == "serializable") { + isolation_level = PostgresIsolationLevel::SERIALIZABLE; + } else { + throw InvalidInputException("Invalid value \"%s\" for isolation_level, expected READ COMMITTED, " + "REPEATABLE READ or SERIALIZABLE", + param); + } } else { throw BinderException("Unrecognized option for Postgres attach: %s", entry.first); } } auto connection_string = PostgresCatalog::GetConnectionString(context, attach_path, secret_name); - return make_uniq(db, std::move(connection_string), std::move(attach_path), access_mode, std::move(schema_to_load)); + return make_uniq(db, std::move(connection_string), std::move(attach_path), access_mode, + std::move(schema_to_load), isolation_level); } static unique_ptr PostgresCreateTransactionManager(StorageExtensionInfo *storage_info, diff --git a/src/storage/postgres_catalog.cpp b/src/storage/postgres_catalog.cpp index 0d9ce4b82..953d73d33 100644 --- a/src/storage/postgres_catalog.cpp +++ b/src/storage/postgres_catalog.cpp @@ -10,10 +10,11 @@ namespace duckdb { -PostgresCatalog::PostgresCatalog(AttachedDatabase &db_p, string connection_string_p, string attach_path_p, AccessMode access_mode, - string schema_to_load) - : Catalog(db_p), connection_string(std::move(connection_string_p)), attach_path(std::move(attach_path_p)), access_mode(access_mode), schemas(*this, schema_to_load), connection_pool(*this), - default_schema(schema_to_load) { +PostgresCatalog::PostgresCatalog(AttachedDatabase &db_p, string connection_string_p, string attach_path_p, + AccessMode access_mode, string schema_to_load, PostgresIsolationLevel isolation_level) + : Catalog(db_p), connection_string(std::move(connection_string_p)), attach_path(std::move(attach_path_p)), + access_mode(access_mode), isolation_level(isolation_level), schemas(*this, schema_to_load), + connection_pool(*this), default_schema(schema_to_load) { if (default_schema.empty()) { default_schema = "public"; } @@ -100,7 +101,6 @@ string PostgresCatalog::GetConnectionString(ClientContext &context, const string return connection_string; } - PostgresCatalog::~PostgresCatalog() = default; void PostgresCatalog::Initialize(bool load_builtin) { @@ -138,9 +138,10 @@ void PostgresCatalog::ScanSchemas(ClientContext &context, std::function()); }); } -optional_ptr PostgresCatalog::LookupSchema(CatalogTransaction transaction, const EntryLookupInfo &schema_lookup, - OnEntryNotFound if_not_found) { - auto schema_name = schema_lookup.GetEntryName(); +optional_ptr PostgresCatalog::LookupSchema(CatalogTransaction transaction, + const EntryLookupInfo &schema_lookup, + OnEntryNotFound if_not_found) { + auto schema_name = schema_lookup.GetEntryName(); auto &postgres_transaction = PostgresTransaction::Get(transaction.GetContext(), *this); if (schema_name == "pg_temp") { schema_name = postgres_transaction.GetTemporarySchema(); diff --git a/src/storage/postgres_delete.cpp b/src/storage/postgres_delete.cpp index 88dec2ce5..5f97485e6 100644 --- a/src/storage/postgres_delete.cpp +++ b/src/storage/postgres_delete.cpp @@ -119,7 +119,8 @@ InsertionOrderPreservingMap PostgresDelete::ParamsToString() const { //===--------------------------------------------------------------------===// // Plan //===--------------------------------------------------------------------===// -PhysicalOperator &PostgresCatalog::PlanDelete(ClientContext &context, PhysicalPlanGenerator &planner, LogicalDelete &op, PhysicalOperator &plan) { +PhysicalOperator &PostgresCatalog::PlanDelete(ClientContext &context, PhysicalPlanGenerator &planner, LogicalDelete &op, + PhysicalOperator &plan) { if (op.return_chunk) { throw BinderException("RETURNING clause not yet supported for deletion of a Postgres table"); } @@ -127,7 +128,7 @@ PhysicalOperator &PostgresCatalog::PlanDelete(ClientContext &context, PhysicalPl PostgresCatalog::MaterializePostgresScans(plan); auto &delete_op = planner.Make(op, op.table, bound_ref.index); - delete_op.children.push_back(plan); + delete_op.children.push_back(plan); return delete_op; } diff --git a/src/storage/postgres_insert.cpp b/src/storage/postgres_insert.cpp index dd616df30..41d318b1b 100644 --- a/src/storage/postgres_insert.cpp +++ b/src/storage/postgres_insert.cpp @@ -153,7 +153,8 @@ InsertionOrderPreservingMap PostgresInsert::ParamsToString() const { //===--------------------------------------------------------------------===// // Plan //===--------------------------------------------------------------------===// -PhysicalOperator &AddCastToPostgresTypes(ClientContext &context, PhysicalPlanGenerator &planner, PhysicalOperator &plan) { +PhysicalOperator &AddCastToPostgresTypes(ClientContext &context, PhysicalPlanGenerator &planner, + PhysicalOperator &plan) { // check if we need to cast anything bool require_cast = false; auto &child_types = plan.GetTypes(); @@ -164,30 +165,31 @@ PhysicalOperator &AddCastToPostgresTypes(ClientContext &context, PhysicalPlanGen break; } } - if (!require_cast) { - return plan; - } - - vector postgres_types; - vector> select_list; - for (idx_t i = 0; i < child_types.size(); i++) { - auto &type = child_types[i]; - unique_ptr expr; - expr = make_uniq(type, i); - - auto postgres_type = PostgresUtils::ToPostgresType(type); - if (postgres_type != type) { - // add a cast - expr = BoundCastExpression::AddCastToType(context, std::move(expr), postgres_type); - } - postgres_types.push_back(std::move(postgres_type)); - select_list.push_back(std::move(expr)); - } - - // we need to cast: add casts - auto &proj = planner.Make(std::move(postgres_types), std::move(select_list), plan.estimated_cardinality); - proj.children.push_back(plan); - return proj; + if (!require_cast) { + return plan; + } + + vector postgres_types; + vector> select_list; + for (idx_t i = 0; i < child_types.size(); i++) { + auto &type = child_types[i]; + unique_ptr expr; + expr = make_uniq(type, i); + + auto postgres_type = PostgresUtils::ToPostgresType(type); + if (postgres_type != type) { + // add a cast + expr = BoundCastExpression::AddCastToType(context, std::move(expr), postgres_type); + } + postgres_types.push_back(std::move(postgres_type)); + select_list.push_back(std::move(expr)); + } + + // we need to cast: add casts + auto &proj = + planner.Make(std::move(postgres_types), std::move(select_list), plan.estimated_cardinality); + proj.children.push_back(plan); + return proj; } bool PostgresCatalog::IsPostgresScan(const string &name) { @@ -210,7 +212,8 @@ void PostgresCatalog::MaterializePostgresScans(PhysicalOperator &op) { } } -PhysicalOperator &PostgresCatalog::PlanInsert(ClientContext &context, PhysicalPlanGenerator &planner, LogicalInsert &op, optional_ptr plan) { +PhysicalOperator &PostgresCatalog::PlanInsert(ClientContext &context, PhysicalPlanGenerator &planner, LogicalInsert &op, + optional_ptr plan) { if (op.return_chunk) { throw BinderException("RETURNING clause not yet supported for insertion into Postgres table"); } @@ -218,7 +221,7 @@ PhysicalOperator &PostgresCatalog::PlanInsert(ClientContext &context, PhysicalPl throw BinderException("ON CONFLICT clause not yet supported for insertion into Postgres table"); } - D_ASSERT(plan); + D_ASSERT(plan); MaterializePostgresScans(*plan); auto &inner_plan = AddCastToPostgresTypes(context, planner, *plan); @@ -227,7 +230,8 @@ PhysicalOperator &PostgresCatalog::PlanInsert(ClientContext &context, PhysicalPl return insert; } -PhysicalOperator &PostgresCatalog::PlanCreateTableAs(ClientContext &context, PhysicalPlanGenerator &planner, LogicalCreateTable &op, PhysicalOperator &plan) { +PhysicalOperator &PostgresCatalog::PlanCreateTableAs(ClientContext &context, PhysicalPlanGenerator &planner, + LogicalCreateTable &op, PhysicalOperator &plan) { auto &inner_plan = AddCastToPostgresTypes(context, planner, plan); MaterializePostgresScans(inner_plan); diff --git a/src/storage/postgres_optimizer.cpp b/src/storage/postgres_optimizer.cpp index 393eb7e27..5eab29f83 100644 --- a/src/storage/postgres_optimizer.cpp +++ b/src/storage/postgres_optimizer.cpp @@ -7,7 +7,6 @@ #include "storage/postgres_catalog.hpp" #include "postgres_scanner.hpp" - namespace duckdb { struct PostgresOperators { diff --git a/src/storage/postgres_schema_entry.cpp b/src/storage/postgres_schema_entry.cpp index c1b34918e..35c4bd1d3 100644 --- a/src/storage/postgres_schema_entry.cpp +++ b/src/storage/postgres_schema_entry.cpp @@ -183,7 +183,8 @@ void PostgresSchemaEntry::DropEntry(ClientContext &context, DropInfo &info) { GetCatalogSet(info.type).DropEntry(context, info); } -optional_ptr PostgresSchemaEntry::LookupEntry(CatalogTransaction transaction, const EntryLookupInfo &lookup_info) { +optional_ptr PostgresSchemaEntry::LookupEntry(CatalogTransaction transaction, + const EntryLookupInfo &lookup_info) { auto catalog_type = lookup_info.GetCatalogType(); if (!CatalogTypeIsSupported(catalog_type)) { return nullptr; @@ -205,4 +206,4 @@ PostgresCatalogSet &PostgresSchemaEntry::GetCatalogSet(CatalogType type) { } } -} // namespace duckdb \ No newline at end of file +} // namespace duckdb diff --git a/src/storage/postgres_transaction.cpp b/src/storage/postgres_transaction.cpp index c956857eb..7ed8c33d7 100644 --- a/src/storage/postgres_transaction.cpp +++ b/src/storage/postgres_transaction.cpp @@ -9,7 +9,8 @@ namespace duckdb { PostgresTransaction::PostgresTransaction(PostgresCatalog &postgres_catalog, TransactionManager &manager, ClientContext &context) - : Transaction(manager, context), access_mode(postgres_catalog.access_mode) { + : Transaction(manager, context), access_mode(postgres_catalog.access_mode), + isolation_level(postgres_catalog.isolation_level) { connection = postgres_catalog.GetConnectionPool().GetConnection(); } @@ -31,8 +32,21 @@ void PostgresTransaction::Rollback() { } } -static string GetBeginTransactionQuery(AccessMode access_mode) { - string result = "BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ"; +string PostgresTransaction::GetBeginTransactionQuery() { + string result = "BEGIN TRANSACTION ISOLATION LEVEL "; + switch (isolation_level) { + case PostgresIsolationLevel::READ_COMMITTED: + result += "READ COMMITTED"; + break; + case PostgresIsolationLevel::REPEATABLE_READ: + result += "REPEATABLE READ"; + break; + case PostgresIsolationLevel::SERIALIZABLE: + result += "SERIALIZABLE"; + break; + default: + throw InternalException("Unsupported isolation level"); + } if (access_mode == AccessMode::READ_ONLY) { result += " READ ONLY"; } @@ -53,7 +67,7 @@ PostgresConnection &PostgresTransaction::GetConnection() { auto &con = GetConnectionRaw(); if (transaction_state == PostgresTransactionState::TRANSACTION_NOT_YET_STARTED) { transaction_state = PostgresTransactionState::TRANSACTION_STARTED; - string query = GetBeginTransactionQuery(access_mode); + string query = GetBeginTransactionQuery(); con.Execute(query); } return con; @@ -71,7 +85,7 @@ unique_ptr PostgresTransaction::Query(const string &query) { auto &con = GetConnectionRaw(); if (transaction_state == PostgresTransactionState::TRANSACTION_NOT_YET_STARTED) { transaction_state = PostgresTransactionState::TRANSACTION_STARTED; - string transaction_start = GetBeginTransactionQuery(access_mode); + string transaction_start = GetBeginTransactionQuery(); transaction_start += ";\n"; return con.Query(transaction_start + query); } @@ -93,7 +107,7 @@ vector> PostgresTransaction::ExecuteQueries(const str auto &con = GetConnectionRaw(); if (transaction_state == PostgresTransactionState::TRANSACTION_NOT_YET_STARTED) { transaction_state = PostgresTransactionState::TRANSACTION_STARTED; - string transaction_start = GetBeginTransactionQuery(access_mode); + string transaction_start = GetBeginTransactionQuery(); transaction_start += ";\n"; return con.ExecuteQueries(transaction_start + queries); } diff --git a/src/storage/postgres_update.cpp b/src/storage/postgres_update.cpp index 8fa4d690b..12611723c 100644 --- a/src/storage/postgres_update.cpp +++ b/src/storage/postgres_update.cpp @@ -180,7 +180,8 @@ InsertionOrderPreservingMap PostgresUpdate::ParamsToString() const { //===--------------------------------------------------------------------===// // Plan //===--------------------------------------------------------------------===// -PhysicalOperator &PostgresCatalog::PlanUpdate(ClientContext &context, PhysicalPlanGenerator &planner, LogicalUpdate &op, PhysicalOperator &plan) { +PhysicalOperator &PostgresCatalog::PlanUpdate(ClientContext &context, PhysicalPlanGenerator &planner, LogicalUpdate &op, + PhysicalOperator &plan) { if (op.return_chunk) { throw BinderException("RETURNING clause not yet supported for updates of a Postgres table"); } @@ -192,7 +193,7 @@ PhysicalOperator &PostgresCatalog::PlanUpdate(ClientContext &context, PhysicalPl PostgresCatalog::MaterializePostgresScans(plan); auto &update = planner.Make(op, op.table, std::move(op.columns)); - update.children.push_back(plan); + update.children.push_back(plan); return update; } diff --git a/test/create-decimal-tables.py b/test/create-decimal-tables.py index 0bbd4ff60..92cb5aaa9 100644 --- a/test/create-decimal-tables.py +++ b/test/create-decimal-tables.py @@ -6,37 +6,37 @@ max_len = 18 for type_inte_len in range(0, max_len + 1): - for type_frac_len in range(0, max_len + 1): - type_len = type_inte_len + type_frac_len - if type_len == 0: - continue - tname = f"dec_{type_inte_len}_{type_frac_len}" - if generate_insertion_script: - print(f"CREATE TABLE {tname} (dec DECIMAL({type_len},{type_frac_len}));") - else: - print(f"query I") - print(f"SELECT * FROM {tname}") - print("----") + for type_frac_len in range(0, max_len + 1): + type_len = type_inte_len + type_frac_len + if type_len == 0: + continue + tname = f"dec_{type_inte_len}_{type_frac_len}" + if generate_insertion_script: + print(f"CREATE TABLE {tname} (dec DECIMAL({type_len},{type_frac_len}));") + else: + print(f"query I") + print(f"SELECT * FROM {tname}") + print("----") - if generate_insertion_script: - print(f"INSERT INTO {tname} VALUES ") - prefix = '(' - suffix = '),' - else: - prefix = '' - suffix = '' - for val_inte_len in range(0, type_inte_len + 1): - for val_frac_len in range(0, type_frac_len + 1): - inte_str = "0" - frac_str = "0" - if val_inte_len > 0: - inte_str = pattern[0:val_inte_len] - if val_frac_len > 0: - frac_str = pattern[0:val_frac_len] - print (prefix + f"{inte_str}.{frac_str}" + suffix) - print (prefix + f"-{inte_str}.{frac_str}" + suffix) - if val_inte_len > 0 and val_frac_len > 0: - print (prefix + "1".ljust(val_inte_len, '0') + "." + "1".rjust(val_frac_len, '0') + suffix) - print (prefix + "-"+"1".ljust(val_inte_len, '0') + "." + "1".rjust(val_frac_len, '0') + suffix) - print(prefix + "0.0" + suffix) - print('') + if generate_insertion_script: + print(f"INSERT INTO {tname} VALUES ") + prefix = '(' + suffix = '),' + else: + prefix = '' + suffix = '' + for val_inte_len in range(0, type_inte_len + 1): + for val_frac_len in range(0, type_frac_len + 1): + inte_str = "0" + frac_str = "0" + if val_inte_len > 0: + inte_str = pattern[0:val_inte_len] + if val_frac_len > 0: + frac_str = pattern[0:val_frac_len] + print(prefix + f"{inte_str}.{frac_str}" + suffix) + print(prefix + f"-{inte_str}.{frac_str}" + suffix) + if val_inte_len > 0 and val_frac_len > 0: + print(prefix + "1".ljust(val_inte_len, '0') + "." + "1".rjust(val_frac_len, '0') + suffix) + print(prefix + "-" + "1".ljust(val_inte_len, '0') + "." + "1".rjust(val_frac_len, '0') + suffix) + print(prefix + "0.0" + suffix) + print('') diff --git a/test/sql/misc/autoload.test b/test/sql/misc/autoload.test index dc5f6dc45..6a22bd0b0 100644 --- a/test/sql/misc/autoload.test +++ b/test/sql/misc/autoload.test @@ -1,4 +1,4 @@ -# name: test/sql/misc/autoloading.test +# name: test/sql/misc/autoload.test # description: Test autoloading based on setting # group: [misc] diff --git a/test/sql/misc/postgres_binary.test b/test/sql/misc/postgres_binary.test index ddebfb39f..d0141588c 100644 --- a/test/sql/misc/postgres_binary.test +++ b/test/sql/misc/postgres_binary.test @@ -1,6 +1,6 @@ # name: test/sql/misc/postgres_binary.test # description: Test postgres binary copy through a file -# group: [scanner] +# group: [misc] require postgres_scanner diff --git a/test/sql/storage/attach_isolation_level.test b/test/sql/storage/attach_isolation_level.test new file mode 100644 index 000000000..21fe79af5 --- /dev/null +++ b/test/sql/storage/attach_isolation_level.test @@ -0,0 +1,44 @@ +# name: test/sql/storage/attach_isolation_level.test +# description: Test attaching with a different isolation level +# group: [storage] + +require postgres_scanner + +require-env POSTGRES_TEST_DATABASE_AVAILABLE + +statement ok +PRAGMA enable_verification + +statement ok +ATTACH 'dbname=postgresscanner' AS s (TYPE POSTGRES, ISOLATION_LEVEL 'READ COMMITTED') + +# select from a NUMERIC field +query I +SELECT * FROM s.pg_giant_numeric +---- +0.0 +1.0000000000000002e+32 +-1.234567891234568e+26 + +statement ok +DETACH s + +statement ok +ATTACH 'dbname=postgresscanner' AS s (TYPE POSTGRES, ISOLATION_LEVEL 'SERIALIZABLE') + +# select from a NUMERIC field +query I +SELECT * FROM s.pg_giant_numeric +---- +0.0 +1.0000000000000002e+32 +-1.234567891234568e+26 + +statement ok +DETACH s + +# unrecognized isolation level +statement error +ATTACH 'dbname=postgresscanner' AS s (TYPE POSTGRES, ISOLATION_LEVEL 'unrecognized_isolation') +---- +unrecognized_isolation diff --git a/test/sql/storage/attach_issue_146.test b/test/sql/storage/attach_issue_146.test index cdacba8d3..fb4650a8e 100644 --- a/test/sql/storage/attach_issue_146.test +++ b/test/sql/storage/attach_issue_146.test @@ -1,4 +1,4 @@ -# name: test/sql/storage/attach_keywords.test +# name: test/sql/storage/attach_issue_146.test # description: Test quoting in ATTACH with keyword identifiers # group: [storage]