Skip to content

Commit 6e40f6a

Browse files
committed
Add RELOID and TYPEOID portbility.
1 parent 1349c4e commit 6e40f6a

File tree

10 files changed

+329
-6
lines changed

10 files changed

+329
-6
lines changed

contrib/pg_execplan/init.sql

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
-- query - query string which will be parsed and planned.
55
-- filename - path to the file on a disk.
66
CREATE OR REPLACE FUNCTION @extschema@.pg_store_query_plan(
7-
query TEXT,
8-
filename TEXT)
7+
filename TEXT,
8+
query TEXT
9+
)
910
RETURNS VOID AS 'pg_execplan'
1011
LANGUAGE C;
1112

contrib/pg_execplan/pg_execplan.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ pg_store_query_plan(PG_FUNCTION_ARGS)
8383
fwrite(&string_len, sizeof(size_t), 1, fout);
8484
fwrite(query_string, sizeof(char), string_len, fout);
8585

86+
set_portable_output(true);
8687
plan_string = nodeToString(queryDesc->plannedstmt);
88+
set_portable_output(false);
8789
string_len = strlen(plan_string);
8890
fwrite(&string_len, sizeof(size_t), 1, fout);
8991
fwrite(plan_string, sizeof(char), string_len, fout);
@@ -135,7 +137,19 @@ pg_exec_query_plan(PG_FUNCTION_ARGS)
135137
int eflags = 0;
136138

137139
LoadPlanFromFile(filename, &query_string, &plan_string);
138-
pstmt = (PlannedStmt *) stringToNode(plan_string);
140+
141+
PG_TRY();
142+
{
143+
set_portable_input(true);
144+
pstmt = (PlannedStmt *) stringToNode(plan_string);
145+
set_portable_input(false);
146+
}
147+
PG_CATCH();
148+
{
149+
elog(INFO, "!!!BAD PLAN: %s", plan_string);
150+
PG_RE_THROW();
151+
}
152+
PG_END_TRY();
139153

