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