11
11
#include "nodes/params.h"
12
12
#include "optimizer/planner.h"
13
13
#include "storage/lmgr.h"
14
+ #include "tcop/utility.h"
14
15
#include "utils/builtins.h"
15
16
#include "utils/guc.h"
16
17
#include "utils/plancache.h"
@@ -22,25 +23,33 @@ PG_FUNCTION_INFO_V1(pg_execute_plan);
22
23
23
24
void _PG_init (void );
24
25
26
+ static ProcessUtility_hook_type next_ProcessUtility_hook = NULL ;
25
27
static planner_hook_type prev_planner_hook = NULL ;
28
+ static ExecutorStart_hook_type prev_ExecutorStart = NULL ;
26
29
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL ;
27
30
31
+ static void HOOK_Utility_injection (PlannedStmt * pstmt , const char * queryString ,
32
+ ProcessUtilityContext context , ParamListInfo params ,
33
+ QueryEnvironment * queryEnv , DestReceiver * dest ,
34
+ char * completionTag );
28
35
static PlannedStmt * HOOK_Planner_injection (Query * parse , int cursorOptions ,
29
36
ParamListInfo boundParams );
37
+ static void HOOK_ExecStart_injection (QueryDesc * queryDesc , int eflags );
30
38
static void HOOK_ExecEnd_injection (QueryDesc * queryDesc );
31
39
static char * serialize_plan (PlannedStmt * pstmt , ParamListInfo boundParams ,
32
- int * size );
40
+ const char * querySourceText );
41
+ static void execute_query (char * planString );
42
+
33
43
static PGconn * conn = NULL ;
34
44
35
45
int node_number1 = 0 ;
36
- //#include "utils/guc.h"
46
+
37
47
/*
38
48
* Module load/unload callback
39
49
*/
40
50
void
41
51
_PG_init (void )
42
52
{
43
- elog (LOG , "_PG_Init" );
44
53
DefineCustomIntVariable ("pargres.node" ,
45
54
"Node number in instances collaboration" ,
46
55
NULL ,
@@ -54,28 +63,90 @@ _PG_init(void)
54
63
NULL ,
55
64
NULL );
56
65
66
+ /* ProcessUtility hook */
67
+ next_ProcessUtility_hook = ProcessUtility_hook ;
68
+ ProcessUtility_hook = HOOK_Utility_injection ;
69
+
57
70
/* Planner hook */
58
71
prev_planner_hook = planner_hook ;
59
72
planner_hook = HOOK_Planner_injection ;
60
73
74
+ prev_ExecutorStart = ExecutorStart_hook ;
75
+ ExecutorStart_hook = HOOK_ExecStart_injection ;
76
+
61
77
prev_ExecutorEnd = ExecutorEnd_hook ;
62
78
ExecutorEnd_hook = HOOK_ExecEnd_injection ;
63
79
}
64
80
65
81
static void
66
- HOOK_ExecEnd_injection (QueryDesc * queryDesc )
82
+ HOOK_Utility_injection (PlannedStmt * pstmt ,
83
+ const char * queryString ,
84
+ ProcessUtilityContext context ,
85
+ ParamListInfo params ,
86
+ QueryEnvironment * queryEnv ,
87
+ DestReceiver * dest ,
88
+ char * completionTag )
67
89
{
68
- PGresult * result ;
90
+ Node * parsetree = pstmt -> utilityStmt ;
91
+
92
+ if ((OidIsValid (get_extension_oid ("execplan" , true))) &&
93
+ (node_number1 == 0 ) &&
94
+ (nodeTag (parsetree ) == T_CreateStmt ))
95
+ {
96
+ char conninfo [1024 ];
97
+ int status ;
98
+
99
+ elog (LOG , "Send UTILITY query: %s" , queryString );
100
+
101
+ /* Connect to slave and send it a query plan */
102
+ sprintf (conninfo , "host=localhost port=5433%c" , '\0' );
103
+ conn = PQconnectdb (conninfo );
104
+ if (PQstatus (conn ) == CONNECTION_BAD )
105
+ elog (LOG , "Connection error. conninfo: %s" , conninfo );
106
+
107
+ status = PQsendQuery (conn , queryString );
108
+ if (status == 0 )
109
+ elog (ERROR , "Query sending error: %s" , PQerrorMessage (conn ));
110
+ }
111
+
112
+ if (next_ProcessUtility_hook )
113
+ (* next_ProcessUtility_hook ) (pstmt , queryString , context , params ,
114
+ queryEnv , dest , completionTag );
115
+ else
116
+ standard_ProcessUtility (pstmt , queryString ,
117
+ context , params , queryEnv ,
118
+ dest , completionTag );
69
119
70
- /* Execute before hook because it destruct memory context of exchange list */
71
120
if (conn )
121
+ {
122
+ PGresult * result ;
123
+
72
124
while ((result = PQgetResult (conn )) != NULL )
73
125
Assert (PQresultStatus (result ) != PGRES_FATAL_ERROR );
126
+ PQfinish (conn );
127
+ conn = NULL ;
128
+ }
129
+ }
74
130
75
- if (prev_ExecutorEnd )
76
- prev_ExecutorEnd (queryDesc );
77
- else
78
- standard_ExecutorEnd (queryDesc );
131
+ static void
132
+ execute_query (char * planString )
133
+ {
134
+ char conninfo [1024 ];
135
+ char * SQLCommand ;
136
+ int status ;
137
+
138
+ /* Connect to slave and send it a query plan */
139
+ sprintf (conninfo , "host=localhost port=5433%c" , '\0' );
140
+ conn = PQconnectdb (conninfo );
141
+ if (PQstatus (conn ) == CONNECTION_BAD )
142
+ elog (LOG , "Connection error. conninfo: %s" , conninfo );
143
+
144
+ SQLCommand = (char * ) palloc0 (strlen (planString )+ 100 );
145
+ sprintf (SQLCommand , "SELECT pg_execute_plan('%s')" , planString );
146
+ //elog(LOG, "query: %s", SQLCommand);
147
+ status = PQsendQuery (conn , SQLCommand );
148
+ if (status == 0 )
149
+ elog (ERROR , "Query sending error: %s" , PQerrorMessage (conn ));
79
150
}
80
151
81
152
static PlannedStmt *
@@ -91,72 +162,103 @@ HOOK_Planner_injection(Query *parse, int cursorOptions,
91
162
else
92
163
pstmt = standard_planner (parse , cursorOptions , boundParams );
93
164
94
- if (node_number1 > 0 )
165
+ if (( node_number1 > 0 ) || ( parse -> utilityStmt != NULL ) )
95
166
return pstmt ;
96
- else
97
- printf ("SEND Query\n" );
98
167
99
168
/* Extension is not initialized. */
100
169
if (OidIsValid (get_extension_oid ("execplan" , true)))
101
170
{
102
- char conninfo [1024 ];
103
- char * data ,
104
- * SQLCommand ;
105
- int status ,
106
- data_size ;
107
171
108
- /* Connect to slave and send it a query plan */
109
- sprintf (conninfo , "host=localhost port=5433%c" , '\0' );
110
- conn = PQconnectdb (conninfo );
111
- if (PQstatus (conn ) == CONNECTION_BAD )
112
- elog (LOG , "Connection error. conninfo: %s" , conninfo );
113
-
114
- data = serialize_plan (pstmt , boundParams , & data_size );
115
- SQLCommand = (char * ) palloc0 (strlen (data )+ 100 );
116
- sprintf (SQLCommand , "SELECT pg_execute_plan('%s')" , data );
117
- elog (LOG , "query: %s" , SQLCommand );
118
- status = PQsendQuery (conn , SQLCommand );
119
- if (status == 0 )
120
- elog (ERROR , "Query sending error: %s" , PQerrorMessage (conn ));
121
172
}
122
173
return pstmt ;
123
174
}
124
175
176
+ static void
177
+ HOOK_ExecStart_injection (QueryDesc * queryDesc , int eflags )
178
+ {
179
+ Node * parsetree = queryDesc -> plannedstmt -> utilityStmt ;
180
+
181
+ if ((OidIsValid (get_extension_oid ("execplan" , true))) &&
182
+ (node_number1 == 0 ) &&
183
+ ((parsetree == NULL ) || (nodeTag (parsetree ) != T_CreatedbStmt )))
184
+ {
185
+ elog (LOG , "Send query: %s" , queryDesc -> sourceText );
186
+ execute_query (serialize_plan (queryDesc -> plannedstmt , queryDesc -> params ,
187
+ queryDesc -> sourceText ));
188
+ }
189
+ else
190
+ {
191
+ // elog(LOG, "EXECUTOR Process query without sending. IsParsetree=%hhu node_number1=%d IsExt=%hhu", parsetree != NULL, node_number1, OidIsValid(get_extension_oid("execplan", true)));
192
+ }
193
+
194
+ if (prev_ExecutorStart )
195
+ prev_ExecutorStart (queryDesc , eflags );
196
+ else
197
+ standard_ExecutorStart (queryDesc , eflags );
198
+ }
199
+
200
+ static void
201
+ HOOK_ExecEnd_injection (QueryDesc * queryDesc )
202
+ {
203
+ /* Execute before hook because it destruct memory context of exchange list */
204
+ if (conn )
205
+ {
206
+ PGresult * result ;
207
+
208
+ while ((result = PQgetResult (conn )) != NULL )
209
+ Assert (PQresultStatus (result ) != PGRES_FATAL_ERROR );
210
+ PQfinish (conn );
211
+ conn = NULL ;
212
+ }
213
+
214
+ if (prev_ExecutorEnd )
215
+ prev_ExecutorEnd (queryDesc );
216
+ else
217
+ standard_ExecutorEnd (queryDesc );
218
+ }
219
+
125
220
#include "utils/fmgrprotos.h"
126
221
127
222
static char *
128
- serialize_plan (PlannedStmt * pstmt , ParamListInfo boundParams , int * size )
223
+ serialize_plan (PlannedStmt * pstmt , ParamListInfo boundParams ,
224
+ const char * querySourceText )
129
225
{
130
226
int splan_len ,
131
227
sparams_len ,
228
+ qtext_len ,
132
229
econtainer_len ;
133
230
char * serialized_plan ,
134
231
* container ,
135
232
* start_address ,
136
233
* econtainer ;
137
234
138
- Assert (size != NULL );
139
-
140
235
serialized_plan = nodeToString (pstmt );
141
236
142
- /* We use splan_len +1 bytes for include end-of-string symbol. */
237
+ /* We use len +1 bytes for include end-of-string symbol. */
143
238
splan_len = strlen (serialized_plan ) + 1 ;
239
+ qtext_len = strlen (querySourceText ) + 1 ;
144
240
145
241
sparams_len = EstimateParamListSpace (boundParams );
146
242
147
- container = (char * ) palloc0 (splan_len + sparams_len );
243
+ container = (char * ) palloc0 (splan_len + sparams_len + qtext_len );
148
244
//elog(LOG, "Serialize sizes: plan: %d params: %d, numParams: %d", splan_len, sparams_len, boundParams->numParams);
149
245
memcpy (container , serialized_plan , splan_len );
150
- start_address = container + splan_len ;
246
+ start_address = container + splan_len ;
151
247
SerializeParamList (boundParams , & start_address );
152
248
153
- econtainer_len = esc_enc_len ( container , splan_len + sparams_len );
154
- econtainer = ( char * ) palloc0 ( econtainer_len + 1 );
249
+ Assert ( start_address == container + splan_len + sparams_len );
250
+ memcpy ( start_address , querySourceText , qtext_len );
155
251
156
- Assert (econtainer_len == esc_encode (container , splan_len + sparams_len , econtainer ));
252
+ econtainer_len = pg_base64_enc_len (container , splan_len + sparams_len + qtext_len );
253
+ econtainer = (char * ) palloc0 (econtainer_len + 1 );
254
+ if (econtainer_len != pg_base64_encode (container , splan_len + sparams_len +
255
+ qtext_len , econtainer ))
256
+ elog (LOG , "econtainer_len: %d %d" , econtainer_len , pg_base64_encode (container , splan_len + sparams_len +
257
+ qtext_len , econtainer ));
258
+ Assert (econtainer_len == pg_base64_encode (container , splan_len + sparams_len +
259
+ qtext_len , econtainer ));
157
260
econtainer [econtainer_len ] = '\0' ;
158
- * size = econtainer_len + 1 ;
159
- elog (LOG , "Serialize sizes: econtainer: %d" , * size );
261
+
160
262
return econtainer ;
161
263
}
162
264
@@ -209,30 +311,22 @@ pg_execute_plan(PG_FUNCTION_ARGS)
209
311
char * data = TextDatumGetCString (PG_GETARG_DATUM (0 ));
210
312
PlannedStmt * pstmt ;
211
313
QueryDesc * queryDesc ;
212
- char queryString [ 5 ] = "NONE" ;
314
+ char * queryString ;
213
315
ParamListInfo paramLI = NULL ;
214
316
int dec_tot_len ;
215
317
char * dcontainer ,
216
318
* start_addr ;
217
319
218
- elog (LOG , "datalen=%lu\n" , strlen (data ));
219
320
/* Compute decoded size of bytea data */
220
- dec_tot_len = esc_dec_len (data , strlen (data ));
221
- elog (LOG , "dec_tot_len=%d datalen=%lu\n" , dec_tot_len , strlen (data ));
321
+ dec_tot_len = pg_base64_dec_len (data , strlen (data ));
222
322
dcontainer = (char * ) palloc0 (dec_tot_len );
223
- Assert (dec_tot_len == esc_decode (data , strlen (data ), dcontainer ));
323
+ Assert (dec_tot_len == pg_base64_decode (data , strlen (data ), dcontainer ));
224
324
225
325
pstmt = (PlannedStmt * ) stringToNode ((char * ) dcontainer );
226
- elog (LOG , "Serialize Plan Size=%lu\n" , strlen (dcontainer ));
227
326
start_addr = dcontainer + strlen (dcontainer ) + 1 ;
228
327
paramLI = RestoreParamList ((char * * ) & start_addr );
229
- elog (LOG , "Decoded params. numParams: %d\n" , paramLI -> numParams );
230
- // printf("INCOMING: %s\n", data);
231
- // PG_RETURN_BOOL(true);
232
- /* Execute query plan. Based on execParallel.c ParallelQueryMain() */
233
- //
234
- // ptr += strlen((const char *) ptr);
235
- //
328
+ queryString = start_addr ;
329
+ // elog(LOG, "Decoded query: %s\n", start_addr);
236
330
237
331
queryDesc = CreateQueryDesc (pstmt , queryString , GetActiveSnapshot (),
238
332
InvalidSnapshot , None_Receiver , paramLI , NULL ,
0 commit comments