1 /*-------------------------------------------------------------------------
2  *
3  * String-processing utility routines for frontend code
4  *
5  * Assorted utility functions that are useful in constructing SQL queries
6  * and interpreting backend output.
7  *
8  *
9  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
10  * Portions Copyright (c) 1994, Regents of the University of California
11  *
12  * src/fe_utils/string_utils.c
13  *
14  *-------------------------------------------------------------------------
15  */
16 #include "postgres_fe.h"
17 
18 #include <ctype.h>
19 
20 #include "fe_utils/string_utils.h"
21 
22 #include "common/keywords.h"
23 
24 
25 static PQExpBuffer defaultGetLocalPQExpBuffer(void);
26 
27 /* Globals exported by this file */
28 int			quote_all_identifiers = 0;
29 PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
30 
31 
32 /*
33  * Returns a temporary PQExpBuffer, valid until the next call to the function.
34  * This is used by fmtId and fmtQualifiedId.
35  *
36  * Non-reentrant and non-thread-safe but reduces memory leakage. You can
37  * replace this with a custom version by setting the getLocalPQExpBuffer
38  * function pointer.
39  */
40 static PQExpBuffer
defaultGetLocalPQExpBuffer(void)41 defaultGetLocalPQExpBuffer(void)
42 {
43 	static PQExpBuffer id_return = NULL;
44 
45 	if (id_return)				/* first time through? */
46 	{
47 		/* same buffer, just wipe contents */
48 		resetPQExpBuffer(id_return);
49 	}
50 	else
51 	{
52 		/* new buffer */
53 		id_return = createPQExpBuffer();
54 	}
55 
56 	return id_return;
57 }
58 
59 /*
60  *	Quotes input string if it's not a legitimate SQL identifier as-is.
61  *
62  *	Note that the returned string must be used before calling fmtId again,
63  *	since we re-use the same return buffer each time.
64  */
65 const char *
fmtId(const char * rawid)66 fmtId(const char *rawid)
67 {
68 	PQExpBuffer id_return = getLocalPQExpBuffer();
69 
70 	const char *cp;
71 	bool		need_quotes = false;
72 
73 	/*
74 	 * These checks need to match the identifier production in scan.l. Don't
75 	 * use islower() etc.
76 	 */
77 	if (quote_all_identifiers)
78 		need_quotes = true;
79 	/* slightly different rules for first character */
80 	else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
81 		need_quotes = true;
82 	else
83 	{
84 		/* otherwise check the entire string */
85 		for (cp = rawid; *cp; cp++)
86 		{
87 			if (!((*cp >= 'a' && *cp <= 'z')
88 				  || (*cp >= '0' && *cp <= '9')
89 				  || (*cp == '_')))
90 			{
91 				need_quotes = true;
92 				break;
93 			}
94 		}
95 	}
96 
97 	if (!need_quotes)
98 	{
99 		/*
100 		 * Check for keyword.  We quote keywords except for unreserved ones.
101 		 * (In some cases we could avoid quoting a col_name or type_func_name
102 		 * keyword, but it seems much harder than it's worth to tell that.)
103 		 *
104 		 * Note: ScanKeywordLookup() does case-insensitive comparison, but
105 		 * that's fine, since we already know we have all-lower-case.
106 		 */
107 		int			kwnum = ScanKeywordLookup(rawid, &ScanKeywords);
108 
109 		if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
110 			need_quotes = true;
111 	}
112 
113 	if (!need_quotes)
114 	{
115 		/* no quoting needed */
116 		appendPQExpBufferStr(id_return, rawid);
117 	}
118 	else
119 	{
120 		appendPQExpBufferChar(id_return, '"');
121 		for (cp = rawid; *cp; cp++)
122 		{
123 			/*
124 			 * Did we find a double-quote in the string? Then make this a
125 			 * double double-quote per SQL99. Before, we put in a
126 			 * backslash/double-quote pair. - thomas 2000-08-05
127 			 */
128 			if (*cp == '"')
129 				appendPQExpBufferChar(id_return, '"');
130 			appendPQExpBufferChar(id_return, *cp);
131 		}
132 		appendPQExpBufferChar(id_return, '"');
133 	}
134 
135 	return id_return->data;
136 }
137 
138 /*
139  * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
140  *
141  * Like fmtId, use the result before calling again.
142  *
143  * Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
144  * use that buffer until we're finished with calling fmtId().
145  */
146 const char *
fmtQualifiedId(const char * schema,const char * id)147 fmtQualifiedId(const char *schema, const char *id)
148 {
149 	PQExpBuffer id_return;
150 	PQExpBuffer lcl_pqexp = createPQExpBuffer();
151 
152 	/* Some callers might fail to provide a schema name */
153 	if (schema && *schema)
154 	{
155 		appendPQExpBuffer(lcl_pqexp, "%s.", fmtId(schema));
156 	}
157 	appendPQExpBufferStr(lcl_pqexp, fmtId(id));
158 
159 	id_return = getLocalPQExpBuffer();
160 
161 	appendPQExpBufferStr(id_return, lcl_pqexp->data);
162 	destroyPQExpBuffer(lcl_pqexp);
163 
164 	return id_return->data;
165 }
166 
167 
168 /*
169  * Format a Postgres version number (in the PG_VERSION_NUM integer format
170  * returned by PQserverVersion()) as a string.  This exists mainly to
171  * encapsulate knowledge about two-part vs. three-part version numbers.
172  *
173  * For reentrancy, caller must supply the buffer the string is put in.
174  * Recommended size of the buffer is 32 bytes.
175  *
176  * Returns address of 'buf', as a notational convenience.
177  */
178 char *
formatPGVersionNumber(int version_number,bool include_minor,char * buf,size_t buflen)179 formatPGVersionNumber(int version_number, bool include_minor,
180 					  char *buf, size_t buflen)
181 {
182 	if (version_number >= 100000)
183 	{
184 		/* New two-part style */
185 		if (include_minor)
186 			snprintf(buf, buflen, "%d.%d", version_number / 10000,
187 					 version_number % 10000);
188 		else
189 			snprintf(buf, buflen, "%d", version_number / 10000);
190 	}
191 	else
192 	{
193 		/* Old three-part style */
194 		if (include_minor)
195 			snprintf(buf, buflen, "%d.%d.%d", version_number / 10000,
196 					 (version_number / 100) % 100,
197 					 version_number % 100);
198 		else
199 			snprintf(buf, buflen, "%d.%d", version_number / 10000,
200 					 (version_number / 100) % 100);
201 	}
202 	return buf;
203 }
204 
205 
206 /*
207  * Convert a string value to an SQL string literal and append it to
208  * the given buffer.  We assume the specified client_encoding and
209  * standard_conforming_strings settings.
210  *
211  * This is essentially equivalent to libpq's PQescapeStringInternal,
212  * except for the output buffer structure.  We need it in situations
213  * where we do not have a PGconn available.  Where we do,
214  * appendStringLiteralConn is a better choice.
215  */
216 void
appendStringLiteral(PQExpBuffer buf,const char * str,int encoding,bool std_strings)217 appendStringLiteral(PQExpBuffer buf, const char *str,
218 					int encoding, bool std_strings)
219 {
220 	size_t		length = strlen(str);
221 	const char *source = str;
222 	char	   *target;
223 
224 	if (!enlargePQExpBuffer(buf, 2 * length + 2))
225 		return;
226 
227 	target = buf->data + buf->len;
228 	*target++ = '\'';
229 
230 	while (*source != '\0')
231 	{
232 		char		c = *source;
233 		int			len;
234 		int			i;
235 
236 		/* Fast path for plain ASCII */
237 		if (!IS_HIGHBIT_SET(c))
238 		{
239 			/* Apply quoting if needed */
240 			if (SQL_STR_DOUBLE(c, !std_strings))
241 				*target++ = c;
242 			/* Copy the character */
243 			*target++ = c;
244 			source++;
245 			continue;
246 		}
247 
248 		/* Slow path for possible multibyte characters */
249 		len = PQmblen(source, encoding);
250 
251 		/* Copy the character */
252 		for (i = 0; i < len; i++)
253 		{
254 			if (*source == '\0')
255 				break;
256 			*target++ = *source++;
257 		}
258 
259 		/*
260 		 * If we hit premature end of string (ie, incomplete multibyte
261 		 * character), try to pad out to the correct length with spaces. We
262 		 * may not be able to pad completely, but we will always be able to
263 		 * insert at least one pad space (since we'd not have quoted a
264 		 * multibyte character).  This should be enough to make a string that
265 		 * the server will error out on.
266 		 */
267 		if (i < len)
268 		{
269 			char	   *stop = buf->data + buf->maxlen - 2;
270 
271 			for (; i < len; i++)
272 			{
273 				if (target >= stop)
274 					break;
275 				*target++ = ' ';
276 			}
277 			break;
278 		}
279 	}
280 
281 	/* Write the terminating quote and NUL character. */
282 	*target++ = '\'';
283 	*target = '\0';
284 
285 	buf->len = target - buf->data;
286 }
287 
288 
289 /*
290  * Convert a string value to an SQL string literal and append it to
291  * the given buffer.  Encoding and string syntax rules are as indicated
292  * by current settings of the PGconn.
293  */
294 void
appendStringLiteralConn(PQExpBuffer buf,const char * str,PGconn * conn)295 appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
296 {
297 	size_t		length = strlen(str);
298 
299 	/*
300 	 * XXX This is a kluge to silence escape_string_warning in our utility
301 	 * programs.  It should go away someday.
302 	 */
303 	if (strchr(str, '\\') != NULL && PQserverVersion(conn) >= 80100)
304 	{
305 		/* ensure we are not adjacent to an identifier */
306 		if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
307 			appendPQExpBufferChar(buf, ' ');
308 		appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
309 		appendStringLiteral(buf, str, PQclientEncoding(conn), false);
310 		return;
311 	}
312 	/* XXX end kluge */
313 
314 	if (!enlargePQExpBuffer(buf, 2 * length + 2))
315 		return;
316 	appendPQExpBufferChar(buf, '\'');
317 	buf->len += PQescapeStringConn(conn, buf->data + buf->len,
318 								   str, length, NULL);
319 	appendPQExpBufferChar(buf, '\'');
320 }
321 
322 
323 /*
324  * Convert a string value to a dollar quoted literal and append it to
325  * the given buffer. If the dqprefix parameter is not NULL then the
326  * dollar quote delimiter will begin with that (after the opening $).
327  *
328  * No escaping is done at all on str, in compliance with the rules
329  * for parsing dollar quoted strings.  Also, we need not worry about
330  * encoding issues.
331  */
332 void
appendStringLiteralDQ(PQExpBuffer buf,const char * str,const char * dqprefix)333 appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
334 {
335 	static const char suffixes[] = "_XXXXXXX";
336 	int			nextchar = 0;
337 	PQExpBuffer delimBuf = createPQExpBuffer();
338 
339 	/* start with $ + dqprefix if not NULL */
340 	appendPQExpBufferChar(delimBuf, '$');
341 	if (dqprefix)
342 		appendPQExpBufferStr(delimBuf, dqprefix);
343 
344 	/*
345 	 * Make sure we choose a delimiter which (without the trailing $) is not
346 	 * present in the string being quoted. We don't check with the trailing $
347 	 * because a string ending in $foo must not be quoted with $foo$.
348 	 */
349 	while (strstr(str, delimBuf->data) != NULL)
350 	{
351 		appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
352 		nextchar %= sizeof(suffixes) - 1;
353 	}
354 
355 	/* add trailing $ */
356 	appendPQExpBufferChar(delimBuf, '$');
357 
358 	/* quote it and we are all done */
359 	appendPQExpBufferStr(buf, delimBuf->data);
360 	appendPQExpBufferStr(buf, str);
361 	appendPQExpBufferStr(buf, delimBuf->data);
362 
363 	destroyPQExpBuffer(delimBuf);
364 }
365 
366 
367 /*
368  * Convert a bytea value (presented as raw bytes) to an SQL string literal
369  * and append it to the given buffer.  We assume the specified
370  * standard_conforming_strings setting.
371  *
372  * This is needed in situations where we do not have a PGconn available.
373  * Where we do, PQescapeByteaConn is a better choice.
374  */
375 void
appendByteaLiteral(PQExpBuffer buf,const unsigned char * str,size_t length,bool std_strings)376 appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
377 				   bool std_strings)
378 {
379 	const unsigned char *source = str;
380 	char	   *target;
381 
382 	static const char hextbl[] = "0123456789abcdef";
383 
384 	/*
385 	 * This implementation is hard-wired to produce hex-format output. We do
386 	 * not know the server version the output will be loaded into, so making
387 	 * an intelligent format choice is impossible.  It might be better to
388 	 * always use the old escaped format.
389 	 */
390 	if (!enlargePQExpBuffer(buf, 2 * length + 5))
391 		return;
392 
393 	target = buf->data + buf->len;
394 	*target++ = '\'';
395 	if (!std_strings)
396 		*target++ = '\\';
397 	*target++ = '\\';
398 	*target++ = 'x';
399 
400 	while (length-- > 0)
401 	{
402 		unsigned char c = *source++;
403 
404 		*target++ = hextbl[(c >> 4) & 0xF];
405 		*target++ = hextbl[c & 0xF];
406 	}
407 
408 	/* Write the terminating quote and NUL character. */
409 	*target++ = '\'';
410 	*target = '\0';
411 
412 	buf->len = target - buf->data;
413 }
414 
415 
416 /*
417  * Append the given string to the shell command being built in the buffer,
418  * with shell-style quoting as needed to create exactly one argument.
419  *
420  * Forbid LF or CR characters, which have scant practical use beyond designing
421  * security breaches.  The Windows command shell is unusable as a conduit for
422  * arguments containing LF or CR characters.  A future major release should
423  * reject those characters in CREATE ROLE and CREATE DATABASE, because use
424  * there eventually leads to errors here.
425  *
426  * appendShellString() simply prints an error and dies if LF or CR appears.
427  * appendShellStringNoError() omits those characters from the result, and
428  * returns false if there were any.
429  */
430 void
appendShellString(PQExpBuffer buf,const char * str)431 appendShellString(PQExpBuffer buf, const char *str)
432 {
433 	if (!appendShellStringNoError(buf, str))
434 	{
435 		fprintf(stderr,
436 				_("shell command argument contains a newline or carriage return: \"%s\"\n"),
437 				str);
438 		exit(EXIT_FAILURE);
439 	}
440 }
441 
442 bool
appendShellStringNoError(PQExpBuffer buf,const char * str)443 appendShellStringNoError(PQExpBuffer buf, const char *str)
444 {
445 #ifdef WIN32
446 	int			backslash_run_length = 0;
447 #endif
448 	bool		ok = true;
449 	const char *p;
450 
451 	/*
452 	 * Don't bother with adding quotes if the string is nonempty and clearly
453 	 * contains only safe characters.
454 	 */
455 	if (*str != '\0' &&
456 		strspn(str, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./:") == strlen(str))
457 	{
458 		appendPQExpBufferStr(buf, str);
459 		return ok;
460 	}
461 
462 #ifndef WIN32
463 	appendPQExpBufferChar(buf, '\'');
464 	for (p = str; *p; p++)
465 	{
466 		if (*p == '\n' || *p == '\r')
467 		{
468 			ok = false;
469 			continue;
470 		}
471 
472 		if (*p == '\'')
473 			appendPQExpBufferStr(buf, "'\"'\"'");
474 		else
475 			appendPQExpBufferChar(buf, *p);
476 	}
477 	appendPQExpBufferChar(buf, '\'');
478 #else							/* WIN32 */
479 
480 	/*
481 	 * A Windows system() argument experiences two layers of interpretation.
482 	 * First, cmd.exe interprets the string.  Its behavior is undocumented,
483 	 * but a caret escapes any byte except LF or CR that would otherwise have
484 	 * special meaning.  Handling of a caret before LF or CR differs between
485 	 * "cmd.exe /c" and other modes, and it is unusable here.
486 	 *
487 	 * Second, the new process parses its command line to construct argv (see
488 	 * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx).  This treats
489 	 * backslash-double quote sequences specially.
490 	 */
491 	appendPQExpBufferStr(buf, "^\"");
492 	for (p = str; *p; p++)
493 	{
494 		if (*p == '\n' || *p == '\r')
495 		{
496 			ok = false;
497 			continue;
498 		}
499 
500 		/* Change N backslashes before a double quote to 2N+1 backslashes. */
501 		if (*p == '"')
502 		{
503 			while (backslash_run_length)
504 			{
505 				appendPQExpBufferStr(buf, "^\\");
506 				backslash_run_length--;
507 			}
508 			appendPQExpBufferStr(buf, "^\\");
509 		}
510 		else if (*p == '\\')
511 			backslash_run_length++;
512 		else
513 			backslash_run_length = 0;
514 
515 		/*
516 		 * Decline to caret-escape the most mundane characters, to ease
517 		 * debugging and lest we approach the command length limit.
518 		 */
519 		if (!((*p >= 'a' && *p <= 'z') ||
520 			  (*p >= 'A' && *p <= 'Z') ||
521 			  (*p >= '0' && *p <= '9')))
522 			appendPQExpBufferChar(buf, '^');
523 		appendPQExpBufferChar(buf, *p);
524 	}
525 
526 	/*
527 	 * Change N backslashes at end of argument to 2N backslashes, because they
528 	 * precede the double quote that terminates the argument.
529 	 */
530 	while (backslash_run_length)
531 	{
532 		appendPQExpBufferStr(buf, "^\\");
533 		backslash_run_length--;
534 	}
535 	appendPQExpBufferStr(buf, "^\"");
536 #endif							/* WIN32 */
537 
538 	return ok;
539 }
540 
541 
542 /*
543  * Append the given string to the buffer, with suitable quoting for passing
544  * the string as a value in a keyword/value pair in a libpq connection string.
545  */
546 void
appendConnStrVal(PQExpBuffer buf,const char * str)547 appendConnStrVal(PQExpBuffer buf, const char *str)
548 {
549 	const char *s;
550 	bool		needquotes;
551 
552 	/*
553 	 * If the string is one or more plain ASCII characters, no need to quote
554 	 * it. This is quite conservative, but better safe than sorry.
555 	 */
556 	needquotes = true;
557 	for (s = str; *s; s++)
558 	{
559 		if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
560 			  (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
561 		{
562 			needquotes = true;
563 			break;
564 		}
565 		needquotes = false;
566 	}
567 
568 	if (needquotes)
569 	{
570 		appendPQExpBufferChar(buf, '\'');
571 		while (*str)
572 		{
573 			/* ' and \ must be escaped by to \' and \\ */
574 			if (*str == '\'' || *str == '\\')
575 				appendPQExpBufferChar(buf, '\\');
576 
577 			appendPQExpBufferChar(buf, *str);
578 			str++;
579 		}
580 		appendPQExpBufferChar(buf, '\'');
581 	}
582 	else
583 		appendPQExpBufferStr(buf, str);
584 }
585 
586 
587 /*
588  * Append a psql meta-command that connects to the given database with the
589  * then-current connection's user, host and port.
590  */
591 void
appendPsqlMetaConnect(PQExpBuffer buf,const char * dbname)592 appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname)
593 {
594 	const char *s;
595 	bool complex;
596 
597 	/*
598 	 * If the name is plain ASCII characters, emit a trivial "\connect "foo"".
599 	 * For other names, even many not technically requiring it, skip to the
600 	 * general case.  No database has a zero-length name.
601 	 */
602 	complex = false;
603 
604 	for (s = dbname; *s; s++)
605 	{
606 		if (*s == '\n' || *s == '\r')
607 		{
608 			fprintf(stderr,
609 					_("database name contains a newline or carriage return: \"%s\"\n"),
610 					dbname);
611 			exit(EXIT_FAILURE);
612 		}
613 
614 		if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
615 			  (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
616 		{
617 			complex = true;
618 		}
619 	}
620 
621 	appendPQExpBufferStr(buf, "\\connect ");
622 	if (complex)
623 	{
624 		PQExpBufferData connstr;
625 
626 		initPQExpBuffer(&connstr);
627 		appendPQExpBuffer(&connstr, "dbname=");
628 		appendConnStrVal(&connstr, dbname);
629 
630 		appendPQExpBuffer(buf, "-reuse-previous=on ");
631 
632 		/*
633 		 * As long as the name does not contain a newline, SQL identifier
634 		 * quoting satisfies the psql meta-command parser.  Prefer not to
635 		 * involve psql-interpreted single quotes, which behaved differently
636 		 * before PostgreSQL 9.2.
637 		 */
638 		appendPQExpBufferStr(buf, fmtId(connstr.data));
639 
640 		termPQExpBuffer(&connstr);
641 	}
642 	else
643 		appendPQExpBufferStr(buf, fmtId(dbname));
644 	appendPQExpBufferChar(buf, '\n');
645 }
646 
647 
648 /*
649  * Deconstruct the text representation of a 1-dimensional Postgres array
650  * into individual items.
651  *
652  * On success, returns true and sets *itemarray and *nitems to describe
653  * an array of individual strings.  On parse failure, returns false;
654  * *itemarray may exist or be NULL.
655  *
656  * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
657  */
658 bool
parsePGArray(const char * atext,char *** itemarray,int * nitems)659 parsePGArray(const char *atext, char ***itemarray, int *nitems)
660 {
661 	int			inputlen;
662 	char	  **items;
663 	char	   *strings;
664 	int			curitem;
665 
666 	/*
667 	 * We expect input in the form of "{item,item,item}" where any item is
668 	 * either raw data, or surrounded by double quotes (in which case embedded
669 	 * characters including backslashes and quotes are backslashed).
670 	 *
671 	 * We build the result as an array of pointers followed by the actual
672 	 * string data, all in one malloc block for convenience of deallocation.
673 	 * The worst-case storage need is not more than one pointer and one
674 	 * character for each input character (consider "{,,,,,,,,,,}").
675 	 */
676 	*itemarray = NULL;
677 	*nitems = 0;
678 	inputlen = strlen(atext);
679 	if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
680 		return false;			/* bad input */
681 	items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
682 	if (items == NULL)
683 		return false;			/* out of memory */
684 	*itemarray = items;
685 	strings = (char *) (items + inputlen);
686 
687 	atext++;					/* advance over initial '{' */
688 	curitem = 0;
689 	while (*atext != '}')
690 	{
691 		if (*atext == '\0')
692 			return false;		/* premature end of string */
693 		items[curitem] = strings;
694 		while (*atext != '}' && *atext != ',')
695 		{
696 			if (*atext == '\0')
697 				return false;	/* premature end of string */
698 			if (*atext != '"')
699 				*strings++ = *atext++;	/* copy unquoted data */
700 			else
701 			{
702 				/* process quoted substring */
703 				atext++;
704 				while (*atext != '"')
705 				{
706 					if (*atext == '\0')
707 						return false;	/* premature end of string */
708 					if (*atext == '\\')
709 					{
710 						atext++;
711 						if (*atext == '\0')
712 							return false;	/* premature end of string */
713 					}
714 					*strings++ = *atext++;	/* copy quoted data */
715 				}
716 				atext++;
717 			}
718 		}
719 		*strings++ = '\0';
720 		if (*atext == ',')
721 			atext++;
722 		curitem++;
723 	}
724 	if (atext[1] != '\0')
725 		return false;			/* bogus syntax (embedded '}') */
726 	*nitems = curitem;
727 	return true;
728 }
729 
730 
731 /*
732  * Format a reloptions array and append it to the given buffer.
733  *
734  * "prefix" is prepended to the option names; typically it's "" or "toast.".
735  *
736  * Returns false if the reloptions array could not be parsed (in which case
737  * nothing will have been appended to the buffer), or true on success.
738  *
739  * Note: this logic should generally match the backend's flatten_reloptions()
740  * (in adt/ruleutils.c).
741  */
742 bool
appendReloptionsArray(PQExpBuffer buffer,const char * reloptions,const char * prefix,int encoding,bool std_strings)743 appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,
744 					  const char *prefix, int encoding, bool std_strings)
745 {
746 	char	  **options;
747 	int			noptions;
748 	int			i;
749 
750 	if (!parsePGArray(reloptions, &options, &noptions))
751 	{
752 		if (options)
753 			free(options);
754 		return false;
755 	}
756 
757 	for (i = 0; i < noptions; i++)
758 	{
759 		char	   *option = options[i];
760 		char	   *name;
761 		char	   *separator;
762 		char	   *value;
763 
764 		/*
765 		 * Each array element should have the form name=value.  If the "=" is
766 		 * missing for some reason, treat it like an empty value.
767 		 */
768 		name = option;
769 		separator = strchr(option, '=');
770 		if (separator)
771 		{
772 			*separator = '\0';
773 			value = separator + 1;
774 		}
775 		else
776 			value = "";
777 
778 		if (i > 0)
779 			appendPQExpBufferStr(buffer, ", ");
780 		appendPQExpBuffer(buffer, "%s%s=", prefix, fmtId(name));
781 
782 		/*
783 		 * In general we need to quote the value; but to avoid unnecessary
784 		 * clutter, do not quote if it is an identifier that would not need
785 		 * quoting.  (We could also allow numbers, but that is a bit trickier
786 		 * than it looks --- for example, are leading zeroes significant?  We
787 		 * don't want to assume very much here about what custom reloptions
788 		 * might mean.)
789 		 */
790 		if (strcmp(fmtId(value), value) == 0)
791 			appendPQExpBufferStr(buffer, value);
792 		else
793 			appendStringLiteral(buffer, value, encoding, std_strings);
794 	}
795 
796 	if (options)
797 		free(options);
798 
799 	return true;
800 }
801 
802 
803 /*
804  * processSQLNamePattern
805  *
806  * Scan a wildcard-pattern string and generate appropriate WHERE clauses
807  * to limit the set of objects returned.  The WHERE clauses are appended
808  * to the already-partially-constructed query in buf.  Returns whether
809  * any clause was added.
810  *
811  * conn: connection query will be sent to (consulted for escaping rules).
812  * buf: output parameter.
813  * pattern: user-specified pattern option, or NULL if none ("*" is implied).
814  * have_where: true if caller already emitted "WHERE" (clauses will be ANDed
815  * onto the existing WHERE clause).
816  * force_escape: always quote regexp special characters, even outside
817  * double quotes (else they are quoted only between double quotes).
818  * schemavar: name of query variable to match against a schema-name pattern.
819  * Can be NULL if no schema.
820  * namevar: name of query variable to match against an object-name pattern.
821  * altnamevar: NULL, or name of an alternative variable to match against name.
822  * visibilityrule: clause to use if we want to restrict to visible objects
823  * (for example, "pg_catalog.pg_table_is_visible(p.oid)").  Can be NULL.
824  *
825  * Formatting note: the text already present in buf should end with a newline.
826  * The appended text, if any, will end with one too.
827  */
828 bool
processSQLNamePattern(PGconn * conn,PQExpBuffer buf,const char * pattern,bool have_where,bool force_escape,const char * schemavar,const char * namevar,const char * altnamevar,const char * visibilityrule)829 processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
830 					  bool have_where, bool force_escape,
831 					  const char *schemavar, const char *namevar,
832 					  const char *altnamevar, const char *visibilityrule)
833 {
834 	PQExpBufferData schemabuf;
835 	PQExpBufferData namebuf;
836 	int			encoding = PQclientEncoding(conn);
837 	bool		inquotes;
838 	const char *cp;
839 	int			i;
840 	bool		added_clause = false;
841 
842 #define WHEREAND() \
843 	(appendPQExpBufferStr(buf, have_where ? "  AND " : "WHERE "), \
844 	 have_where = true, added_clause = true)
845 
846 	if (pattern == NULL)
847 	{
848 		/* Default: select all visible objects */
849 		if (visibilityrule)
850 		{
851 			WHEREAND();
852 			appendPQExpBuffer(buf, "%s\n", visibilityrule);
853 		}
854 		return added_clause;
855 	}
856 
857 	initPQExpBuffer(&schemabuf);
858 	initPQExpBuffer(&namebuf);
859 
860 	/*
861 	 * Parse the pattern, converting quotes and lower-casing unquoted letters.
862 	 * Also, adjust shell-style wildcard characters into regexp notation.
863 	 *
864 	 * We surround the pattern with "^(...)$" to force it to match the whole
865 	 * string, as per SQL practice.  We have to have parens in case the string
866 	 * contains "|", else the "^" and "$" will be bound into the first and
867 	 * last alternatives which is not what we want.
868 	 *
869 	 * Note: the result of this pass is the actual regexp pattern(s) we want
870 	 * to execute.  Quoting/escaping into SQL literal format will be done
871 	 * below using appendStringLiteralConn().
872 	 */
873 	appendPQExpBufferStr(&namebuf, "^(");
874 
875 	inquotes = false;
876 	cp = pattern;
877 
878 	while (*cp)
879 	{
880 		char		ch = *cp;
881 
882 		if (ch == '"')
883 		{
884 			if (inquotes && cp[1] == '"')
885 			{
886 				/* emit one quote, stay in inquotes mode */
887 				appendPQExpBufferChar(&namebuf, '"');
888 				cp++;
889 			}
890 			else
891 				inquotes = !inquotes;
892 			cp++;
893 		}
894 		else if (!inquotes && isupper((unsigned char) ch))
895 		{
896 			appendPQExpBufferChar(&namebuf,
897 								  pg_tolower((unsigned char) ch));
898 			cp++;
899 		}
900 		else if (!inquotes && ch == '*')
901 		{
902 			appendPQExpBufferStr(&namebuf, ".*");
903 			cp++;
904 		}
905 		else if (!inquotes && ch == '?')
906 		{
907 			appendPQExpBufferChar(&namebuf, '.');
908 			cp++;
909 		}
910 		else if (!inquotes && ch == '.')
911 		{
912 			/* Found schema/name separator, move current pattern to schema */
913 			resetPQExpBuffer(&schemabuf);
914 			appendPQExpBufferStr(&schemabuf, namebuf.data);
915 			resetPQExpBuffer(&namebuf);
916 			appendPQExpBufferStr(&namebuf, "^(");
917 			cp++;
918 		}
919 		else if (ch == '$')
920 		{
921 			/*
922 			 * Dollar is always quoted, whether inside quotes or not. The
923 			 * reason is that it's allowed in SQL identifiers, so there's a
924 			 * significant use-case for treating it literally, while because
925 			 * we anchor the pattern automatically there is no use-case for
926 			 * having it possess its regexp meaning.
927 			 */
928 			appendPQExpBufferStr(&namebuf, "\\$");
929 			cp++;
930 		}
931 		else
932 		{
933 			/*
934 			 * Ordinary data character, transfer to pattern
935 			 *
936 			 * Inside double quotes, or at all times if force_escape is true,
937 			 * quote regexp special characters with a backslash to avoid
938 			 * regexp errors.  Outside quotes, however, let them pass through
939 			 * as-is; this lets knowledgeable users build regexp expressions
940 			 * that are more powerful than shell-style patterns.
941 			 */
942 			if ((inquotes || force_escape) &&
943 				strchr("|*+?()[]{}.^$\\", ch))
944 				appendPQExpBufferChar(&namebuf, '\\');
945 			i = PQmblen(cp, encoding);
946 			while (i-- && *cp)
947 			{
948 				appendPQExpBufferChar(&namebuf, *cp);
949 				cp++;
950 			}
951 		}
952 	}
953 
954 	/*
955 	 * Now decide what we need to emit.  We may run under a hostile
956 	 * search_path, so qualify EVERY name.  Note there will be a leading "^("
957 	 * in the patterns in any case.
958 	 *
959 	 * We want the regex matches to use the database's default collation where
960 	 * collation-sensitive behavior is required (for example, which characters
961 	 * match '\w').  That happened by default before PG v12, but if the server
962 	 * is >= v12 then we need to force it through explicit COLLATE clauses,
963 	 * otherwise the "C" collation attached to "name" catalog columns wins.
964 	 */
965 	if (namebuf.len > 2)
966 	{
967 		/* We have a name pattern, so constrain the namevar(s) */
968 
969 		appendPQExpBufferStr(&namebuf, ")$");
970 		/* Optimize away a "*" pattern */
971 		if (strcmp(namebuf.data, "^(.*)$") != 0)
972 		{
973 			WHEREAND();
974 			if (altnamevar)
975 			{
976 				appendPQExpBuffer(buf,
977 								  "(%s OPERATOR(pg_catalog.~) ", namevar);
978 				appendStringLiteralConn(buf, namebuf.data, conn);
979 				if (PQserverVersion(conn) >= 120000)
980 					appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
981 				appendPQExpBuffer(buf,
982 								  "\n        OR %s OPERATOR(pg_catalog.~) ",
983 								  altnamevar);
984 				appendStringLiteralConn(buf, namebuf.data, conn);
985 				if (PQserverVersion(conn) >= 120000)
986 					appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
987 				appendPQExpBufferStr(buf, ")\n");
988 			}
989 			else
990 			{
991 				appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", namevar);
992 				appendStringLiteralConn(buf, namebuf.data, conn);
993 				if (PQserverVersion(conn) >= 120000)
994 					appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
995 				appendPQExpBufferChar(buf, '\n');
996 			}
997 		}
998 	}
999 
1000 	if (schemabuf.len > 2)
1001 	{
1002 		/* We have a schema pattern, so constrain the schemavar */
1003 
1004 		appendPQExpBufferStr(&schemabuf, ")$");
1005 		/* Optimize away a "*" pattern */
1006 		if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
1007 		{
1008 			WHEREAND();
1009 			appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", schemavar);
1010 			appendStringLiteralConn(buf, schemabuf.data, conn);
1011 			if (PQserverVersion(conn) >= 120000)
1012 				appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
1013 			appendPQExpBufferChar(buf, '\n');
1014 		}
1015 	}
1016 	else
1017 	{
1018 		/* No schema pattern given, so select only visible objects */
1019 		if (visibilityrule)
1020 		{
1021 			WHEREAND();
1022 			appendPQExpBuffer(buf, "%s\n", visibilityrule);
1023 		}
1024 	}
1025 
1026 	termPQExpBuffer(&schemabuf);
1027 	termPQExpBuffer(&namebuf);
1028 
1029 	return added_clause;
1030 #undef WHEREAND
1031 }
1032