Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
| `iceberg` | Apache Iceberg support | Installable |
| `delta` | Delta Lake support | Installable |
| `azure` | Azure Blob Storage connectivity | Installable |
| `excel` | Excel Xlsx file support | Installable |
| Community | Various community extensions | Installable (requires configuration) |
| `gsheets` | GSheets from GDrive file support | Installable (requires configuration) |

Installing other extensions may work, but they have not been thoroughly tested and are used at your own risk

Expand Down Expand Up @@ -42,6 +44,11 @@ SELECT duckdb.install_extension('prql', 'community');
SET duckdb.allow_unsigned_extensions = true;
```

**Note**: Recycling of the DuckDb might be required:
```sql
CALL duckdb.recycle_ddb();
```

## Managing Extensions

Installing an extension causes it to be loaded and installed globally for any connection that uses DuckDB. The current list of installed extensions is maintained in the `duckdb.extensions` table. Superusers can use this table to view and manage extensions:
Expand Down
14 changes: 14 additions & 0 deletions docs/secrets.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,20 @@ SELECT duckdb.create_azure_secret(
);
```

For GSheets secrets you may use:
```sql
SELECT duckdb.create_gsheet_secret(
'key_file', '/path/to/credential.json'
);
```
Or
```sql
SELECT duckdb.create_gsheet_secret(
'access_token', 'my-secret-token'
);
```


## Secrets with `credential_chain` provider:

For more advanced use-cases, one can define secrets with a `SERVER` (and `USER MAPPING`) on `duckdb` Foreign Data Wrapper:
Expand Down
54 changes: 54 additions & 0 deletions sql/pg_duckdb--1.0.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,52 @@ SET search_path = pg_catalog, pg_temp
AS 'MODULE_PATHNAME', 'duckdb_only_function'
LANGUAGE C;

-- read_xlsx function for single path
CREATE FUNCTION @extschema@.read_xlsx(path text, header BOOLEAN DEFAULT NULL,
sheet TEXT DEFAULT NULL,
all_varchar BOOLEAN DEFAULT FALSE,
ignore_errors BOOLEAN DEFAULT FALSE,
range TEXT DEFAULT NULL,
stop_at_empty BOOLEAN DEFAULT NULL,
empty_as_varchar BOOLEAN DEFAULT FALSE)
RETURNS SETOF duckdb.row
SET search_path = pg_catalog, pg_temp
AS 'MODULE_PATHNAME', 'duckdb_only_function'
LANGUAGE C;

-- read_xlsx function for array of paths
CREATE FUNCTION @extschema@.read_xlsx(path text[], header BOOLEAN DEFAULT NULL,
sheet TEXT DEFAULT NULL,
all_varchar BOOLEAN DEFAULT FALSE,
ignore_errors BOOLEAN DEFAULT FALSE,
range TEXT DEFAULT NULL,
stop_at_empty BOOLEAN DEFAULT NULL,
empty_as_varchar BOOLEAN DEFAULT FALSE)
RETURNS SETOF duckdb.row
SET search_path = pg_catalog, pg_temp
AS 'MODULE_PATHNAME', 'duckdb_only_function'
LANGUAGE C;

-- read_gsheet function for single path
CREATE FUNCTION @extschema@.read_gsheet(path text, header BOOLEAN DEFAULT NULL,
sheet TEXT DEFAULT NULL,
all_varchar BOOLEAN DEFAULT FALSE,
range TEXT DEFAULT NULL)
RETURNS SETOF duckdb.row
SET search_path = pg_catalog, pg_temp
AS 'MODULE_PATHNAME', 'duckdb_only_function'
LANGUAGE C;

-- read_gsheet function for array of paths
CREATE FUNCTION @extschema@.read_gsheet(path text[], header BOOLEAN DEFAULT NULL,
sheet TEXT DEFAULT NULL,
all_varchar BOOLEAN DEFAULT FALSE,
range TEXT DEFAULT NULL)
RETURNS SETOF duckdb.row
SET search_path = pg_catalog, pg_temp
AS 'MODULE_PATHNAME', 'duckdb_only_function'
LANGUAGE C;

-- read_csv function for single path
CREATE FUNCTION @extschema@.read_csv(path text, all_varchar BOOLEAN DEFAULT FALSE,
allow_quoted_nulls BOOLEAN DEFAULT TRUE,
Expand Down Expand Up @@ -1867,6 +1913,14 @@ RETURNS TEXT
SET search_path = pg_catalog, pg_temp
LANGUAGE C AS 'MODULE_PATHNAME', 'pgduckdb_create_azure_secret';

CREATE FUNCTION duckdb.create_gsheet_secret(
provider text,
credential text
)
RETURNS text
LANGUAGE c
AS 'MODULE_PATHNAME', 'pgduckdb_create_gsheet_secret';

CREATE FUNCTION duckdb.view(dbname text, schema text, view_name text, query text)
RETURNS SETOF duckdb.row
SET search_path = pg_catalog, pg_temp
Expand Down
50 changes: 50 additions & 0 deletions src/pgduckdb_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,56 @@ DECLARE_PG_FUNCTION(pgduckdb_create_azure_secret) {
PG_RETURN_TEXT_P(result);
}

DECLARE_PG_FUNCTION(pgduckdb_create_gsheet_secret) {
auto provider_type = pgduckdb::pg::GetArgString(fcinfo, 0);
auto credential = pgduckdb::pg::GetArgString(fcinfo, 1);
auto lc_provider = duckdb::StringUtil::Lower(provider_type);

if (lc_provider != "key_file" && lc_provider != "access_token") {
elog(ERROR,
"Invalid provider '%s'. For gsheet, supported providers are 'key_file' or 'access_token'.",
provider_type.c_str());
}

std::string secret_name_prefix = "gsheet_secret";
SPI_connect();
auto server_name = pgduckdb::FindServerName(secret_name_prefix.c_str());
{
std::ostringstream create_server_query;
create_server_query << "CREATE SERVER " << server_name
<< " TYPE 'gsheet' FOREIGN DATA WRAPPER duckdb";

auto ret = SPI_exec(create_server_query.str().c_str(), 0);
if (ret != SPI_OK_UTILITY) {
elog(ERROR, "Could not create 'gsheet' SERVER: %s", SPI_result_code_string(ret));
}
}
{
std::ostringstream create_mapping_query;
create_mapping_query << "CREATE USER MAPPING FOR CURRENT_USER SERVER "
<< server_name << " OPTIONS (";

create_mapping_query << "PROVIDER " << duckdb::KeywordHelper::WriteQuoted(lc_provider) << ", ";

if (lc_provider == "key_file") {
create_mapping_query << "FILEPATH " << duckdb::KeywordHelper::WriteQuoted(credential);
} else {
create_mapping_query << "TOKEN " << duckdb::KeywordHelper::WriteQuoted(credential);
}

create_mapping_query << ");";

auto ret = SPI_exec(create_mapping_query.str().c_str(), 0);
if (ret != SPI_OK_UTILITY) {
elog(ERROR, "Could not create 'gsheet' USER MAPPING: %s", SPI_result_code_string(ret));
}
}

SPI_finish();
auto result = cstring_to_text(server_name.c_str());
PG_RETURN_TEXT_P(result);
}

/*
* We need these dummy cache functions so that people are able to load the
* new pg_duckdb.so file with an old SQL version (where these functions still
Expand Down
Loading