Skip to content

Commit 1084b1a

Browse files
duckdblabs-botgithub-actions[bot]
authored andcommitted
Update vendored DuckDB sources to f5174f0d6d
1 parent 362ade9 commit 1084b1a

13 files changed

Lines changed: 263 additions & 199 deletions

File tree

src/duckdb/src/common/adbc/adbc.cpp

Lines changed: 88 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ struct DuckDBAdbcStatementWrapper {
113113
duckdb_connection connection;
114114
duckdb_prepared_statement statement;
115115
char *ingestion_table_name;
116+
char *target_catalog;
116117
char *db_schema;
117118
ArrowArrayStream ingestion_stream;
118119
IngestionMode ingestion_mode = IngestionMode::CREATE;
@@ -725,16 +726,36 @@ void stream_schema(ArrowArrayStream *stream, ArrowSchema &schema) {
725726
}
726727

727728
// Helper function to build CREATE TABLE SQL statement
728-
static std::string BuildCreateTableSQL(const char *schema, const char *table_name,
729+
static std::string BuildCreateTableSQL(const char *catalog, const char *schema, const char *table_name,
729730
const duckdb::vector<duckdb::LogicalType> &types,
730-
const duckdb::vector<std::string> &names, bool if_not_exists = false) {
731+
const duckdb::vector<std::string> &names, bool if_not_exists = false,
732+
bool temporary = false, bool replace = false) {
731733
std::ostringstream create_table;
732-
create_table << "CREATE TABLE ";
734+
if (replace) {
735+
create_table << "CREATE OR REPLACE ";
736+
} else {
737+
create_table << "CREATE ";
738+
}
739+
if (temporary) {
740+
create_table << "TEMP ";
741+
}
742+
create_table << "TABLE ";
733743
if (if_not_exists) {
734744
create_table << "IF NOT EXISTS ";
735745
}
736-
if (schema) {
737-
create_table << duckdb::KeywordHelper::WriteOptionallyQuoted(schema) << ".";
746+
// Note: DuckDB resolves two-part names as either catalog.table (default schema)
747+
// or schema.table depending on context. This can become ambiguous if a schema and
748+
// an attached catalog share a name. Callers should prefer passing an explicit
749+
// schema (or defaulting to "main") to produce an unambiguous three-part name.
750+
// For TEMP tables, specifying catalog/schema in the CREATE statement is not allowed;
751+
// the table is automatically placed in the temp catalog.
752+
if (!temporary) {
753+
if (catalog) {
754+
create_table << duckdb::KeywordHelper::WriteOptionallyQuoted(catalog) << ".";
755+
}
756+
if (schema) {
757+
create_table << duckdb::KeywordHelper::WriteOptionallyQuoted(schema) << ".";
758+
}
738759
}
739760
create_table << duckdb::KeywordHelper::WriteOptionallyQuoted(table_name) << " (";
740761
for (idx_t i = 0; i < types.size(); i++) {
@@ -748,18 +769,7 @@ static std::string BuildCreateTableSQL(const char *schema, const char *table_nam
748769
return create_table.str();
749770
}
750771

751-
// Helper function to build DROP TABLE IF EXISTS SQL statement
752-
static std::string BuildDropTableSQL(const char *schema, const char *table_name) {
753-
std::ostringstream drop_table;
754-
drop_table << "DROP TABLE IF EXISTS ";
755-
if (schema) {
756-
drop_table << duckdb::KeywordHelper::WriteOptionallyQuoted(schema) << ".";
757-
}
758-
drop_table << duckdb::KeywordHelper::WriteOptionallyQuoted(table_name);
759-
return drop_table.str();
760-
}
761-
762-
AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, const char *schema,
772+
AdbcStatusCode Ingest(duckdb_connection connection, const char *catalog, const char *table_name, const char *schema,
763773
struct ArrowArrayStream *input, struct AdbcError *error, IngestionMode ingestion_mode,
764774
bool temporary, int64_t *rows_affected) {
765775
if (!connection) {
@@ -775,10 +785,31 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, cons
775785
return ADBC_STATUS_INVALID_ARGUMENT;
776786
}
777787
if (schema && temporary) {
778-
// Temporary option is not supported with ADBC_INGEST_OPTION_TARGET_DB_SCHEMA or
779-
// ADBC_INGEST_OPTION_TARGET_CATALOG
788+
// Temporary option is not supported with ADBC_INGEST_OPTION_TARGET_DB_SCHEMA
780789
SetError(error, "Temporary option is not supported with schema");
781-
return ADBC_STATUS_INVALID_ARGUMENT;
790+
return ADBC_STATUS_INVALID_STATE;
791+
}
792+
if (catalog && temporary) {
793+
// Temporary option is not supported with ADBC_INGEST_OPTION_TARGET_CATALOG
794+
SetError(error, "Temporary option is not supported with catalog");
795+
return ADBC_STATUS_INVALID_STATE;
796+
}
797+
798+
// Resolve target name parts.
799+
// Used for both SQL generation (CREATE/DROP) and appender lookup.
800+
// Prefer explicit three-part names; two-part names can be ambiguous.
801+
const char *effective_catalog = catalog;
802+
const char *effective_schema = schema;
803+
if (temporary) {
804+
// Temporary tables live in the special "temp" catalog.
805+
// "CREATE TEMP TABLE" automatically places tables in temp.main.
806+
// For the appender, we need to explicitly target the temp catalog.
807+
effective_catalog = "temp";
808+
effective_schema = nullptr;
809+
} else if (catalog && !schema) {
810+
// Default schema for attached catalogs (DEFAULT_SCHEMA).
811+
// Use catalog.main.table to avoid catalog/schema name ambiguity.
812+
effective_schema = "main";
782813
}
783814

784815
duckdb::ArrowSchemaWrapper arrow_schema_wrapper;
@@ -800,7 +831,7 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, cons
800831
switch (ingestion_mode) {
801832
case IngestionMode::CREATE: {
802833
// CREATE mode: Create table, error if already exists
803-
auto sql = BuildCreateTableSQL(schema, table_name, types, names);
834+
auto sql = BuildCreateTableSQL(effective_catalog, effective_schema, table_name, types, names, false, temporary);
804835
duckdb_result result;
805836
if (duckdb_query(connection, sql.c_str(), &result) == DuckDBError) {
806837
const char *error_msg = duckdb_result_error(&result);
@@ -820,16 +851,10 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, cons
820851
// The appender will naturally fail if the table doesn't exist
821852
break;
822853
case IngestionMode::REPLACE: {
823-
// REPLACE mode: Drop table if exists, then create
824-
auto drop_sql = BuildDropTableSQL(schema, table_name);
825-
auto create_sql = BuildCreateTableSQL(schema, table_name, types, names);
854+
// REPLACE mode: CREATE OR REPLACE TABLE
855+
auto create_sql =
856+
BuildCreateTableSQL(effective_catalog, effective_schema, table_name, types, names, false, temporary, true);
826857
duckdb_result result;
827-
if (duckdb_query(connection, drop_sql.c_str(), &result) == DuckDBError) {
828-
SetError(error, duckdb_result_error(&result));
829-
duckdb_destroy_result(&result);
830-
return ADBC_STATUS_INTERNAL;
831-
}
832-
duckdb_destroy_result(&result);
833858
if (duckdb_query(connection, create_sql.c_str(), &result) == DuckDBError) {
834859
SetError(error, duckdb_result_error(&result));
835860
duckdb_destroy_result(&result);
@@ -840,7 +865,7 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, cons
840865
}
841866
case IngestionMode::CREATE_APPEND: {
842867
// CREATE_APPEND mode: Create if not exists, append if exists
843-
auto sql = BuildCreateTableSQL(schema, table_name, types, names, true);
868+
auto sql = BuildCreateTableSQL(effective_catalog, effective_schema, table_name, types, names, true, temporary);
844869
duckdb_result result;
845870
if (duckdb_query(connection, sql.c_str(), &result) == DuckDBError) {
846871
SetError(error, duckdb_result_error(&result));
@@ -851,7 +876,7 @@ AdbcStatusCode Ingest(duckdb_connection connection, const char *table_name, cons
851876
break;
852877
}
853878
}
854-
AppenderWrapper appender(connection, schema, table_name);
879+
AppenderWrapper appender(connection, effective_catalog, effective_schema, table_name);
855880
if (!appender.Valid()) {
856881
return ADBC_STATUS_INTERNAL;
857882
}
@@ -919,6 +944,7 @@ AdbcStatusCode StatementNew(struct AdbcConnection *connection, struct AdbcStatem
919944
statement_wrapper->statement = nullptr;
920945
statement_wrapper->ingestion_stream.release = nullptr;
921946
statement_wrapper->ingestion_table_name = nullptr;
947+
statement_wrapper->target_catalog = nullptr;
922948
statement_wrapper->db_schema = nullptr;
923949
statement_wrapper->temporary_table = false;
924950

@@ -943,6 +969,10 @@ AdbcStatusCode StatementRelease(struct AdbcStatement *statement, struct AdbcErro
943969
free(wrapper->ingestion_table_name);
944970
wrapper->ingestion_table_name = nullptr;
945971
}
972+
if (wrapper->target_catalog) {
973+
free(wrapper->target_catalog);
974+
wrapper->target_catalog = nullptr;
975+
}
946976
if (wrapper->db_schema) {
947977
free(wrapper->db_schema);
948978
wrapper->db_schema = nullptr;
@@ -1019,8 +1049,9 @@ static AdbcStatusCode IngestToTableFromBoundStream(DuckDBAdbcStatementWrapper *s
10191049
auto stream = statement->ingestion_stream;
10201050

10211051
// Ingest into a table from the bound stream
1022-
return Ingest(statement->connection, statement->ingestion_table_name, statement->db_schema, &stream, error,
1023-
statement->ingestion_mode, statement->temporary_table, rows_affected);
1052+
return Ingest(statement->connection, statement->target_catalog, statement->ingestion_table_name,
1053+
statement->db_schema, &stream, error, statement->ingestion_mode, statement->temporary_table,
1054+
rows_affected);
10241055
}
10251056

10261057
AdbcStatusCode StatementExecuteQuery(struct AdbcStatement *statement, struct ArrowArrayStream *out,
@@ -1354,15 +1385,25 @@ AdbcStatusCode StatementSetOption(struct AdbcStatement *statement, const char *k
13541385
auto wrapper = static_cast<DuckDBAdbcStatementWrapper *>(statement->private_data);
13551386

13561387
if (strcmp(key, ADBC_INGEST_OPTION_TARGET_TABLE) == 0) {
1388+
if (wrapper->ingestion_table_name) {
1389+
free(wrapper->ingestion_table_name);
1390+
}
13571391
wrapper->ingestion_table_name = strdup(value);
1358-
wrapper->temporary_table = false;
13591392
return ADBC_STATUS_OK;
13601393
}
13611394
if (strcmp(key, ADBC_INGEST_OPTION_TEMPORARY) == 0) {
13621395
if (strcmp(value, ADBC_OPTION_VALUE_ENABLED) == 0) {
1396+
// Align with arrow-adbc PostgreSQL driver behavior: if a schema was set
1397+
// before enabling temporary ingestion, clear it so temporary can proceed.
1398+
// (Some clients set schema by default.)
13631399
if (wrapper->db_schema) {
1364-
SetError(error, "Temporary option is not supported with schema");
1365-
return ADBC_STATUS_INVALID_ARGUMENT;
1400+
free(wrapper->db_schema);
1401+
wrapper->db_schema = nullptr;
1402+
}
1403+
// Some clients may also set a catalog by default; clear it so temporary can proceed.
1404+
if (wrapper->target_catalog) {
1405+
free(wrapper->target_catalog);
1406+
wrapper->target_catalog = nullptr;
13661407
}
13671408
wrapper->temporary_table = true;
13681409
return ADBC_STATUS_OK;
@@ -1378,14 +1419,21 @@ AdbcStatusCode StatementSetOption(struct AdbcStatement *statement, const char *k
13781419
}
13791420

13801421
if (strcmp(key, ADBC_INGEST_OPTION_TARGET_DB_SCHEMA) == 0) {
1381-
if (wrapper->temporary_table) {
1382-
SetError(error, "Temporary option is not supported with schema");
1383-
return ADBC_STATUS_INVALID_ARGUMENT;
1422+
if (wrapper->db_schema) {
1423+
free(wrapper->db_schema);
13841424
}
13851425
wrapper->db_schema = strdup(value);
13861426
return ADBC_STATUS_OK;
13871427
}
13881428

1429+
if (strcmp(key, ADBC_INGEST_OPTION_TARGET_CATALOG) == 0) {
1430+
if (wrapper->target_catalog) {
1431+
free(wrapper->target_catalog);
1432+
}
1433+
wrapper->target_catalog = strdup(value);
1434+
return ADBC_STATUS_OK;
1435+
}
1436+
13891437
if (strcmp(key, ADBC_INGEST_OPTION_MODE) == 0) {
13901438
if (strcmp(value, ADBC_INGEST_OPTION_MODE_CREATE) == 0) {
13911439
wrapper->ingestion_mode = IngestionMode::CREATE;

src/duckdb/src/execution/physical_plan_generator.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,4 +185,11 @@ PhysicalOperator &PhysicalPlanGenerator::CreatePlan(LogicalOperator &op) {
185185
throw InternalException("Physical plan generator - no plan generated");
186186
}
187187

188+
ArenaAllocator &PhysicalPlanGenerator::ArenaRef() {
189+
if (!physical_plan) {
190+
physical_plan = make_uniq<PhysicalPlan>(Allocator::Get(context));
191+
}
192+
return physical_plan->ArenaRef();
193+
}
194+
188195
} // namespace duckdb

src/duckdb/src/function/table/version/pragma_version.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#ifndef DUCKDB_PATCH_VERSION
2-
#define DUCKDB_PATCH_VERSION "0-dev5446"
2+
#define DUCKDB_PATCH_VERSION "0-dev5469"
33
#endif
44
#ifndef DUCKDB_MINOR_VERSION
55
#define DUCKDB_MINOR_VERSION 5
@@ -8,10 +8,10 @@
88
#define DUCKDB_MAJOR_VERSION 1
99
#endif
1010
#ifndef DUCKDB_VERSION
11-
#define DUCKDB_VERSION "v1.5.0-dev5446"
11+
#define DUCKDB_VERSION "v1.5.0-dev5469"
1212
#endif
1313
#ifndef DUCKDB_SOURCE_ID
14-
#define DUCKDB_SOURCE_ID "13e1f2229c"
14+
#define DUCKDB_SOURCE_ID "f5174f0d6d"
1515
#endif
1616
#include "duckdb/function/table/system_functions.hpp"
1717
#include "duckdb/main/database.hpp"

src/duckdb/src/include/duckdb.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3456,6 +3456,20 @@ This allows NULL values to be written to the vector, regardless of whether a val
34563456
*/
34573457
DUCKDB_C_API void duckdb_vector_ensure_validity_writable(duckdb_vector vector);
34583458

3459+
/*!
3460+
Safely assigns a string element in the vector at the specified location. Supersedes
3461+
`duckdb_vector_assign_string_element`. The vector type must be VARCHAR and the input must be valid UTF-8. Otherwise, it
3462+
returns an invalid Unicode error.
3463+
3464+
* @param vector The vector to alter
3465+
* @param index The row position in the vector to assign the string to
3466+
* @param str The null-terminated string
3467+
* @return If valid UTF-8, then `nullptr`, else error information. If not `nullptr`, then the return value must be
3468+
destroyed with `duckdb_destroy_error_data`.
3469+
*/
3470+
DUCKDB_C_API duckdb_error_data duckdb_vector_safe_assign_string_element(duckdb_vector vector, idx_t index,
3471+
const char *str);
3472+
34593473
/*!
34603474
Assigns a string element in the vector at the specified location.
34613475

src/duckdb/src/include/duckdb/common/adbc/adbc.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,18 @@ namespace duckdb_adbc {
1818

1919
class AppenderWrapper {
2020
public:
21-
AppenderWrapper(duckdb_connection conn, const char *schema, const char *table) : appender(nullptr) {
22-
if (duckdb_appender_create(conn, schema, table, &appender) != DuckDBSuccess) {
23-
appender = nullptr;
21+
AppenderWrapper(duckdb_connection conn, const char *catalog, const char *schema, const char *table)
22+
: appender(nullptr) {
23+
// Note: duckdb_appender_create_ext allocates an internal wrapper even on failure.
24+
// If creation fails, make sure to destroy it to avoid leaking.
25+
auto created = duckdb_appender(nullptr);
26+
if (duckdb_appender_create_ext(conn, catalog, schema, table, &created) != DuckDBSuccess) {
27+
if (created) {
28+
duckdb_appender_destroy(&created);
29+
}
30+
return;
2431
}
32+
appender = created;
2533
}
2634
~AppenderWrapper() {
2735
if (appender) {

src/duckdb/src/include/duckdb/execution/physical_plan_generator.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ class PhysicalPlanGenerator {
100100
return physical_plan->Make<T>(std::forward<ARGS>(args)...);
101101
}
102102

103+
//! Get a reference to the ArenaAllocator of the underlying physical plan.
104+
//! Creates a new (empty) physical plan if none exists yet.
105+
ArenaAllocator &ArenaRef();
106+
103107
public:
104108
PhysicalOperator &ResolveDefaultsProjection(LogicalInsert &op, PhysicalOperator &child);
105109

src/duckdb/src/include/duckdb/main/capi/extension_api.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,7 @@ typedef struct {
671671
sel_t *(*duckdb_selection_vector_get_data_ptr)(duckdb_selection_vector sel);
672672
void (*duckdb_vector_copy_sel)(duckdb_vector src, duckdb_vector dst, duckdb_selection_vector sel, idx_t src_count,
673673
idx_t src_offset, idx_t dst_offset);
674+
duckdb_error_data (*duckdb_vector_safe_assign_string_element)(duckdb_vector vector, idx_t index, const char *str);
674675
} duckdb_ext_api_v1;
675676

676677
//===--------------------------------------------------------------------===//
@@ -1221,6 +1222,7 @@ inline duckdb_ext_api_v1 CreateAPIv1() {
12211222
result.duckdb_destroy_selection_vector = duckdb_destroy_selection_vector;
12221223
result.duckdb_selection_vector_get_data_ptr = duckdb_selection_vector_get_data_ptr;
12231224
result.duckdb_vector_copy_sel = duckdb_vector_copy_sel;
1225+
result.duckdb_vector_safe_assign_string_element = duckdb_vector_safe_assign_string_element;
12241226
return result;
12251227
}
12261228

src/duckdb/src/include/duckdb/storage/caching_file_system.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#pragma once
1010

1111
#include "duckdb/common/enums/cache_validation_mode.hpp"
12+
#include "duckdb/common/file_opener.hpp"
1213
#include "duckdb/common/file_open_flags.hpp"
1314
#include "duckdb/common/open_file_info.hpp"
1415
#include "duckdb/common/winapi.hpp"
@@ -35,7 +36,7 @@ struct CachingFileHandle {
3536

3637
public:
3738
DUCKDB_API CachingFileHandle(QueryContext context, CachingFileSystem &caching_file_system, const OpenFileInfo &path,
38-
FileOpenFlags flags, CachedFile &cached_file);
39+
FileOpenFlags flags, optional_ptr<FileOpener> opener, CachedFile &cached_file);
3940
DUCKDB_API ~CachingFileHandle();
4041

4142
public:
@@ -89,6 +90,8 @@ struct CachingFileHandle {
8990
OpenFileInfo path;
9091
//! Flags used to open the file
9192
FileOpenFlags flags;
93+
//! File opener, which contains file open context.
94+
optional_ptr<FileOpener> opener;
9295
//! Cache validation mode for this file
9396
CacheValidationMode validate;
9497
//! The associated CachedFile with cached ranges
@@ -119,9 +122,10 @@ class CachingFileSystem {
119122
public:
120123
DUCKDB_API static CachingFileSystem Get(ClientContext &context);
121124

122-
DUCKDB_API unique_ptr<CachingFileHandle> OpenFile(const OpenFileInfo &path, FileOpenFlags flags);
125+
DUCKDB_API unique_ptr<CachingFileHandle> OpenFile(const OpenFileInfo &path, FileOpenFlags flags,
126+
optional_ptr<FileOpener> opener = nullptr);
123127
DUCKDB_API unique_ptr<CachingFileHandle> OpenFile(QueryContext context, const OpenFileInfo &path,
124-
FileOpenFlags flags);
128+
FileOpenFlags flags, optional_ptr<FileOpener> opener = nullptr);
125129

126130
private:
127131
//! The Client FileSystem (needs to be client-specific so we can do, e.g., HTTPFS profiling)

0 commit comments

Comments
 (0)