Skip to content

Commit 678ac3d

Browse files
committed
Add OIDs list processing + portable plan sign
1 parent df9c2ca commit 678ac3d

File tree

12 files changed

+196
-100
lines changed

12 files changed

+196
-100
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ lib*.pc
4242
/Debug/
4343
/Release/
4444
/tmp_install/
45+
/.cproject
46+
/.project
47+
/.settings/

contrib/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ SUBDIRS = \
3030
pageinspect \
3131
passwordcheck \
3232
pg_buffercache \
33+
pg_execplan \
3334
pg_freespacemap \
3435
pg_prewarm \
3536
pg_standby \
@@ -38,6 +39,7 @@ SUBDIRS = \
3839
pgcrypto \
3940
pgrowlocks \
4041
pgstattuple \
42+
pg_repeater \
4143
pg_visibility \
4244
postgres_fdw \
4345
seg \

contrib/pg_execplan/init.sql

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
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-
filename TEXT,
8-
query TEXT
9-
)
7+
filename TEXT,
8+
query TEXT
9+
)
1010
RETURNS VOID AS 'pg_execplan'
1111
LANGUAGE C;
1212

13-
CREATE OR REPLACE FUNCTION @extschema@.pg_exec_plan(query TEXT,
14-
plan TEXT
13+
CREATE OR REPLACE FUNCTION @extschema@.pg_exec_plan(query TEXT,
14+
plan TEXT,
15+
params TEXT
1516
)
1617
RETURNS BOOL AS 'pg_execplan'
1718
LANGUAGE C;

contrib/pg_execplan/pg_execplan.c

Lines changed: 109 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "common/base64.h"
1212
#include "executor/executor.h"
1313
#include "nodes/nodes.h"
14+
#include "nodes/params.h"
1415
#include "nodes/plannodes.h"
1516
#include "tcop/pquery.h"
1617
#include "tcop/utility.h"
@@ -42,10 +43,13 @@ _PG_init(void)
4243
Datum
4344
pg_store_query_plan(PG_FUNCTION_ARGS)
4445
{
45-
char *query_string = TextDatumGetCString(PG_GETARG_DATUM(1)),
46-
*filename = TextDatumGetCString(PG_GETARG_DATUM(0)),
47-
*plan_string;
48-
int nstmts;
46+
char *filename = TextDatumGetCString(PG_GETARG_DATUM(0)),
47+
*squery = TextDatumGetCString(PG_GETARG_DATUM(1)),
48+
*sparams = NULL,
49+
*start_address,
50+
*splan;
51+
int nstmts,
52+
sparams_len;
4953
FILE *fout;
5054
MemoryContext oldcontext;
5155
List *parsetree_list;
@@ -56,21 +60,21 @@ pg_store_query_plan(PG_FUNCTION_ARGS)
5660
size_t string_len;
5761

5862
if (EXPLAN_DEBUG_LEVEL > 0)
59-
elog(LOG, "Store into %s plan of the query %s.", filename, query_string);
63+
elog(LOG, "Store into %s plan of the query %s.", filename, squery);
6064

6165
oldcontext = MemoryContextSwitchTo(MessageContext);
6266

63-
parsetree_list = pg_parse_query(query_string);
67+
parsetree_list = pg_parse_query(squery);
6468
nstmts = list_length(parsetree_list);
6569
if (nstmts != 1)
6670
elog(ERROR, "Query contains %d elements, but must contain only one.", nstmts);
6771

6872
parsetree = (RawStmt *) linitial(parsetree_list);
69-
querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0, NULL);
73+
querytree_list = pg_analyze_and_rewrite(parsetree, squery, NULL, 0, NULL);
7074
plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL);
7175

