Skip to content

Commit c613b0f

Browse files
committed
Allow extension owned rest catalog to alter server options
This means any type 'rest' server (extension or user-owned) will use GUC options as default, and change any option to the ones set on the server. This eliminates the need of the function IsRestCatalogOwnedByUsers Instead we just have IsRestCatalog function. This also eliminates the need of GetRestCatalogConnectionFromGUCs Instead we just have GetRestCatalogConnectionFromServer - this function uses GUC values as defaults for all type 'rest' servers. Signed-off-by: sfc-gh-npuka <naisila.puka@snowflake.com>
1 parent 6c5e4bd commit c613b0f

7 files changed

Lines changed: 44 additions & 109 deletions

File tree

pg_lake_engine/include/pg_lake/util/catalog_type.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,4 @@ extern PGDLLEXPORT bool HasRestCatalogTableOption(List *options);
6262
extern PGDLLEXPORT bool HasObjectStoreCatalogTableOption(List *options);
6363
extern PGDLLEXPORT bool HasReadOnlyOption(List *options);
6464
extern PGDLLEXPORT bool IsCatalogOwnedByExtension(const char *catalog);
65-
extern PGDLLEXPORT bool IsRestCatalogOwnedByExtension(const char *catalog);
66-
extern PGDLLEXPORT bool IsRestCatalogOwnedByUsers(List *options);
65+
extern PGDLLEXPORT bool IsRestCatalog(const char *catalog);

pg_lake_engine/src/utils/catalog_type.c

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -77,13 +77,7 @@ HasRestCatalogTableOption(List *options)
7777
{
7878
char *catalog = GetStringOption(options, "catalog", false);
7979

80-
if (catalog == NULL)
81-
return false;
82-
83-
if (IsRestCatalogOwnedByExtension(catalog))
84-
return true;
85-
86-
return IsRestCatalogOwnedByUsers(options);
80+
return IsRestCatalog(catalog);
8781
}
8882

8983

@@ -113,46 +107,32 @@ HasReadOnlyOption(List *options)
113107
}
114108

115109

116-
/*
117-
* IsRestCatalogOwnedByExtension returns true if the catalog name matches
118-
* the extension-owned 'rest' catalog literal.
119-
*/
120-
bool
121-
IsRestCatalogOwnedByExtension(const char *catalog)
122-
{
123-
return pg_strncasecmp(catalog, REST_CATALOG_NAME, strlen(REST_CATALOG_NAME)) == 0;
124-
}
125-
126-
127110
/*
128111
* IsCatalogOwnedByExtension returns true if the catalog name is one of the
129112
* extension-owned literals: 'rest', 'object_store', or 'postgres'.
130113
*/
131114
bool
132115
IsCatalogOwnedByExtension(const char *catalog)
133116
{
134-
return IsRestCatalogOwnedByExtension(catalog) ||
117+
return pg_strncasecmp(catalog, REST_CATALOG_NAME, strlen(REST_CATALOG_NAME)) == 0 ||
135118
pg_strncasecmp(catalog, OBJECT_STORE_CATALOG_NAME, strlen(OBJECT_STORE_CATALOG_NAME)) == 0 ||
136119
pg_strncasecmp(catalog, POSTGRES_CATALOG_NAME, strlen(POSTGRES_CATALOG_NAME)) == 0;
137120
}
138121

139122