140154
psrc = CreateCachedPlan(NULL, query_string, query_string);
141155
CompleteCachedPlan(psrc, NIL, NULL, NULL, 0, NULL, NULL,
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
-- Make dummy I/O routines using the existing internal support for int4, text
2+
CREATE FUNCTION int42_in(cstring)
3+
RETURNS int42
4+
AS 'int4in'
5+
LANGUAGE internal STRICT IMMUTABLE;
6+
CREATE FUNCTION int42_out(int42)
7+
RETURNS cstring
8+
AS 'int4out'
9+
LANGUAGE internal STRICT IMMUTABLE;
10+
11+
CREATE TYPE int42 (
12+
internallength = 4,
13+
input = int42_in,
14+
output = int42_out,
15+
alignment = int4,
16+
default = 42,
17+
passedbyvalue
18+
);
19+
20+
CREATE TABLE t1 (id int42);

contrib/pg_execplan/tests/rpl.sh

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#!/bin/bash
2+
3+
# Script for the plan passing between separate instances
4+
U=`whoami`
5+
6+
# Paths
7+
PGINSTALL=`pwd`/tmp_install/
8+
LD_LIBRARY_PATH=$PGINSTALL/lib
9+
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH
10+
export PATH=$PGINSTALL/bin:$PATH
11+
12+
pkill -9 postgres || true
13+
sleep 1
14+
rm -rf $PGINSTALL || true
15+
rm -rf PGDATA_Master || true
16+
rm -rf PGDATA_Slave || true
17+
rm -rf master.log || true
18+
rm -rf slave.log || true
19+
20+
# Building project
21+
make > /dev/null
22+
make -C contrib > /dev/null
23+
make install > /dev/null
24+
make -C contrib install > /dev/null
25+
26+
mkdir PGDATA_Master
27+
mkdir PGDATA_Slave
28+
initdb -D PGDATA_Master
29+
initdb -D PGDATA_Slave
30+
echo "shared_preload_libraries = 'postgres_fdw, pg_execplan'" >> PGDATA_Master/postgresql.conf
31+
echo "shared_preload_libraries = 'postgres_fdw, pg_execplan'" >> PGDATA_Slave/postgresql.conf
32+
33+
pg_ctl -w -D PGDATA_Master -o "-p 5432" -l master.log start
34+
pg_ctl -w -D PGDATA_Slave -o "-p 5433" -l slave.log start
35+
createdb $U -p 5432
36+
createdb $U -p 5433
37+
38+
psql -p 5432 -c "CREATE EXTENSION postgres_fdw;"
39+
psql -p 5433 -c "CREATE EXTENSION postgres_fdw;"
40+
psql -p 5432 -c "CREATE EXTENSION pg_execplan;"
41+
psql -p 5433 -c "CREATE EXTENSION pg_execplan;"
42+
43+
# shift oids
44+
psql -p 5433 -c "CREATE TABLE t0 (id int);"
45+
psql -p 5433 -c "DROP TABLE t0;"
46+
47+
#create database objects for check of oid switching
48+
psql -p 5432 -f contrib/pg_execplan/tests/create_objects.sql
49+
psql -p 5433 -f contrib/pg_execplan/tests/create_objects.sql
50+
51+
# TEST ON RELOID and TYPEOID objects.
52+
psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', 'SELECT * FROM t1;');"
53+
psql -p 5433 -c "SELECT pg_exec_query_plan('../test.txt');"
54+

src/backend/nodes/outfuncs.c

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,80 @@
3030
#include "nodes/plannodes.h"
3131
#include "nodes/relation.h"
3232
#include "utils/datum.h"
33+
#include "utils/lsyscache.h"
3334
#include "utils/rel.h"
35+
#include "utils/syscache.h"
3436

37+
#define OID_TYPES_NUM (2)
38+
static const Oid oid_types[OID_TYPES_NUM] = {RELOID, TYPEOID};
39+
40+
static bool portable_output = false;
41+
void
42+
set_portable_output(bool value)
43+
{
44+
portable_output = value;
45+
}
46+
47+
static void
48+
write_oid_field(StringInfo str, Oid oid)
49+
{
50+
int i;
51+
52+
if (!portable_output)
53+
{
54+
appendStringInfo(str, " %u", oid);
55+
return;
56+
}
57+
58+
appendStringInfo(str, " (");
59+
60+
if (!OidIsValid(oid))
61+
{
62+
/* Special case for invalid oid fields. For example, checkAsUser. */
63+
elog(INFO, "oid %d is INVALID OID!", oid);
64+
appendStringInfo(str, "%u %u)", 0, oid);
65+
return;
66+
}
67+
68+
for (i = 0; i < OID_TYPES_NUM; i++)
69+
if (SearchSysCacheExists1(oid_types[i], oid))
70+
break;
71+
72+
if (i == OID_TYPES_NUM)
73+
{
74+
elog(INFO, "Unexpected oid type %d!", oid);
75+
appendStringInfo(str, "%u %u)", 0, oid);
76+
return;
77+
}
78+
79+
switch (oid_types[i])
80+
{
81+
case RELOID:
82+
elog(INFO, "(RELOID %d): (%s, %s)", oid,
83+
get_namespace_name((get_rel_namespace((oid)))),
84+
get_rel_name((oid))
85+
);
86+
appendStringInfo(str, "%u %s %s", RELOID,
87+
get_namespace_name((get_rel_namespace((oid)))),
88+
get_rel_name((oid)));
89+
break;
90+
91+
case TYPEOID:
92+
elog(INFO, "(TYPEOID %d): %s %s", oid,
93+
get_namespace_name(get_typ_namespace(oid)),
94+
get_typ_name(oid));
95+
appendStringInfo(str, "%u %s %s", TYPEOID,
96+
get_namespace_name(get_typ_namespace(oid)),
97+
get_typ_name(oid));
98+
99+
break;
100+
101+
default:
102+
elog(ERROR, "oid %d type is %d (NOT DEFINED)!", oid, oid_types[i]);
103+
break;
104+
}
105+
appendStringInfo(str, ")");
106+
}
35107

36108
/*
37109
* Macros to simplify output of different kinds of fields. Use these
@@ -54,7 +126,10 @@
54126

55127
/* Write an OID field (don't hard-wire assumption that OID is same as uint) */
56128
#define WRITE_OID_FIELD(fldname) \
57-
appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
129+
do { \
130+
appendStringInfo(str, " :%s", CppAsString(fldname)); \
131+
write_oid_field(str, node->fldname); \
132+
} while (0)
58133

59134
/* Write a long-integer field */
60135
#define WRITE_LONG_FIELD(fldname) \

src/backend/nodes/readfuncs.c

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,19 @@
3434
#include "nodes/plannodes.h"
3535
#include "nodes/readfuncs.h"
3636

37+
/* Portable-related dependencies */
38+
#include "utils/lsyscache.h"
39+
#include "catalog/namespace.h"
40+
#include "utils/syscache.h"
41+
42+
static Oid read_oid_field(char **token, int *length);
43+
44+
static bool portable_input = false;
45+
void
46+
set_portable_input(bool value)
47+
{
48+
portable_input = value;
49+
}
3750

3851
/*
3952
* Macros to simplify reading of different kinds of fields. Use these
@@ -79,8 +92,7 @@
7992
/* Read an OID field (don't hard-wire assumption that OID is same as uint) */
8093
#define READ_OID_FIELD(fldname) \
8194
token = pg_strtok(&length); /* skip :fldname */ \
82-
token = pg_strtok(&length); /* get field value */ \
83-
local_node->fldname = atooid(token)
95+
local_node->fldname = read_oid_field(&token, &length);
8496

8597
/* Read a char field (ie, one ascii character) */
8698
#define READ_CHAR_FIELD(fldname) \
@@ -2719,3 +2731,80 @@ readBoolCols(int numCols)
27192731

27202732
return bool_vals;
27212733
}
2734+
2735+
#define atooid(x) ((Oid) strtoul((x), NULL, 10))
2736+
2737+
static Oid
2738+
read_oid_field(char **token, int *length)
2739+
{
2740+
Oid oid_type,
2741+
oid;
2742+
2743+
if (!portable_input)
2744+
{
2745+
*token = pg_strtok(length);
2746+
return atooid(*token);
2747+
}
2748+
2749+
*token = pg_strtok(length);
2750+
Assert((*token)[0] = '(');
2751+
*token = pg_strtok(length);
2752+
oid_type = atooid(*token);
2753+
2754+
if (!OidIsValid(oid_type))
2755+
{
2756+
Oid oid;
2757+
*token = pg_strtok(length);
2758+
oid = atooid(*token);
2759+
*token = pg_strtok(length);
2760+
Assert((*token)[0] = ')');
2761+
return oid;
2762+
}
2763+
2764+
switch (oid_type)
2765+
{
2766+
case RELOID:
2767+
{
2768+
char *relname,
2769+
*nspname;
2770+
Oid rel_nsp_oid;
2771+
2772+
*token = pg_strtok(length); /* Switch to namespace name */
2773+
nspname = nullable_string(*token, *length);
2774+
rel_nsp_oid = LookupNamespaceNoError(nspname);
2775+
*token = pg_strtok(length); /* Switch to relname */
2776+
relname = nullable_string(*token, *length);
2777+
oid = get_relname_relid(relname, rel_nsp_oid);
2778+
elog(INFO, "reloid=%d", oid);
2779+
break;
2780+
}
2781+
case TYPEOID:
2782+
{
2783+
char *nspname; /* namespace name */
2784+
char *typname; /* data type name */
2785+
2786+
*token = pg_strtok(length); /* get nspname */
2787+
nspname = nullable_string(*token, *length);
2788+
*token = pg_strtok(length); /* get typname */
2789+
typname = nullable_string(*token, *length);
2790+
if (typname)
2791+
{
2792+
oid = get_typname_typid(typname, LookupNamespaceNoError((nspname)));
2793+
if (!OidIsValid((oid)))
2794+
elog(WARNING, "could not find OID for type %s.%s",
2795+
nspname, typname);
2796+
}
2797+
else
2798+
oid = InvalidOid;
2799+
elog(INFO, "typeoid=%d", oid);
2800+
}
2801+
break;
2802+
2803+
default:
2804+
Assert(0);
2805+
break;
2806+
}
2807+
*token = pg_strtok(length);
2808+
Assert((*token)[0] = ')');
2809+
return oid;
2810+
}