7276
queryDesc = CreateQueryDesc((PlannedStmt *) linitial(plantree_list),
73-
query_string,
77+
squery,
7478
InvalidSnapshot,
7579
InvalidSnapshot,
7680
None_Receiver,
@@ -82,24 +86,35 @@ pg_store_query_plan(PG_FUNCTION_ARGS)
8286

8387
fout = fopen(filename, "wb");
8488
Assert(fout != NULL);
85-
string_len = strlen(query_string);
89+
string_len = strlen(squery);
8690
fwrite(&string_len, sizeof(size_t), 1, fout);
87-
fwrite(query_string, sizeof(char), string_len, fout);
91+
fwrite(squery, sizeof(char), string_len, fout);
8892

8993
set_portable_output(true);
90-
plan_string = nodeToString(queryDesc->plannedstmt);
94+
splan = nodeToString(queryDesc->plannedstmt);
9195
set_portable_output(false);
92-
string_len = strlen(plan_string);
96+
string_len = strlen(splan);
9397
fwrite(&string_len, sizeof(size_t), 1, fout);
94-
fwrite(plan_string, sizeof(char), string_len, fout);
95-
98+
fwrite(splan, sizeof(char), string_len, fout);
99+
100+
/*
101+
* Serialize parameters list. In this case we have no parameters and will
102+
* serialize NULL list.
103+
*/
104+
sparams_len = EstimateParamListSpace(NULL);
105+
sparams = palloc0(sparams_len);
106+
start_address = sparams;
107+
SerializeParamList(NULL, &start_address);
108+
string_len = sparams_len;
109+
fwrite(&string_len, sizeof(size_t), 1, fout);
110+
fwrite(sparams, sizeof(char), string_len, fout);
96111
fclose(fout);
97112
MemoryContextSwitchTo(oldcontext);
98113
PG_RETURN_VOID();
99114
}
100115

