From 68396fe0f6ca050e146d977c70487b661c517b0f Mon Sep 17 00:00:00 2001 From: Paul Ramsey Date: Thu, 24 Feb 2022 09:58:39 -0800 Subject: [PATCH] Allow installation in alternate schema w/o search_path hacking. Closes #122 --- http--1.4.sql | 20 +++++++------ http.c | 78 +++++++++++++++++++++++++++++++++++++++------------ http.control | 1 - 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/http--1.4.sql b/http--1.4.sql index db7e8b9..f6054b7 100644 --- a/http--1.4.sql +++ b/http--1.4.sql @@ -63,32 +63,32 @@ CREATE OR REPLACE FUNCTION http(request http_request) CREATE OR REPLACE FUNCTION http_get(uri VARCHAR) RETURNS http_response - AS $$ SELECT http(('GET', $1, NULL, NULL, NULL)::http_request) $$ + AS $$ SELECT @extschema@.http(('GET', $1, NULL, NULL, NULL)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_post(uri VARCHAR, content VARCHAR, content_type VARCHAR) RETURNS http_response - AS $$ SELECT http(('POST', $1, NULL, $3, $2)::http_request) $$ + AS $$ SELECT @extschema@.http(('POST', $1, NULL, $3, $2)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_put(uri VARCHAR, content VARCHAR, content_type VARCHAR) RETURNS http_response - AS $$ SELECT http(('PUT', $1, NULL, $3, $2)::http_request) $$ + AS $$ SELECT @extschema@.http(('PUT', $1, NULL, $3, $2)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_patch(uri VARCHAR, content VARCHAR, content_type VARCHAR) RETURNS http_response - AS $$ SELECT http(('PATCH', $1, NULL, $3, $2)::http_request) $$ + AS $$ SELECT @extschema@.http(('PATCH', $1, NULL, $3, $2)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_delete(uri VARCHAR) RETURNS http_response - AS $$ SELECT http(('DELETE', $1, NULL, NULL, NULL)::http_request) $$ + AS $$ SELECT @extschema@.http(('DELETE', $1, NULL, NULL, NULL)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_head(uri VARCHAR) RETURNS http_response - AS $$ SELECT http(('HEAD', $1, NULL, NULL, NULL)::http_request) $$ + AS $$ SELECT @extschema@.http(('HEAD', $1, NULL, NULL, NULL)::@extschema@.http_request) $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION urlencode(string VARCHAR) @@ -111,12 +111,16 @@ CREATE OR REPLACE FUNCTION urlencode(data JSONB) CREATE OR REPLACE FUNCTION http_get(uri VARCHAR, data JSONB) RETURNS http_response - AS $$ SELECT http(('GET', $1 || '?' || urlencode($2), NULL, NULL, NULL)::http_request) $$ + AS $$ + SELECT @extschema@.http(('GET', $1 || '?' || urlencode($2), NULL, NULL, NULL)::@extschema@.http_request) + $$ LANGUAGE 'sql'; CREATE OR REPLACE FUNCTION http_post(uri VARCHAR, data JSONB) RETURNS http_response - AS $$ SELECT http(('POST', $1, NULL, 'application/x-www-form-urlencoded', urlencode($2))::http_request) $$ + AS $$ + SELECT @extschema@.http(('POST', $1, NULL, 'application/x-www-form-urlencoded', urlencode($2))::@extschema@.http_request) + $$ LANGUAGE 'sql'; diff --git a/http.c b/http.c index 514f35f..7c3ba76 100644 --- a/http.c +++ b/http.c @@ -43,9 +43,12 @@ #include #include #include +#include #include +#include #include #include +#include #include #include #include @@ -58,6 +61,7 @@ #include #include #include +#include #include #if PG_VERSION_NUM >= 100000 @@ -574,6 +578,43 @@ header_array_to_slist(ArrayType *array, struct curl_slist *headers) return headers; } +/** +* Look up the namespace the extension is installed in +*/ +static Oid +get_extension_schema(Oid ext_oid) +{ + Oid result; + Relation rel; + SysScanDesc scandesc; + HeapTuple tuple; + ScanKeyData entry[1]; + + rel = table_open(ExtensionRelationId, AccessShareLock); + + ScanKeyInit(&entry[0], + Anum_pg_extension_oid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(ext_oid)); + + scandesc = systable_beginscan(rel, ExtensionOidIndexId, true, + NULL, 1, entry); + + tuple = systable_getnext(scandesc); + + /* We assume that there can be at most one matching tuple */ + if (HeapTupleIsValid(tuple)) + result = ((Form_pg_extension) GETSTRUCT(tuple))->extnamespace; + else + result = InvalidOid; + + systable_endscan(scandesc); + + table_close(rel, AccessShareLock); + + return result; +} + /** * Look up the tuple description for a extension-defined type, * avoiding the pitfalls of using relations that are not part @@ -584,33 +625,30 @@ static TupleDesc typname_get_tupledesc(const char *extname, const char *typname) { Oid extoid = get_extension_oid(extname, true); - ListCell *l; + Oid extschemaoid; if ( ! OidIsValid(extoid) ) elog(ERROR, "could not lookup '%s' extension oid", extname); - foreach(l, fetch_search_path(true)) - { - Oid typnamespace = lfirst_oid(l); + extschemaoid = get_extension_schema(extoid); #if PG_VERSION_NUM >= 120000 - Oid typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, - PointerGetDatum(typname), - ObjectIdGetDatum(typnamespace)); + Oid typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, + PointerGetDatum(typname), + ObjectIdGetDatum(extschemaoid)); #else - Oid typoid = GetSysCacheOid2(TYPENAMENSP, - PointerGetDatum(typname), - ObjectIdGetDatum(typnamespace)); + Oid typoid = GetSysCacheOid2(TYPENAMENSP, + PointerGetDatum(typname), + ObjectIdGetDatum(extschemaoid)); #endif - if ( OidIsValid(typoid) ) + if ( OidIsValid(typoid) ) + { + // Oid typ_oid = get_typ_typrelid(rel_oid); + Oid relextoid = getExtensionOfObject(TypeRelationId, typoid); + if ( relextoid == extoid ) { - // Oid typ_oid = get_typ_typrelid(rel_oid); - Oid relextoid = getExtensionOfObject(TypeRelationId, typoid); - if ( relextoid == extoid ) - { - return TypeGetTupleDesc(typoid, NIL); - } + return TypeGetTupleDesc(typoid, NIL); } } @@ -1206,7 +1244,11 @@ Datum http_request(PG_FUNCTION_ARGS) } /* Prepare our return object */ - tup_desc = RelationNameGetTupleDesc("http_response"); + if (get_call_result_type(fcinfo, 0, &tup_desc) != TYPEFUNC_COMPOSITE) { + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("%s called with incompatible return type", __func__))); + } + ncolumns = tup_desc->natts; values = palloc0(sizeof(Datum)*ncolumns); nulls = palloc0(sizeof(bool)*ncolumns); diff --git a/http.control b/http.control index dc60809..ef36fec 100644 --- a/http.control +++ b/http.control @@ -1,4 +1,3 @@ default_version = '1.4' module_pathname = '$libdir/http' -relocatable = true comment = 'HTTP client for PostgreSQL, allows web page retrieval inside the database.'