src/backend/utils/cache/lsyscache.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,3 +3061,67 @@ get_range_subtype(Oid rangeOid)
30613061
else
30623062
return InvalidOid;
30633063
}
3064+
3065+
/*
3066+
* get_typ_name
3067+
*
3068+
* Given the type OID, find the type name
3069+
* It returns palloc'd copy of the name or NULL if the cache lookup fails...
3070+
*/
3071+
char *
3072+
get_typ_name(Oid typid)
3073+
{
3074+
HeapTuple tp;
3075+
3076+
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3077+
if (HeapTupleIsValid(tp))
3078+
{
3079+
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3080+
char *result;
3081+
3082+
result = pstrdup(NameStr(typtup->typname));
3083+
ReleaseSysCache(tp);
3084+
return result;
3085+
}
3086+
else
3087+
return NULL;
3088+
}
3089+
3090+
/*
3091+
* get_typ_namespace
3092+
*
3093+
* Given the type OID, find the namespace
3094+
* It returns InvalidOid if the cache lookup fails...
3095+
*/
3096+
Oid
3097+
get_typ_namespace(Oid typid)
3098+
{
3099+
HeapTuple tp;
3100+
3101+
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
3102+
if (HeapTupleIsValid(tp))
3103+
{
3104+
Form_pg_type typtup = (Form_pg_type) GETSTRUCT(tp);
3105+
Oid result;
3106+
3107+
result = typtup->typnamespace;
3108+
ReleaseSysCache(tp);
3109+
return result;
3110+
}
3111+
else
3112+
return InvalidOid;
3113+
}
3114+
3115+
/*
3116+
* get_typname_typid
3117+
* Given a type name and namespace OID, look up the type OID.
3118+
*
3119+
* Returns InvalidOid if there is no such type
3120+
*/
3121+
Oid
3122+
get_typname_typid(const char *typname, Oid typnamespace)
3123+
{
3124+
return GetSysCacheOid2(TYPENAMENSP,
3125+
CStringGetDatum(typname),
3126+
ObjectIdGetDatum(typnamespace));
3127+
}

src/include/nodes/nodes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,8 @@ extern void outBitmapset(struct StringInfoData *str,
575575
const struct Bitmapset *bms);
576576
extern void outDatum(struct StringInfoData *str, uintptr_t value,
577577
int typlen, bool typbyval);
578+
579+
extern void set_portable_output(bool value);
578580
extern char *nodeToString(const void *obj);
579581
extern char *bmsToString(const struct Bitmapset *bms);
580582

0 commit comments

Comments
 (0)