@@ -68,7 +68,8 @@ int RestCatalogAuthType = REST_CATALOG_AUTH_TYPE_OAUTH2;
6868bool RestCatalogEnableVendedCredentials = true;
6969
7070/*
71- * Per-catalog token cache. Keyed by catalog.
71+ * Per-rest-catalog token cache. Keyed by catalog.
72+ * Should always be accessed via GetRestCatalogAccessToken()
7273 */
7374#define TOKEN_CACHE_KEY_LEN NAMEDATALEN
7475
@@ -82,6 +83,8 @@ typedef struct RestCatalogTokenCacheEntry
8283static HTAB * RestCatalogTokenCache = NULL ;
8384static MemoryContext RestTokenCacheCtx = NULL ;
8485
86+ /* end of per-catalog token cache variables */
87+
8588static char * GetRestCatalogAccessToken (RestCatalogOptions * opts , bool forceRefreshToken );
8689static void FetchRestCatalogAccessToken (RestCatalogOptions * opts , char * * accessToken , int * expiresIn );
8790static void CreateNamespaceOnRestCatalog (RestCatalogOptions * opts , const char * catalogName , const char * namespaceName );
@@ -723,8 +726,8 @@ StartStageRestCatalogIcebergTableCreate(Oid relationId)
723726 headers = lappend (headers , vendedCreds );
724727 }
725728
726- HttpResult httpResult = SendRequestToRestCatalog (HTTP_POST , postUrl , body -> data ,
727- headers , opts );
729+ HttpResult httpResult = SendRequestToRestCatalog (opts , HTTP_POST , postUrl , body -> data ,
730+ headers );
728731
729732 if (httpResult .status != 200 )
730733 {
@@ -859,9 +862,8 @@ RegisterNamespaceToRestCatalog(RestCatalogOptions * opts, const char *catalogNam
859862 psprintf (REST_CATALOG_NAMESPACE_NAME ,
860863 opts -> host , URLEncodePath (catalogName ),
861864 URLEncodePath (namespaceName ));
862- HttpResult httpResult = SendRequestToRestCatalog (HTTP_GET , getUrl , NULL ,
863- GetHeadersWithAuth (opts ),
864- opts );
865+ HttpResult httpResult = SendRequestToRestCatalog (opts , HTTP_GET , getUrl , NULL ,
866+ GetHeadersWithAuth (opts ));
865867
866868 switch (httpResult .status )
867869 {
@@ -951,9 +953,8 @@ ErrorIfRestNamespaceDoesNotExist(RestCatalogOptions * opts, const char *catalogN
951953 psprintf (REST_CATALOG_NAMESPACE_NAME ,
952954 opts -> host , URLEncodePath (catalogName ),
953955 URLEncodePath (namespaceName ));
954- HttpResult httpResult = SendRequestToRestCatalog (HTTP_GET , getUrl , NULL ,
955- GetHeadersWithAuth (opts ),
956- opts );
956+ HttpResult httpResult = SendRequestToRestCatalog (opts , HTTP_GET , getUrl , NULL ,
957+ GetHeadersWithAuth (opts ));
957958
958959 /* namespace not found */
959960 if (httpResult .status == 404 )
@@ -1002,8 +1003,7 @@ GetMetadataLocationFromRestCatalog(RestCatalogOptions * opts, const char *restCa
10021003 opts -> host , URLEncodePath (restCatalogName ), URLEncodePath (namespaceName ), URLEncodePath (relationName ));
10031004
10041005 List * headers = GetHeadersWithAuth (opts );
1005- HttpResult hr = SendRequestToRestCatalog (HTTP_GET , getUrl , NULL , headers ,
1006- opts );
1006+ HttpResult hr = SendRequestToRestCatalog (opts , HTTP_GET , getUrl , NULL , headers );
10071007
10081008 if (hr .status != 200 )
10091009 {
@@ -1051,9 +1051,8 @@ CreateNamespaceOnRestCatalog(RestCatalogOptions * opts, const char *catalogName,
10511051 psprintf (REST_CATALOG_NAMESPACE , opts -> host ,
10521052 URLEncodePath (catalogName ));
10531053
1054- HttpResult httpResult = SendRequestToRestCatalog (HTTP_POST , postUrl , body .data ,
1055- PostHeadersWithAuth (opts ),
1056- opts );
1054+ HttpResult httpResult = SendRequestToRestCatalog (opts , HTTP_POST , postUrl , body .data ,
1055+ PostHeadersWithAuth (opts ));
10571056
10581057 if (httpResult .status != 200 )
10591058 {
@@ -1155,6 +1154,12 @@ BuildTokenCacheKey(char *key, const RestCatalogOptions * opts)
11551154 * Any ALTER/DROP SERVER blows away the entire token cache so stale
11561155 * credentials are never reused. The cache is rebuilt lazily on the
11571156 * next token lookup.
1157+ *
1158+ * We ignore hashvalue and reset the whole cache rather than selectively
1159+ * invalidating a single server's entry (as postgres_fdw does). With a
1160+ * handful of servers and infrequent ALTER SERVER, the cost of a few
1161+ * extra OAuth round-trips is negligible compared to the complexity of
1162+ * keying the cache by OID for selective invalidation.
11581163 */
11591164static void
11601165InvalidateRestTokenCache (Datum arg , int cacheid , uint32 hashvalue )
@@ -1169,6 +1174,11 @@ InvalidateRestTokenCache(Datum arg, int cacheid, uint32 hashvalue)
11691174
11701175/*
11711176 * Initialize the per-catalog token cache hash table if needed.
1177+ *
1178+ * TokenCacheCallbackRegistered is separate from RestCatalogTokenCache because
1179+ * the callback must be registered exactly once per backend lifetime
1180+ * (CacheRegisterSyscacheCallback appends to a fixed-size array), while
1181+ * RestCatalogTokenCache is reset to NULL on every invalidation.
11721182 */
11731183static bool TokenCacheCallbackRegistered = false;
11741184
@@ -1318,10 +1328,14 @@ FetchRestCatalogAccessToken(RestCatalogOptions * opts, char **accessToken, int *
13181328
13191329 headers = lappend (headers , "Content-Type: application/x-www-form-urlencoded" );
13201330
1321- /* POST — pass NULL opts to skip 419 token refresh (avoids recursion) */
1322- HttpResult httpResponse = SendRequestToRestCatalog (HTTP_POST , accessTokenUrl ,
1323- body .data , headers ,
1324- NULL );
1331+ /*
1332+ * Pass NULL opts so SendRequestToRestCatalog skips the 419 token-refresh
1333+ * retry branch. Otherwise a 419 here would call
1334+ * GetRestCatalogAccessToken -> FetchRestCatalogAccessToken ->
1335+ * SendRequestToRestCatalog in an infinite loop.
1336+ */
1337+ HttpResult httpResponse = SendRequestToRestCatalog (NULL , HTTP_POST , accessTokenUrl ,
1338+ body .data , headers );
13251339
13261340 if (httpResponse .status != 200 )
13271341 ereport (ERROR ,
0 commit comments