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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy