1 /*
2  * Copyright (c) 2017-2018	Tatsuo Ishii
3  * Copyright (c) 2018-2021	PgPool Global Development Group
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby
7  * granted, provided that the above copyright notice appear in all
8  * copies and that both that copyright notice and this permission
9  * notice appear in supporting documentation, and that the name of the
10  * author not be used in advertising or publicity pertaining to
11  * distribution of the software without specific, written prior
12  * permission. The author makes no representations about the
13  * suitability of this software for any purpose.  It is provided "as
14  * is" without express or implied warranty.
15  *
16  * Process Parse, Bind, Execute message.
17  */
18 
19 #include "../../include/config.h"
20 #include "pgproto/pgproto.h"
21 #include <unistd.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <getopt.h>
25 #include <string.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include "pgproto/fe_memutils.h"
29 #include <libpq-fe.h>
30 #include "pgproto/read.h"
31 #include "pgproto/send.h"
32 #include "pgproto/extended_query.h"
33 #include "pgproto/buffer.h"
34 
35 /*
36  * Send parse messae. "conn" should at the point right after the message kind
37  * was read.
38  */
39 void
process_parse(char * buf,PGconn * conn)40 process_parse(char *buf, PGconn *conn)
41 {
42 	char	   *query;
43 	int			len;
44 	char	   *stmt;
45 	short		noids;
46 	int			oids[MAXENTRIES];
47 	int			i;
48 	char	   *bufp;
49 
50 	SKIP_TABS(buf);
51 
52 	len = sizeof(int);
53 
54 	stmt = buffer_read_string(buf, &bufp);
55 	buf = bufp;
56 	len += strlen(stmt) + 1;
57 
58 	SKIP_TABS(buf);
59 
60 	query = buffer_read_string(buf, &bufp);
61 	buf = bufp;
62 	len += strlen(query) + 1;
63 
64 	SKIP_TABS(buf);
65 
66 	fprintf(stderr, "FE=> Parse(stmt=\"%s\", query=\"%s\")", stmt, query);
67 
68 	noids = buffer_read_int(buf, &bufp);
69 	buf = bufp;
70 
71 	if (noids > MAXENTRIES)
72 	{
73 		fprintf(stderr, "Too many oid params for parse message (%d)\n", noids);
74 		exit(1);
75 	}
76 
77 	len += sizeof(short) + noids * sizeof(int);
78 
79 	if (noids > 0)
80 	{
81 		fprintf(stderr, ", oids={");
82 
83 		for (i = 0; i < noids; i++)
84 		{
85 			oids[i] = buffer_read_int(buf, &bufp);
86 			fprintf(stderr, "%d", oids[i]);
87 			if ((i + 1) != noids)
88 				fprintf(stderr, ",");
89 			buf = bufp;
90 		}
91 	}
92 	fprintf(stderr, "\n");
93 
94 	send_char('P', conn);
95 	send_int(len, conn);
96 	send_string(stmt, conn);
97 	free(stmt);
98 	send_string(query, conn);
99 	free(query);
100 	send_int16(noids, conn);
101 	if (noids > 0)
102 	{
103 		for (i = 0; i < noids; i++)
104 		{
105 			send_int(oids[i], conn);
106 		}
107 	}
108 }
109 
110 /*
111  * Send bind message. "conn" should be at the point right after the message kind
112  * was read.
113  */
114 void
process_bind(char * buf,PGconn * conn)115 process_bind(char *buf, PGconn *conn)
116 {
117 	int			len;
118 	char	   *stmt;
119 	char	   *portal;
120 	short		nparams;
121 	short		ncodes;
122 	short		codes[MAXENTRIES];
123 	int			paramlens[MAXENTRIES];
124 	char	   *paramvals[MAXENTRIES];
125 	short		nresult_formatcodes;
126 	short		result_formatcodes[MAXENTRIES];
127 	int			i;
128 	char	   *bufp;
129 
130 	SKIP_TABS(buf);
131 
132 	len = sizeof(int);
133 
134 	portal = buffer_read_string(buf, &bufp);
135 	buf = bufp;
136 	len += strlen(portal) + 1;
137 
138 	SKIP_TABS(buf);
139 
140 	stmt = buffer_read_string(buf, &bufp);
141 	buf = bufp;
142 	len += strlen(stmt) + 1;
143 
144 	fprintf(stderr, "FE=> Bind(stmt=\"%s\", portal=\"%s\")", stmt, portal);
145 
146 	SKIP_TABS(buf);
147 
148 	ncodes = buffer_read_int(buf, &bufp);
149 	len += sizeof(short) + sizeof(short) * ncodes;
150 	buf = bufp;
151 
152 	SKIP_TABS(buf);
153 
154 	if (ncodes > MAXENTRIES)
155 	{
156 		fprintf(stderr, "Too many codes for bind message (%d)\n", ncodes);
157 		exit(1);
158 	}
159 
160 	if (ncodes > 0)
161 	{
162 		for (i = 0; i < ncodes; i++)
163 		{
164 			codes[i] = buffer_read_int(buf, &bufp);
165 			buf = bufp;
166 			SKIP_TABS(buf);
167 		}
168 	}
169 
170 	nparams = buffer_read_int(buf, &bufp);
171 	len += sizeof(short) + sizeof(short) * nparams;
172 	buf = bufp;
173 	SKIP_TABS(buf);
174 
175 	if (nparams > MAXENTRIES)
176 	{
177 		fprintf(stderr, "Too many params for bind message (%d)\n", nparams);
178 		exit(1);
179 	}
180 
181 	for (i = 0; i < nparams; i++)
182 	{
183 		paramlens[i] = buffer_read_int(buf, &bufp);
184 		len += sizeof(int);
185 
186 		if (paramlens[i] > 0)
187 		{
188 			buf = bufp;
189 			paramvals[i] = buffer_read_string(buf, &bufp);
190 			buf = bufp;
191 			SKIP_TABS(buf);
192 			len += paramlens[i];
193 		}
194 	}
195 
196 	SKIP_TABS(buf);
197 
198 	nresult_formatcodes = buffer_read_int(buf, &bufp);
199 	buf = bufp;
200 	len += sizeof(short) + sizeof(short) * nresult_formatcodes;
201 	SKIP_TABS(buf);
202 
203 	if (nresult_formatcodes >= 2)
204 	{
205 		for (i = 0; i < nresult_formatcodes; i++)
206 		{
207 			result_formatcodes[i] = buffer_read_int(buf, &bufp);
208 			buf = bufp;
209 			SKIP_TABS(buf);
210 		}
211 	}
212 	fprintf(stderr, "\n");
213 
214 	send_char('B', conn);
215 	send_int(len, conn);
216 	send_string(portal, conn);
217 	free(portal);
218 	send_string(stmt, conn);
219 	free(stmt);
220 	send_int16(ncodes, conn);
221 	for (i = 0; i < ncodes; i++)
222 	{
223 		send_int16(codes[i], conn);
224 	}
225 
226 	send_int16(nparams, conn);
227 	for (i = 0; i < nparams; i++)
228 	{
229 		if (paramlens[i] != -1)
230 		{
231 			if (ncodes == 0 || codes[i] == 0)
232 			{
233 				send_string(paramvals[i], conn);
234 			}
235 			else
236 			{
237 				send_int(atoi(paramvals[i]), conn);
238 			}
239 		}
240 	}
241 
242 	send_int16(nresult_formatcodes, conn);
243 	for (i = 0; i < nresult_formatcodes; i++)
244 	{
245 		send_int16(result_formatcodes[i], conn);
246 	}
247 }
248 
249 /*
250  * Send execute messae. "conn" should at the point right after the message
251  * kind was read.
252  */
253 void
process_execute(char * buf,PGconn * conn)254 process_execute(char *buf, PGconn *conn)
255 {
256 	int			len;
257 	char	   *portal;
258 	int			maxrows;
259 	char	   *bufp;
260 
261 	SKIP_TABS(buf);
262 
263 	len = sizeof(int);
264 
265 	portal = buffer_read_string(buf, &bufp);
266 	buf = bufp;
267 	len += strlen(portal) + 1;
268 
269 	SKIP_TABS(buf);
270 
271 	fprintf(stderr, "FE=> Execute(portal=\"%s\")\n", portal);
272 
273 	SKIP_TABS(buf);
274 
275 	maxrows = buffer_read_int(buf, &bufp);
276 
277 	len += sizeof(int);
278 
279 	send_char('E', conn);
280 	send_int(len, conn);
281 	send_string(portal, conn);
282 	send_int(maxrows, conn);
283 	free(portal);
284 }
285 
286 /*
287  * Send describe messae. "conn" should at the point right after the message kind
288  * was read.
289  */
290 void
process_describe(char * buf,PGconn * conn)291 process_describe(char *buf, PGconn *conn)
292 {
293 	char		kind;
294 	int			len;
295 	char	   *stmt;
296 	char	   *bufp;
297 
298 	SKIP_TABS(buf);
299 
300 	len = sizeof(int);
301 
302 	kind = buffer_read_char(buf, &bufp);
303 	buf = bufp;
304 	len += 1;
305 
306 	SKIP_TABS(buf);
307 
308 	stmt = buffer_read_string(buf, &bufp);
309 	buf = bufp;
310 	len += strlen(stmt) + 1;
311 
312 	SKIP_TABS(buf);
313 
314 	if (kind == 'S')
315 	{
316 		fprintf(stderr, "FE=> Describe(stmt=\"%s\")\n", stmt);
317 	}
318 	else if (kind == 'P')
319 	{
320 		fprintf(stderr, "FE=> Describe(portal=\"%s\")\n", stmt);
321 	}
322 	else
323 	{
324 		fprintf(stderr, "Close: unknown kind:%c\n", kind);
325 		exit(1);
326 	}
327 
328 	send_char('D', conn);
329 	send_int(len, conn);
330 	send_char(kind, conn);
331 	send_string(stmt, conn);
332 	free(stmt);
333 }
334 
335 /*
336  * Send close messae. "conn" should at the point right after the message kind
337  * was read.
338  */
339 void
process_close(char * buf,PGconn * conn)340 process_close(char *buf, PGconn *conn)
341 {
342 	char		kind;
343 	int			len;
344 	char	   *stmt;
345 	char	   *bufp;
346 
347 	SKIP_TABS(buf);
348 
349 	len = sizeof(int);
350 
351 	kind = buffer_read_char(buf, &bufp);
352 	buf = bufp;
353 	len += 1;
354 
355 	SKIP_TABS(buf);
356 
357 	stmt = buffer_read_string(buf, &bufp);
358 	buf = bufp;
359 	len += strlen(stmt) + 1;
360 
361 	SKIP_TABS(buf);
362 
363 	if (kind == 'S')
364 	{
365 		fprintf(stderr, "FE=> Close(stmt=\"%s\")\n", stmt);
366 	}
367 	else if (kind == 'P')
368 	{
369 		fprintf(stderr, "FE=> Close(portal=\"%s\")\n", stmt);
370 	}
371 	else
372 	{
373 		fprintf(stderr, "Close: unknown kind:%c\n", kind);
374 		exit(1);
375 	}
376 
377 	send_char('C', conn);
378 	send_int(len, conn);
379 	send_char(kind, conn);
380 	send_string(stmt, conn);
381 	free(stmt);
382 }
383