Skip to content

Commit

Permalink
Allow installation in alternate schema w/o search_path hacking. Closes
Browse files Browse the repository at this point in the history
  • Loading branch information
pramsey committed Feb 24, 2022
1 parent e8f5d60 commit 68396fe
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 27 deletions.
20 changes: 12 additions & 8 deletions http--1.4.sql
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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';


78 changes: 60 additions & 18 deletions http.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,12 @@
#include <postgres.h>
#include <fmgr.h>
#include <funcapi.h>
#include <access/genam.h>
#include <access/htup.h>
#include <access/table.h>
#include <catalog/namespace.h>
#include <catalog/pg_type.h>
#include <catalog/pg_extension.h>
#include <catalog/dependency.h>
#include <commands/extension.h>
#include <lib/stringinfo.h>
Expand All @@ -58,6 +61,7 @@
#include <utils/lsyscache.h>
#include <utils/syscache.h>
#include <utils/typcache.h>
#include <utils/fmgroids.h>
#include <utils/guc.h>

#if PG_VERSION_NUM >= 100000
Expand Down Expand Up @@ -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
Expand All @@ -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);
}
}

Expand Down Expand Up @@ -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);
Expand Down
1 change: 0 additions & 1 deletion http.control
Original file line number Diff line number Diff line change
@@ -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.'

0 comments on commit 68396fe

Please # to comment.