101116
static void
102-
exec_plan(char *query_string, char *plan_string)
117+
exec_plan(char *squery, char *splan, char *sparams)
103118
{
104119
PlannedStmt *pstmt;
105120
ParamListInfo paramLI = NULL;
@@ -108,28 +123,42 @@ exec_plan(char *query_string, char *plan_string)
108123
QueryDesc *queryDesc;
109124
DestReceiver *receiver;
110125
int eflags = 0;
126+
Oid *param_types = NULL;
127+
char *start_address = sparams;
128+
129+
Assert(squery && splan && sparams);
111130

112131
PG_TRY();
113132
{
114-
set_portable_input(true);
115-
pstmt = (PlannedStmt *) stringToNode(plan_string);
116-
set_portable_input(false);
133+
pstmt = (PlannedStmt *) stringToNode(splan);
134+
135+
/* Deserialize parameters of the query */
136+
paramLI = RestoreParamList(&start_address);
117137
}
118138
PG_CATCH();
119139
{
120-
elog(INFO, "BAD PLAN: %s. Query: %s", plan_string, query_string);
140+
elog(INFO, "BAD PLAN: %s. Query: %s", splan, squery);
121141
PG_RE_THROW();
122142
}
123143
PG_END_TRY();
124144

125145
if (EXPLAN_DEBUG_LEVEL > 0)
126-
elog(INFO, "query: %s\n", query_string);
146+
elog(INFO, "query: %s\n", squery);
127147
if (EXPLAN_DEBUG_LEVEL > 1)
128-
elog(INFO, "\nplan: %s\n", plan_string);
148+
elog(INFO, "\nplan: %s\n", splan);
149+
150+
psrc = CreateCachedPlan(NULL, squery, NULL);
151+
152+
if (paramLI->numParams > 0)
153+
{
154+
int i;
129155

130-
psrc = CreateCachedPlan(NULL, query_string, NULL);
131-
CompleteCachedPlan(psrc, NIL, NULL, NULL, 0, NULL, NULL,
132-
CURSOR_OPT_GENERIC_PLAN, false);
156+
param_types = palloc(sizeof(Oid) * paramLI->numParams);
157+
for (i = 0; i < paramLI->numParams; i++)
158+
param_types[i] = paramLI->params[i].ptype;
159+
}
160+
CompleteCachedPlan(psrc, NIL, NULL, param_types, paramLI->numParams, NULL,
161+
NULL, CURSOR_OPT_GENERIC_PLAN, false);
133162

134163
SetRemoteSubplan(psrc, pstmt);
135164
cplan = GetCachedPlan(psrc, paramLI, false, NULL);
@@ -139,7 +168,7 @@ exec_plan(char *query_string, char *plan_string)
139168
PG_TRY();
140169
{
141170
queryDesc = CreateQueryDesc(pstmt,
142-
query_string,
171+
squery,
143172
GetActiveSnapshot(),
144173
InvalidSnapshot,
145174
receiver,
@@ -155,7 +184,7 @@ exec_plan(char *query_string, char *plan_string)
155184
}
156185
PG_CATCH();
157186
{
158-
elog(INFO, "BAD QUERY: '%s'.", query_string);
187+
elog(INFO, "BAD QUERY: '%s'.", squery);
159188
ReleaseCachedPlan(cplan, false);
160189
PG_RE_THROW();
161190
}
@@ -171,37 +200,49 @@ exec_plan(char *query_string, char *plan_string)
171200
Datum
172201
pg_exec_plan(PG_FUNCTION_ARGS)
173202
{
174-
char *query_string = TextDatumGetCString(PG_GETARG_DATUM(0));
175-
char *plan_string = TextDatumGetCString(PG_GETARG_DATUM(1));
203+
char *squery = TextDatumGetCString(PG_GETARG_DATUM(0));
204+
char *splan = TextDatumGetCString(PG_GETARG_DATUM(1));
205+
char *sparams = TextDatumGetCString(PG_GETARG_DATUM(2));
176206

177207
char *dec_query,
178-
*dec_plan;
208+
*dec_plan,
209+
*dec_params;
179210
int dec_query_len,
180211
dec_query_len1,
181212
dec_plan_len,
182-
dec_plan_len1;
213+
dec_plan_len1,
214+
dec_params_len,
215+
dec_params_len1;
183216

184-
Assert(query_string != NULL);
185-
Assert(plan_string != NULL);
217+
Assert(squery != NULL);
218+
Assert(splan != NULL);
219+
Assert(sparams != NULL);
186220

187-
dec_query_len = pg_b64_dec_len(strlen(query_string) + 1) + 1;
221+
dec_query_len = pg_b64_dec_len(strlen(squery));
188222
dec_query = palloc0(dec_query_len + 1);
189-
dec_query_len1 = pg_b64_decode(query_string, strlen(query_string), dec_query);
190-
Assert(dec_query_len > dec_query_len1);
223+
dec_query_len1 = pg_b64_decode(squery, strlen(squery), dec_query);
224+
Assert(dec_query_len >= dec_query_len1);
191225

192-
dec_plan_len = pg_b64_dec_len(strlen(plan_string) + 1);
226+
dec_plan_len = pg_b64_dec_len(strlen(splan));
193227
dec_plan = palloc0(dec_plan_len + 1);
194-
dec_plan_len1 = pg_b64_decode(plan_string, strlen(plan_string), dec_plan);
195-
Assert(dec_plan_len > dec_plan_len1);
228+
dec_plan_len1 = pg_b64_decode(splan, strlen(splan), dec_plan);
229+
Assert(dec_plan_len >= dec_plan_len1);
230+
231+
dec_params_len = pg_b64_dec_len(strlen(sparams));
232+
dec_params = palloc0(dec_params_len + 1);
233+
dec_params_len1 = pg_b64_decode(sparams, strlen(sparams), dec_params);
234+
Assert(dec_params_len >= dec_params_len1);
196235

197-
exec_plan(dec_query, dec_plan);
236+
exec_plan(dec_query, dec_plan, dec_params);
198237
pfree(dec_query);
199238
pfree(dec_plan);
239+
pfree(dec_params);
200240
PG_RETURN_BOOL(true);
201241
}
202242

203243
static void
204-
LoadPlanFromFile(const char *filename, char **query_string, char **plan_string)
244+
LoadPlanFromFile(const char *filename, char **squery, char **splan,
245+
char **sparams)
205246
{
206247
FILE *fin;
207248
size_t string_len;
@@ -210,16 +251,28 @@ LoadPlanFromFile(const char *filename, char **query_string, char **plan_string)
210251
fin = fopen(filename, "rb");
211252
Assert(fin != NULL);
212253

254+
/* Read query string size, allocate memory and read query from the file. */
213255
nelems = fread(&string_len, sizeof(size_t), 1, fin);
214256
Assert(nelems == 1);
215-
*query_string = palloc0(string_len + 1);
216-
nelems = fread(*query_string, sizeof(char), string_len, fin);
257+
*squery = palloc0(string_len + 1);
258+
nelems = fread(*squery, sizeof(char), string_len, fin);
217259
Assert(nelems == string_len);
218260

261+
/* Read plan size, allocate memory and read plan from the file. */
219262
nelems = fread(&string_len, sizeof(size_t), 1, fin);
220263
Assert(nelems == 1);
221-
*plan_string = palloc0(string_len + 1);
222-
nelems = fread(*plan_string, sizeof(char), string_len, fin);
264+
*splan = palloc0(string_len + 1);
265+
nelems = fread(*splan, sizeof(char), string_len, fin);
266+
Assert(nelems == string_len);
267+
268+
/*
269+
* Read serialized query parameters string length, allocate memory and
270+
* read it from the file.
271+
*/
272+
nelems = fread(&string_len, sizeof(size_t), 1, fin);
273+
Assert(nelems == 1);
274+
*sparams = palloc0(string_len + 1);
275+
nelems = fread(*sparams, sizeof(char), string_len, fin);
223276
Assert(nelems == string_len);
224277

225278
fclose(fin);
@@ -229,11 +282,17 @@ LoadPlanFromFile(const char *filename, char **query_string, char **plan_string)
229282
Datum
230283
pg_exec_stored_plan(PG_FUNCTION_ARGS)
231284
{
232-
char *filename = TextDatumGetCString(PG_GETARG_DATUM(0)),
233-
*query_string = NULL,
234-
*plan_string = NULL;
235-
236-
LoadPlanFromFile(filename, &query_string, &plan_string);
237-
exec_plan(query_string, plan_string);
285+
char *filename = TextDatumGetCString(PG_GETARG_DATUM(0)),
286+
*squery = NULL,
287+
*splan = NULL,
288+
*sparams = NULL;
289+
290+
LoadPlanFromFile(filename, &squery, &splan, &sparams);
291+
292+
Assert(squery && splan && sparams);
293+
exec_plan(squery, splan, sparams);
294+
pfree(squery);
295+
pfree(splan);
296+
pfree(sparams);
238297
PG_RETURN_BOOL(true);
239298
}

contrib/pg_execplan/tests/rpl.sh

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -91,19 +91,3 @@ psql -p 5432 -c "SELECT pg_store_query_plan('../test.txt', '
9191
');"
9292
psql -p 5433 -c "SELECT pg_exec_stored_plan('../test.txt');"
9393

94-
# Prepared operator
95-
psql -p 5432 -c "PREPARE abc (TEXT, tests.bug_status) AS
96-
INSERT INTO bug (description, status)
97-
VALUES (\$1,\$2);
98-
SELECT pg_store_query_plan('../test.txt', '
99-
EXECUTE abc(''test1'', ''closed'')
100-
');"
101-
102-
psql -p 5433 -c "PREPARE abc (TEXT, tests.bug_status) AS
103-
INSERT INTO bug (description, status)
104-
VALUES (\$1,\$2);
105-
SELECT pg_exec_stored_plan('../test.txt');"
106-
107-
psql -p 5433 -c "SELECT * FROM bug;"
108-
psql -p 5433 -c "SELECT * FROM bug1;"
109-

0 commit comments

Comments
 (0)