140123
/*
141-
* IsRestCatalogOwnedByUsers returns true if the catalog option refers to a
142-
* ForeignServer created by the user with the iceberg_catalog FDW whose TYPE is 'rest'.
143-
* Returns false if the catalog is owned by the extension ('rest',
144-
* 'object_store', 'postgres') or if no matching server is found.
124+
* IsRestCatalog returns true if the catalog name identifies a REST catalog.
125+
* This includes the extension-owned 'rest' literal and any user-created
126+
* iceberg_catalog server whose TYPE is 'rest' (or omitted, defaulting to 'rest').
145127
*/
146128
bool
147-
IsRestCatalogOwnedByUsers(List *options)
129+
IsRestCatalog(const char *catalog)
148130
{
149-
char *catalog = GetStringOption(options, "catalog", false);
150-
151131
if (catalog == NULL)
152132
return false;
153133

154-
if (IsCatalogOwnedByExtension(catalog))
155-
return false;
134+
if (pg_strncasecmp(catalog, REST_CATALOG_NAME, strlen(REST_CATALOG_NAME)) == 0)
135+
return true;
156136

157137
/* Try to look up a server with this name */
158138
bool missingOK = true;

pg_lake_iceberg/include/pg_lake/rest_catalog/rest_catalog.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,13 @@ extern int RestCatalogAuthType;
3636
extern bool RestCatalogEnableVendedCredentials;
3737

3838
/*
39-
* Holds per-server REST catalog connection settings. Can be populated from
40-
* GUCs (for backward-compatible catalog='rest') or from a ForeignServer
41-
* created via CREATE SERVER ... FOREIGN DATA WRAPPER iceberg_catalog.
39+
* Holds per-server REST catalog connection settings. Populated from the
40+
* server options of an iceberg_catalog ForeignServer, with GUC fallback
41+
* for any option not explicitly set on the server.
4242
*/
4343
typedef struct RestCatalogConnectionInfo
4444
{
45-
char *serverName; /* server name for cache keying, NULL for
46-
* GUC-based */
45+
char *serverName; /* server name, used for token cache keying */
4746
char *host;
4847
char *oauthHostPath;
4948
char *clientId;
@@ -97,7 +96,6 @@ typedef struct RestCatalogRequest
9796
#define GET_REST_CATALOG_METADATA_LOCATION "%s/api/catalog/v1/%s/namespaces/%s/tables/%s"
9897

9998
/* Connection info resolution */
100-
extern PGDLLEXPORT RestCatalogConnectionInfo * GetRestCatalogConnectionFromGUCs(void);
10199
extern PGDLLEXPORT RestCatalogConnectionInfo * GetRestCatalogConnectionFromServer(const char *serverName);
102100
extern PGDLLEXPORT RestCatalogConnectionInfo * GetRestCatalogConnectionForRelation(Oid relationId);
103101

pg_lake_iceberg/src/rest_catalog/rest_catalog.c

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -291,37 +291,20 @@ ProtectExtensionCatalogServersHandler(ProcessUtilityParams *processUtilityParams
291291
}
292292

293293

294-
/*
295-
* GetRestCatalogConnectionFromGUCs returns a RestCatalogConnectionInfo
296-
* populated from the current GUC variables. Used for backward-compatible
297-
* catalog='rest' tables.
298-
*/
299-
RestCatalogConnectionInfo *
300-
GetRestCatalogConnectionFromGUCs(void)
301-
{
302-
RestCatalogConnectionInfo *conn = palloc0(sizeof(RestCatalogConnectionInfo));
303-
304-
conn->serverName = REST_CATALOG_NAME;
305-
conn->host = RestCatalogHost;
306-
conn->oauthHostPath = RestCatalogOauthHostPath;
307-
conn->clientId = RestCatalogClientId;
308-
conn->clientSecret = RestCatalogClientSecret;
309-
conn->scope = RestCatalogScope;
310-
conn->authType = RestCatalogAuthType;
311-
conn->enableVendedCredentials = RestCatalogEnableVendedCredentials;
312-
313-
return conn;
314-
}
315-
316-
317294
/*
318295
* GetRestCatalogConnectionFromServer returns a RestCatalogConnectionInfo
319-
* populated from the options of a ForeignServer (non-secret config) and
320-
* its USER MAPPING (credentials) for the current user.
296+
* populated from the options of the named ForeignServer. GUC values are
297+
* used as defaults; any option explicitly set on the server overrides the
298+
* corresponding GUC. This applies to both the extension-owned 'rest'
299+
* server and user-created iceberg_catalog servers.
321300
*/
322301
RestCatalogConnectionInfo *
323302
GetRestCatalogConnectionFromServer(const char *serverName)
324303
{
304+
/* Normalize case-insensitive match to the canonical pre-created name */
305+
if (pg_strcasecmp(serverName, REST_CATALOG_NAME) == 0)
306+
serverName = REST_CATALOG_NAME;
307+
325308
ForeignServer *server = GetForeignServerByName(serverName, false);
326309
ForeignDataWrapper *fdw = GetForeignDataWrapper(server->fdwid);
327310

@@ -335,14 +318,14 @@ GetRestCatalogConnectionFromServer(const char *serverName)
335318

336319
conn->serverName = pstrdup(serverName);
337320

338-
/* Set defaults matching the GUC defaults */
339-
conn->host = NULL;
340-
conn->oauthHostPath = "";
341-
conn->clientId = NULL;
342-
conn->clientSecret = NULL;
343-
conn->scope = "PRINCIPAL_ROLE:ALL";
344-
conn->authType = REST_CATALOG_AUTH_TYPE_DEFAULT;
345-
conn->enableVendedCredentials = true;
321+
/* GUC values serve as defaults; server options override below */
322+
conn->host = RestCatalogHost;
323+
conn->oauthHostPath = RestCatalogOauthHostPath;
324+
conn->clientId = RestCatalogClientId;
325+
conn->clientSecret = RestCatalogClientSecret;
326+
conn->scope = RestCatalogScope;
327+
conn->authType = RestCatalogAuthType;
328+
conn->enableVendedCredentials = RestCatalogEnableVendedCredentials;
346329

347330
ListCell *lc;
348331

@@ -372,7 +355,7 @@ GetRestCatalogConnectionFromServer(const char *serverName)
372355
conn->enableVendedCredentials = defGetBoolean(def);
373356
}
374357

375-
if (conn->host == NULL)
358+
if (conn->host == NULL || conn->host[0] == '\0')
376359
ereport(ERROR,
377360
(errcode(ERRCODE_FDW_OPTION_NAME_NOT_FOUND),
378361
errmsg("\"rest_endpoint\" option is required for iceberg_catalog server \"%s\"",
@@ -384,9 +367,9 @@ GetRestCatalogConnectionFromServer(const char *serverName)
384367

385368
/*
386369
* GetRestCatalogConnectionForRelation returns the REST catalog connection
387-
* info for the given relation. If the table uses catalog='rest', the
388-
* connection is built from GUCs. Otherwise, the catalog option is treated
389-
* as a server name and the connection is built from its options.
370+
* info for the given relation. The catalog option value is used as the
371+
* server name. For the extension-owned 'rest' server and user-created
372+
* servers alike, server options are read first with GUC fallback.
390373
*/
391374
RestCatalogConnectionInfo *
392375
GetRestCatalogConnectionForRelation(Oid relationId)
@@ -399,9 +382,6 @@ GetRestCatalogConnectionForRelation(Oid relationId)
399382
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
400383
errmsg("catalog option is not set for relation %u", relationId)));
401384

402-
if (IsRestCatalogOwnedByExtension(catalog))
403-
return GetRestCatalogConnectionFromGUCs();
404-
405385
return GetRestCatalogConnectionFromServer(catalog);
406386
}
407387

pg_lake_iceberg/src/test/rest_catalog.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ register_namespace_to_rest_catalog(PG_FUNCTION_ARGS)
3737
char *catalogName = text_to_cstring(PG_GETARG_TEXT_P(0));
3838
char *namespaceName = text_to_cstring(PG_GETARG_TEXT_P(1));
3939

40-
RestCatalogConnectionInfo *conn = GetRestCatalogConnectionFromGUCs();
40+
RestCatalogConnectionInfo *conn = GetRestCatalogConnectionFromServer(REST_CATALOG_NAME);
4141

4242
RegisterNamespaceToRestCatalog(conn, catalogName, namespaceName);
4343
PG_RETURN_VOID();

pg_lake_table/src/ddl/create_table.c

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -720,12 +720,8 @@ ProcessCreateIcebergTableFromForeignTableStmt(ProcessUtilityParams * params)
720720
if (hasRestCatalogOption && hasExternalCatalogReadOnlyOption)
721721
{
722722
char *catalogOptionValue = GetStringOption(createStmt->options, "catalog", false);
723-
RestCatalogConnectionInfo *conn;
724-
725-
if (IsRestCatalogOwnedByExtension(catalogOptionValue))
726-
conn = GetRestCatalogConnectionFromGUCs();
727-
else
728-
conn = GetRestCatalogConnectionFromServer(catalogOptionValue);
723+
RestCatalogConnectionInfo *conn =
724+
GetRestCatalogConnectionFromServer(catalogOptionValue);
729725

730726
ErrorIfRestNamespaceDoesNotExist(conn, catalogName, catalogNamespace);
731727

@@ -936,12 +932,8 @@ ProcessCreateIcebergTableFromForeignTableStmt(ProcessUtilityParams * params)
936932
* etc., but here we need to do it early before the table is created.
937933
*/
938934
char *catalogOptionValue = GetStringOption(createStmt->options, "catalog", false);
939-
RestCatalogConnectionInfo *conn;
940-
941-
if (IsRestCatalogOwnedByExtension(catalogOptionValue))
942-
conn = GetRestCatalogConnectionFromGUCs();
943-
else
944-
conn = GetRestCatalogConnectionFromServer(catalogOptionValue);
935+
RestCatalogConnectionInfo *conn =
936+
GetRestCatalogConnectionFromServer(catalogOptionValue);
945937

946938
RegisterNamespaceToRestCatalog(conn, get_database_name(MyDatabaseId),
947939
get_namespace_name(namespaceId));

pg_lake_table/src/fdw/option.c

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -742,11 +742,7 @@ pg_lake_iceberg_validator(PG_FUNCTION_ARGS)
742742
{
743743
char *icebergCatalogName = defGetString(def);
744744

745-
/*
746-
* We only accept "rest" and "postgres" for now. If not provided,
747-
* assume "postgres" by default. Don't allow anything.
748-
*/
749-
if (pg_strncasecmp(icebergCatalogName, REST_CATALOG_NAME, strlen(icebergCatalogName)) == 0)
745+
if (IsRestCatalog(icebergCatalogName))
750746
{
751747
/*
752748
* at this point, we cannot tell whether it's read only or
@@ -757,7 +753,6 @@ pg_lake_iceberg_validator(PG_FUNCTION_ARGS)
757753
}
758754
else if (pg_strncasecmp(icebergCatalogName, OBJECT_STORE_CATALOG_NAME, strlen(icebergCatalogName)) == 0)
759755
{
760-
761756
/*
762757
* at this point, we cannot tell whether it's read only or
763758
* read write. We'll determine that later based on the
@@ -768,20 +763,11 @@ pg_lake_iceberg_validator(PG_FUNCTION_ARGS)
768763
else if (pg_strncasecmp(icebergCatalogName, POSTGRES_CATALOG_NAME, strlen(icebergCatalogName)) == 0)
769764
icebergCatalogType = POSTGRES_CATALOG;
770765
else
771-
{
772-
/*
773-
* Check if the catalog value refers to an iceberg_catalog
774-
* server. If so, treat it as a REST catalog.
775-
*/
776-
if (IsRestCatalogOwnedByUsers(options_list))
777-
icebergCatalogType = REST_CATALOG_READ_ONLY;
778-
else
779-
ereport(ERROR,
780-
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
781-
errmsg("invalid catalog option: %s", icebergCatalogName),
782-
errdetail("Use \"rest\", \"object_store\", \"postgres\", "
783-
"or the name of an iceberg_catalog server.")));
784-
}
766+
ereport(ERROR,
767+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
768+
errmsg("invalid catalog option: %s", icebergCatalogName),
769+
errdetail("Use \"rest\", \"object_store\", \"postgres\", "
770+
"or the name of an iceberg_catalog server.")));
785771
}
786772
else if (catalog == ForeignTableRelationId && strcmp(def->defname, "read_only") == 0)
787773
{

0 commit comments

Comments
 (0)