Line data Source code
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-2026, 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 "common/keywords.h"
21 : #include "fe_utils/string_utils.h"
22 : #include "mb/pg_wchar.h"
23 :
24 : static PQExpBuffer defaultGetLocalPQExpBuffer(void);
25 :
26 : /* Globals exported by this file */
27 : int quote_all_identifiers = 0;
28 : PQExpBuffer (*getLocalPQExpBuffer) (void) = defaultGetLocalPQExpBuffer;
29 :
30 : static int fmtIdEncoding = -1;
31 :
32 :
33 : /*
34 : * Returns a temporary PQExpBuffer, valid until the next call to the function.
35 : * This is used by fmtId and fmtQualifiedId.
36 : *
37 : * Non-reentrant and non-thread-safe but reduces memory leakage. You can
38 : * replace this with a custom version by setting the getLocalPQExpBuffer
39 : * function pointer.
40 : */
41 : static PQExpBuffer
42 377255 : defaultGetLocalPQExpBuffer(void)
43 : {
44 : static PQExpBuffer id_return = NULL;
45 :
46 377255 : if (id_return) /* first time through? */
47 : {
48 : /* same buffer, just wipe contents */
49 376784 : resetPQExpBuffer(id_return);
50 : }
51 : else
52 : {
53 : /* new buffer */
54 471 : id_return = createPQExpBuffer();
55 : }
56 :
57 377255 : return id_return;
58 : }
59 :
60 : /*
61 : * Set the encoding that fmtId() and fmtQualifiedId() use.
62 : *
63 : * This is not safe against multiple connections having different encodings,
64 : * but there is no real other way to address the need to know the encoding for
65 : * fmtId()/fmtQualifiedId() input for safe escaping. Eventually we should get
66 : * rid of fmtId().
67 : */
68 : void
69 11245 : setFmtEncoding(int encoding)
70 : {
71 11245 : fmtIdEncoding = encoding;
72 11245 : }
73 :
74 : /*
75 : * Return the currently configured encoding for fmtId() and fmtQualifiedId().
76 : */
77 : static int
78 252628 : getFmtEncoding(void)
79 : {
80 252628 : if (fmtIdEncoding != -1)
81 252628 : return fmtIdEncoding;
82 :
83 : /*
84 : * In assertion builds it seems best to fail hard if the encoding was not
85 : * set, to make it easier to find places with missing calls. But in
86 : * production builds that seems like a bad idea, thus we instead just
87 : * default to UTF-8.
88 : */
89 : Assert(fmtIdEncoding != -1);
90 :
91 0 : return PG_UTF8;
92 : }
93 :
94 : /*
95 : * Quotes input string if it's not a legitimate SQL identifier as-is.
96 : *
97 : * Note that the returned string must be used before calling fmtIdEnc again,
98 : * since we re-use the same return buffer each time.
99 : */
100 : const char *
101 318150 : fmtIdEnc(const char *rawid, int encoding)
102 : {
103 318150 : PQExpBuffer id_return = getLocalPQExpBuffer();
104 :
105 : const char *cp;
106 318150 : bool need_quotes = false;
107 318150 : size_t remaining = strlen(rawid);
108 :
109 : /*
110 : * These checks need to match the identifier production in scan.l. Don't
111 : * use islower() etc.
112 : */
113 318150 : if (quote_all_identifiers)
114 24146 : need_quotes = true;
115 : /* slightly different rules for first character */
116 294004 : else if (!((rawid[0] >= 'a' && rawid[0] <= 'z') || rawid[0] == '_'))
117 739 : need_quotes = true;
118 : else
119 : {
120 : /* otherwise check the entire string */
121 293265 : cp = rawid;
122 3205833 : for (size_t i = 0; i < remaining; i++, cp++)
123 : {
124 2923628 : if (!((*cp >= 'a' && *cp <= 'z')
125 385260 : || (*cp >= '0' && *cp <= '9')
126 268695 : || (*cp == '_')))
127 : {
128 11060 : need_quotes = true;
129 11060 : break;
130 : }
131 : }
132 : }
133 :
134 318150 : if (!need_quotes)
135 : {
136 : /*
137 : * Check for keyword. We quote keywords except for unreserved ones.
138 : * (In some cases we could avoid quoting a col_name or type_func_name
139 : * keyword, but it seems much harder than it's worth to tell that.)
140 : *
141 : * Note: ScanKeywordLookup() does case-insensitive comparison, but
142 : * that's fine, since we already know we have all-lower-case.
143 : */
144 282205 : int kwnum = ScanKeywordLookup(rawid, &ScanKeywords);
145 :
146 282205 : if (kwnum >= 0 && ScanKeywordCategories[kwnum] != UNRESERVED_KEYWORD)
147 738 : need_quotes = true;
148 : }
149 :
150 318150 : if (!need_quotes)
151 : {
152 : /* no quoting needed */
153 281467 : appendPQExpBufferStr(id_return, rawid);
154 : }
155 : else
156 : {
157 36683 : appendPQExpBufferChar(id_return, '"');
158 :
159 36683 : cp = &rawid[0];
160 436180 : while (remaining > 0)
161 : {
162 : int charlen;
163 :
164 : /* Fast path for plain ASCII */
165 399497 : if (!IS_HIGHBIT_SET(*cp))
166 : {
167 : /*
168 : * Did we find a double-quote in the string? Then make this a
169 : * double double-quote per SQL99. Before, we put in a
170 : * backslash/double-quote pair. - thomas 2000-08-05
171 : */
172 397011 : if (*cp == '"')
173 344 : appendPQExpBufferChar(id_return, '"');
174 397011 : appendPQExpBufferChar(id_return, *cp);
175 397011 : remaining--;
176 397011 : cp++;
177 397011 : continue;
178 : }
179 :
180 : /* Slow path for possible multibyte characters */
181 2486 : charlen = pg_encoding_mblen(encoding, cp);
182 :
183 4945 : if (remaining < charlen ||
184 2459 : pg_encoding_verifymbchar(encoding, cp, charlen) == -1)
185 : {
186 : /*
187 : * Multibyte character is invalid. It's important to verify
188 : * that as invalid multibyte characters could e.g. be used to
189 : * "skip" over quote characters, e.g. when parsing
190 : * character-by-character.
191 : *
192 : * Replace the character's first byte with an invalid
193 : * sequence. The invalid sequence ensures that the escaped
194 : * string will trigger an error on the server-side, even if we
195 : * can't directly report an error here.
196 : *
197 : * It would be a bit faster to verify the whole string the
198 : * first time we encounter a set highbit, but this way we can
199 : * replace just the invalid data, which probably makes it
200 : * easier for users to find the invalidly encoded portion of a
201 : * larger string.
202 : */
203 40 : if (enlargePQExpBuffer(id_return, 2))
204 : {
205 40 : pg_encoding_set_invalid(encoding,
206 40 : id_return->data + id_return->len);
207 40 : id_return->len += 2;
208 40 : id_return->data[id_return->len] = '\0';
209 : }
210 :
211 : /*
212 : * Handle the following bytes as if this byte didn't exist.
213 : * That's safer in case the subsequent bytes contain
214 : * characters that are significant for the caller (e.g. '>' in
215 : * html).
216 : */
217 40 : remaining--;
218 40 : cp++;
219 : }
220 : else
221 : {
222 4905 : for (int i = 0; i < charlen; i++)
223 : {
224 2459 : appendPQExpBufferChar(id_return, *cp);
225 2459 : remaining--;
226 2459 : cp++;
227 : }
228 : }
229 : }
230 :
231 36683 : appendPQExpBufferChar(id_return, '"');
232 : }
233 :
234 318150 : return id_return->data;
235 : }
236 :
237 : /*
238 : * Quotes input string if it's not a legitimate SQL identifier as-is.
239 : *
240 : * Note that the returned string must be used before calling fmtId again,
241 : * since we re-use the same return buffer each time.
242 : *
243 : * NB: This assumes setFmtEncoding() previously has been called to configure
244 : * the encoding of rawid. It is preferable to use fmtIdEnc() with an
245 : * explicit encoding.
246 : */
247 : const char *
248 199869 : fmtId(const char *rawid)
249 : {
250 199869 : return fmtIdEnc(rawid, getFmtEncoding());
251 : }
252 :
253 : /*
254 : * fmtQualifiedIdEnc - construct a schema-qualified name, with quoting as
255 : * needed.
256 : *
257 : * Like fmtId, use the result before calling again.
258 : *
259 : * Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
260 : * use that buffer until we're finished with calling fmtId().
261 : */
262 : const char *
263 59105 : fmtQualifiedIdEnc(const char *schema, const char *id, int encoding)
264 : {
265 : PQExpBuffer id_return;
266 59105 : PQExpBuffer lcl_pqexp = createPQExpBuffer();
267 :
268 : /* Some callers might fail to provide a schema name */
269 59105 : if (schema && *schema)
270 : {
271 59105 : appendPQExpBuffer(lcl_pqexp, "%s.", fmtIdEnc(schema, encoding));
272 : }
273 59105 : appendPQExpBufferStr(lcl_pqexp, fmtIdEnc(id, encoding));
274 :
275 59105 : id_return = getLocalPQExpBuffer();
276 :
277 59105 : appendPQExpBufferStr(id_return, lcl_pqexp->data);
278 59105 : destroyPQExpBuffer(lcl_pqexp);
279 :
280 59105 : return id_return->data;
281 : }
282 :
283 : /*
284 : * fmtQualifiedId - construct a schema-qualified name, with quoting as needed.
285 : *
286 : * Like fmtId, use the result before calling again.
287 : *
288 : * Since we call fmtId and it also uses getLocalPQExpBuffer() we cannot
289 : * use that buffer until we're finished with calling fmtId().
290 : *
291 : * NB: This assumes setFmtEncoding() previously has been called to configure
292 : * the encoding of schema/id. It is preferable to use fmtQualifiedIdEnc()
293 : * with an explicit encoding.
294 : */
295 : const char *
296 52759 : fmtQualifiedId(const char *schema, const char *id)
297 : {
298 52759 : return fmtQualifiedIdEnc(schema, id, getFmtEncoding());
299 : }
300 :
301 :
302 : /*
303 : * Format a Postgres version number (in the PG_VERSION_NUM integer format
304 : * returned by PQserverVersion()) as a string. This exists mainly to
305 : * encapsulate knowledge about two-part vs. three-part version numbers.
306 : *
307 : * For reentrancy, caller must supply the buffer the string is put in.
308 : * Recommended size of the buffer is 32 bytes.
309 : *
310 : * Returns address of 'buf', as a notational convenience.
311 : */
312 : char *
313 0 : formatPGVersionNumber(int version_number, bool include_minor,
314 : char *buf, size_t buflen)
315 : {
316 0 : if (version_number >= 100000)
317 : {
318 : /* New two-part style */
319 0 : if (include_minor)
320 0 : snprintf(buf, buflen, "%d.%d", version_number / 10000,
321 : version_number % 10000);
322 : else
323 0 : snprintf(buf, buflen, "%d", version_number / 10000);
324 : }
325 : else
326 : {
327 : /* Old three-part style */
328 0 : if (include_minor)
329 0 : snprintf(buf, buflen, "%d.%d.%d", version_number / 10000,
330 0 : (version_number / 100) % 100,
331 : version_number % 100);
332 : else
333 0 : snprintf(buf, buflen, "%d.%d", version_number / 10000,
334 0 : (version_number / 100) % 100);
335 : }
336 0 : return buf;
337 : }
338 :
339 :
340 : /*
341 : * Convert a string value to an SQL string literal and append it to
342 : * the given buffer. We assume the specified client_encoding and
343 : * standard_conforming_strings settings.
344 : *
345 : * This is essentially equivalent to libpq's PQescapeStringInternal,
346 : * except for the output buffer structure. We need it in situations
347 : * where we do not have a PGconn available. Where we do,
348 : * appendStringLiteralConn is a better choice.
349 : */
350 : void
351 40346 : appendStringLiteral(PQExpBuffer buf, const char *str,
352 : int encoding, bool std_strings)
353 : {
354 40346 : size_t length = strlen(str);
355 40346 : const char *source = str;
356 : char *target;
357 40346 : size_t remaining = length;
358 :
359 40346 : if (!enlargePQExpBuffer(buf, 2 * length + 2))
360 0 : return;
361 :
362 40346 : target = buf->data + buf->len;
363 40346 : *target++ = '\'';
364 :
365 1009589 : while (remaining > 0)
366 : {
367 969243 : char c = *source;
368 : int charlen;
369 : int i;
370 :
371 : /* Fast path for plain ASCII */
372 969243 : if (!IS_HIGHBIT_SET(c))
373 : {
374 : /* Apply quoting if needed */
375 969189 : if (SQL_STR_DOUBLE(c, !std_strings))
376 205 : *target++ = c;
377 : /* Copy the character */
378 969189 : *target++ = c;
379 969189 : source++;
380 969189 : remaining--;
381 969189 : continue;
382 : }
383 :
384 : /* Slow path for possible multibyte characters */
385 54 : charlen = PQmblen(source, encoding);
386 :
387 81 : if (remaining < charlen ||
388 27 : pg_encoding_verifymbchar(encoding, source, charlen) == -1)
389 : {
390 : /*
391 : * Multibyte character is invalid. It's important to verify that
392 : * as invalid multibyte characters could e.g. be used to "skip"
393 : * over quote characters, e.g. when parsing
394 : * character-by-character.
395 : *
396 : * Replace the character's first byte with an invalid sequence.
397 : * The invalid sequence ensures that the escaped string will
398 : * trigger an error on the server-side, even if we can't directly
399 : * report an error here.
400 : *
401 : * We know there's enough space for the invalid sequence because
402 : * the "target" buffer is 2 * length + 2 long, and at worst we're
403 : * replacing a single input byte with two invalid bytes.
404 : *
405 : * It would be a bit faster to verify the whole string the first
406 : * time we encounter a set highbit, but this way we can replace
407 : * just the invalid data, which probably makes it easier for users
408 : * to find the invalidly encoded portion of a larger string.
409 : */
410 40 : pg_encoding_set_invalid(encoding, target);
411 40 : target += 2;
412 :
413 : /*
414 : * Handle the following bytes as if this byte didn't exist. That's
415 : * safer in case the subsequent bytes contain important characters
416 : * for the caller (e.g. '>' in html).
417 : */
418 40 : source++;
419 40 : remaining--;
420 : }
421 : else
422 : {
423 : /* Copy the character */
424 41 : for (i = 0; i < charlen; i++)
425 : {
426 27 : *target++ = *source++;
427 27 : remaining--;
428 : }
429 : }
430 : }
431 :
432 : /* Write the terminating quote and NUL character. */
433 40346 : *target++ = '\'';
434 40346 : *target = '\0';
435 :
436 40346 : buf->len = target - buf->data;
437 : }
438 :
439 :
440 : /*
441 : * Convert a string value to an SQL string literal and append it to
442 : * the given buffer. Encoding and string syntax rules are as indicated
443 : * by current settings of the PGconn.
444 : */
445 : void
446 6319 : appendStringLiteralConn(PQExpBuffer buf, const char *str, PGconn *conn)
447 : {
448 6319 : size_t length = strlen(str);
449 :
450 : /*
451 : * XXX This is a kluge to silence escape_string_warning in our utility
452 : * programs. It can go away once pre-v19 servers are out of support.
453 : */
454 6319 : if (strchr(str, '\\') != NULL && PQserverVersion(conn) < 190000)
455 : {
456 : /* ensure we are not adjacent to an identifier */
457 0 : if (buf->len > 0 && buf->data[buf->len - 1] != ' ')
458 0 : appendPQExpBufferChar(buf, ' ');
459 0 : appendPQExpBufferChar(buf, ESCAPE_STRING_SYNTAX);
460 0 : appendStringLiteral(buf, str, PQclientEncoding(conn), false);
461 0 : return;
462 : }
463 : /* XXX end kluge */
464 :
465 6319 : if (!enlargePQExpBuffer(buf, 2 * length + 2))
466 0 : return;
467 6319 : appendPQExpBufferChar(buf, '\'');
468 6319 : buf->len += PQescapeStringConn(conn, buf->data + buf->len,
469 : str, length, NULL);
470 6319 : appendPQExpBufferChar(buf, '\'');
471 : }
472 :
473 :
474 : /*
475 : * Convert a string value to a dollar quoted literal and append it to
476 : * the given buffer. If the dqprefix parameter is not NULL then the
477 : * dollar quote delimiter will begin with that (after the opening $).
478 : *
479 : * No escaping is done at all on str, in compliance with the rules
480 : * for parsing dollar quoted strings. Also, we need not worry about
481 : * encoding issues.
482 : */
483 : void
484 1637 : appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
485 : {
486 : static const char suffixes[] = "_XXXXXXX";
487 1637 : int nextchar = 0;
488 1637 : PQExpBuffer delimBuf = createPQExpBuffer();
489 :
490 : /* start with $ + dqprefix if not NULL */
491 1637 : appendPQExpBufferChar(delimBuf, '$');
492 1637 : if (dqprefix)
493 0 : appendPQExpBufferStr(delimBuf, dqprefix);
494 :
495 : /*
496 : * Make sure we choose a delimiter which (without the trailing $) is not
497 : * present in the string being quoted. We don't check with the trailing $
498 : * because a string ending in $foo must not be quoted with $foo$.
499 : */
500 2163 : while (strstr(str, delimBuf->data) != NULL)
501 : {
502 526 : appendPQExpBufferChar(delimBuf, suffixes[nextchar++]);
503 526 : nextchar %= sizeof(suffixes) - 1;
504 : }
505 :
506 : /* add trailing $ */
507 1637 : appendPQExpBufferChar(delimBuf, '$');
508 :
509 : /* quote it and we are all done */
510 1637 : appendPQExpBufferStr(buf, delimBuf->data);
511 1637 : appendPQExpBufferStr(buf, str);
512 1637 : appendPQExpBufferStr(buf, delimBuf->data);
513 :
514 1637 : destroyPQExpBuffer(delimBuf);
515 1637 : }
516 :
517 :
518 : /*
519 : * Convert a bytea value (presented as raw bytes) to an SQL string literal
520 : * and append it to the given buffer. We assume the specified
521 : * standard_conforming_strings setting.
522 : *
523 : * This is needed in situations where we do not have a PGconn available.
524 : * Where we do, PQescapeByteaConn is a better choice.
525 : */
526 : void
527 45 : appendByteaLiteral(PQExpBuffer buf, const unsigned char *str, size_t length,
528 : bool std_strings)
529 : {
530 45 : const unsigned char *source = str;
531 : char *target;
532 :
533 : static const char hextbl[] = "0123456789abcdef";
534 :
535 : /*
536 : * This implementation is hard-wired to produce hex-format output. We do
537 : * not know the server version the output will be loaded into, so making
538 : * an intelligent format choice is impossible. It might be better to
539 : * always use the old escaped format.
540 : */
541 45 : if (!enlargePQExpBuffer(buf, 2 * length + 5))
542 0 : return;
543 :
544 45 : target = buf->data + buf->len;
545 45 : *target++ = '\'';
546 45 : if (!std_strings)
547 0 : *target++ = '\\';
548 45 : *target++ = '\\';
549 45 : *target++ = 'x';
550 :
551 4119 : while (length-- > 0)
552 : {
553 4074 : unsigned char c = *source++;
554 :
555 4074 : *target++ = hextbl[(c >> 4) & 0xF];
556 4074 : *target++ = hextbl[c & 0xF];
557 : }
558 :
559 : /* Write the terminating quote and NUL character. */
560 45 : *target++ = '\'';
561 45 : *target = '\0';
562 :
563 45 : buf->len = target - buf->data;
564 : }
565 :
566 :
567 : /*
568 : * Append the given string to the shell command being built in the buffer,
569 : * with shell-style quoting as needed to create exactly one argument.
570 : *
571 : * Forbid LF or CR characters, which have scant practical use beyond designing
572 : * security breaches. The Windows command shell is unusable as a conduit for
573 : * arguments containing LF or CR characters.
574 : *
575 : * appendShellString() simply prints an error and dies if LF or CR appears.
576 : * appendShellStringNoError() omits those characters from the result, and
577 : * returns false if there were any.
578 : */
579 : void
580 548 : appendShellString(PQExpBuffer buf, const char *str)
581 : {
582 548 : if (!appendShellStringNoError(buf, str))
583 : {
584 0 : fprintf(stderr,
585 0 : _("shell command argument contains a newline or carriage return: \"%s\"\n"),
586 : str);
587 0 : exit(EXIT_FAILURE);
588 : }
589 548 : }
590 :
591 : bool
592 548 : appendShellStringNoError(PQExpBuffer buf, const char *str)
593 : {
594 : #ifdef WIN32
595 : int backslash_run_length = 0;
596 : #endif
597 548 : bool ok = true;
598 : const char *p;
599 :
600 : /*
601 : * Don't bother with adding quotes if the string is nonempty and clearly
602 : * contains only safe characters.
603 : */
604 548 : if (*str != '\0' &&
605 548 : strspn(str, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_./:") == strlen(str))
606 : {
607 462 : appendPQExpBufferStr(buf, str);
608 462 : return ok;
609 : }
610 :
611 : #ifndef WIN32
612 86 : appendPQExpBufferChar(buf, '\'');
613 3379 : for (p = str; *p; p++)
614 : {
615 3293 : if (*p == '\n' || *p == '\r')
616 : {
617 0 : ok = false;
618 0 : continue;
619 : }
620 :
621 3293 : if (*p == '\'')
622 84 : appendPQExpBufferStr(buf, "'\"'\"'");
623 : else
624 3209 : appendPQExpBufferChar(buf, *p);
625 : }
626 86 : appendPQExpBufferChar(buf, '\'');
627 : #else /* WIN32 */
628 :
629 : /*
630 : * A Windows system() argument experiences two layers of interpretation.
631 : * First, cmd.exe interprets the string. Its behavior is undocumented,
632 : * but a caret escapes any byte except LF or CR that would otherwise have
633 : * special meaning. Handling of a caret before LF or CR differs between
634 : * "cmd.exe /c" and other modes, and it is unusable here.
635 : *
636 : * Second, the new process parses its command line to construct argv (see
637 : * https://msdn.microsoft.com/en-us/library/17w5ykft.aspx). This treats
638 : * backslash-double quote sequences specially.
639 : */
640 : appendPQExpBufferStr(buf, "^\"");
641 : for (p = str; *p; p++)
642 : {
643 : if (*p == '\n' || *p == '\r')
644 : {
645 : ok = false;
646 : continue;
647 : }
648 :
649 : /* Change N backslashes before a double quote to 2N+1 backslashes. */
650 : if (*p == '"')
651 : {
652 : while (backslash_run_length)
653 : {
654 : appendPQExpBufferStr(buf, "^\\");
655 : backslash_run_length--;
656 : }
657 : appendPQExpBufferStr(buf, "^\\");
658 : }
659 : else if (*p == '\\')
660 : backslash_run_length++;
661 : else
662 : backslash_run_length = 0;
663 :
664 : /*
665 : * Decline to caret-escape the most mundane characters, to ease
666 : * debugging and lest we approach the command length limit.
667 : */
668 : if (!((*p >= 'a' && *p <= 'z') ||
669 : (*p >= 'A' && *p <= 'Z') ||
670 : (*p >= '0' && *p <= '9')))
671 : appendPQExpBufferChar(buf, '^');
672 : appendPQExpBufferChar(buf, *p);
673 : }
674 :
675 : /*
676 : * Change N backslashes at end of argument to 2N backslashes, because they
677 : * precede the double quote that terminates the argument.
678 : */
679 : while (backslash_run_length)
680 : {
681 : appendPQExpBufferStr(buf, "^\\");
682 : backslash_run_length--;
683 : }
684 : appendPQExpBufferStr(buf, "^\"");
685 : #endif /* WIN32 */
686 :
687 86 : return ok;
688 : }
689 :
690 :
691 : /*
692 : * Append the given string to the buffer, with suitable quoting for passing
693 : * the string as a value in a keyword/value pair in a libpq connection string.
694 : */
695 : void
696 2531 : appendConnStrVal(PQExpBuffer buf, const char *str)
697 : {
698 : const char *s;
699 : bool needquotes;
700 :
701 : /*
702 : * If the string is one or more plain ASCII characters, no need to quote
703 : * it. This is quite conservative, but better safe than sorry.
704 : */
705 2531 : needquotes = true;
706 17219 : for (s = str; *s; s++)
707 : {
708 15533 : if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
709 1965 : (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
710 : {
711 845 : needquotes = true;
712 845 : break;
713 : }
714 14688 : needquotes = false;
715 : }
716 :
717 2531 : if (needquotes)
718 : {
719 845 : appendPQExpBufferChar(buf, '\'');
720 17767 : while (*str)
721 : {
722 : /* ' and \ must be escaped by to \' and \\ */
723 16922 : if (*str == '\'' || *str == '\\')
724 302 : appendPQExpBufferChar(buf, '\\');
725 :
726 16922 : appendPQExpBufferChar(buf, *str);
727 16922 : str++;
728 : }
729 845 : appendPQExpBufferChar(buf, '\'');
730 : }
731 : else
732 1686 : appendPQExpBufferStr(buf, str);
733 2531 : }
734 :
735 :
736 : /*
737 : * Append a psql meta-command that connects to the given database with the
738 : * then-current connection's user, host and port.
739 : */
740 : void
741 35 : appendPsqlMetaConnect(PQExpBuffer buf, const char *dbname)
742 : {
743 : const char *s;
744 : bool complex;
745 :
746 : /*
747 : * If the name is plain ASCII characters, emit a trivial "\connect "foo"".
748 : * For other names, even many not technically requiring it, skip to the
749 : * general case. No database has a zero-length name.
750 : */
751 35 : complex = false;
752 :
753 911 : for (s = dbname; *s; s++)
754 : {
755 876 : if (*s == '\n' || *s == '\r')
756 : {
757 0 : fprintf(stderr,
758 0 : _("database name contains a newline or carriage return: \"%s\"\n"),
759 : dbname);
760 0 : exit(EXIT_FAILURE);
761 : }
762 :
763 876 : if (!((*s >= 'a' && *s <= 'z') || (*s >= 'A' && *s <= 'Z') ||
764 385 : (*s >= '0' && *s <= '9') || *s == '_' || *s == '.'))
765 : {
766 327 : complex = true;
767 : }
768 : }
769 :
770 35 : if (complex)
771 : {
772 : PQExpBufferData connstr;
773 :
774 10 : initPQExpBuffer(&connstr);
775 :
776 : /*
777 : * Force the target psql's encoding to SQL_ASCII. We don't really
778 : * know the encoding of the database name, and it doesn't matter as
779 : * long as psql will forward it to the server unchanged.
780 : */
781 10 : appendPQExpBufferStr(buf, "\\encoding SQL_ASCII\n");
782 10 : appendPQExpBufferStr(buf, "\\connect -reuse-previous=on ");
783 :
784 10 : appendPQExpBufferStr(&connstr, "dbname=");
785 10 : appendConnStrVal(&connstr, dbname);
786 :
787 : /*
788 : * As long as the name does not contain a newline, SQL identifier
789 : * quoting satisfies the psql meta-command parser. Prefer not to
790 : * involve psql-interpreted single quotes, which behaved differently
791 : * before PostgreSQL 9.2.
792 : */
793 10 : appendPQExpBufferStr(buf, fmtIdEnc(connstr.data, PG_SQL_ASCII));
794 :
795 10 : termPQExpBuffer(&connstr);
796 : }
797 : else
798 : {
799 25 : appendPQExpBufferStr(buf, "\\connect ");
800 25 : appendPQExpBufferStr(buf, fmtIdEnc(dbname, PG_SQL_ASCII));
801 : }
802 35 : appendPQExpBufferChar(buf, '\n');
803 35 : }
804 :
805 :
806 : /*
807 : * Deconstruct the text representation of a 1-dimensional Postgres array
808 : * into individual items.
809 : *
810 : * On success, returns true and sets *itemarray and *nitems to describe
811 : * an array of individual strings. On parse failure, returns false;
812 : * *itemarray may exist or be NULL.
813 : *
814 : * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
815 : */
816 : bool
817 63286 : parsePGArray(const char *atext, char ***itemarray, int *nitems)
818 : {
819 : int inputlen;
820 : char **items;
821 : char *strings;
822 : int curitem;
823 :
824 : /*
825 : * We expect input in the form of "{item,item,item}" where any item is
826 : * either raw data, or surrounded by double quotes (in which case embedded
827 : * characters including backslashes and quotes are backslashed).
828 : *
829 : * We build the result as an array of pointers followed by the actual
830 : * string data, all in one malloc block for convenience of deallocation.
831 : * The worst-case storage need is not more than one pointer and one
832 : * character for each input character (consider "{,,,,,,,,,,}").
833 : */
834 63286 : *itemarray = NULL;
835 63286 : *nitems = 0;
836 63286 : inputlen = strlen(atext);
837 63286 : if (inputlen < 2 || atext[0] != '{' || atext[inputlen - 1] != '}')
838 0 : return false; /* bad input */
839 63286 : items = (char **) malloc(inputlen * (sizeof(char *) + sizeof(char)));
840 63286 : if (items == NULL)
841 0 : return false; /* out of memory */
842 63286 : *itemarray = items;
843 63286 : strings = (char *) (items + inputlen);
844 :
845 63286 : atext++; /* advance over initial '{' */
846 63286 : curitem = 0;
847 174123 : while (*atext != '}')
848 : {
849 110837 : if (*atext == '\0')
850 0 : return false; /* premature end of string */
851 110837 : items[curitem] = strings;
852 2221018 : while (*atext != '}' && *atext != ',')
853 : {
854 2110181 : if (*atext == '\0')
855 0 : return false; /* premature end of string */
856 2110181 : if (*atext != '"')
857 2109986 : *strings++ = *atext++; /* copy unquoted data */
858 : else
859 : {
860 : /* process quoted substring */
861 195 : atext++;
862 6634 : while (*atext != '"')
863 : {
864 6439 : if (*atext == '\0')
865 0 : return false; /* premature end of string */
866 6439 : if (*atext == '\\')
867 : {
868 975 : atext++;
869 975 : if (*atext == '\0')
870 0 : return false; /* premature end of string */
871 : }
872 6439 : *strings++ = *atext++; /* copy quoted data */
873 : }
874 195 : atext++;
875 : }
876 : }
877 110837 : *strings++ = '\0';
878 110837 : if (*atext == ',')
879 48970 : atext++;
880 110837 : curitem++;
881 : }
882 63286 : if (atext[1] != '\0')
883 0 : return false; /* bogus syntax (embedded '}') */
884 63286 : *nitems = curitem;
885 63286 : return true;
886 : }
887 :
888 :
889 : /*
890 : * Append one element to the text representation of a 1-dimensional Postgres
891 : * array.
892 : *
893 : * The caller must provide the initial '{' and closing '}' of the array.
894 : * This function handles all else, including insertion of commas and
895 : * quoting of values.
896 : *
897 : * We assume that typdelim is ','.
898 : */
899 : void
900 3982 : appendPGArray(PQExpBuffer buffer, const char *value)
901 : {
902 : bool needquote;
903 : const char *tmp;
904 :
905 3982 : if (buffer->data[buffer->len - 1] != '{')
906 3682 : appendPQExpBufferChar(buffer, ',');
907 :
908 : /* Decide if we need quotes; this should match array_out()'s choices. */
909 3982 : if (value[0] == '\0')
910 0 : needquote = true; /* force quotes for empty string */
911 3982 : else if (pg_strcasecmp(value, "NULL") == 0)
912 0 : needquote = true; /* force quotes for literal NULL */
913 : else
914 3982 : needquote = false;
915 :
916 3982 : if (!needquote)
917 : {
918 30001 : for (tmp = value; *tmp; tmp++)
919 : {
920 26125 : char ch = *tmp;
921 :
922 26125 : if (ch == '"' || ch == '\\' ||
923 26019 : ch == '{' || ch == '}' || ch == ',' ||
924 : /* these match scanner_isspace(): */
925 26019 : ch == ' ' || ch == '\t' || ch == '\n' ||
926 26019 : ch == '\r' || ch == '\v' || ch == '\f')
927 : {
928 106 : needquote = true;
929 106 : break;
930 : }
931 : }
932 : }
933 :
934 3982 : if (needquote)
935 : {
936 106 : appendPQExpBufferChar(buffer, '"');
937 4611 : for (tmp = value; *tmp; tmp++)
938 : {
939 4505 : char ch = *tmp;
940 :
941 4505 : if (ch == '"' || ch == '\\')
942 795 : appendPQExpBufferChar(buffer, '\\');
943 4505 : appendPQExpBufferChar(buffer, ch);
944 : }
945 106 : appendPQExpBufferChar(buffer, '"');
946 : }
947 : else
948 3876 : appendPQExpBufferStr(buffer, value);
949 3982 : }
950 :
951 :
952 : /*
953 : * Format a reloptions array and append it to the given buffer.
954 : *
955 : * "prefix" is prepended to the option names; typically it's "" or "toast.".
956 : *
957 : * Returns false if the reloptions array could not be parsed (in which case
958 : * nothing will have been appended to the buffer), or true on success.
959 : *
960 : * Note: this logic should generally match the backend's flatten_reloptions()
961 : * (in adt/ruleutils.c).
962 : */
963 : bool
964 223 : appendReloptionsArray(PQExpBuffer buffer, const char *reloptions,
965 : const char *prefix, int encoding, bool std_strings)
966 : {
967 : char **options;
968 : int noptions;
969 : int i;
970 :
971 223 : if (!parsePGArray(reloptions, &options, &noptions))
972 : {
973 0 : free(options);
974 0 : return false;
975 : }
976 :
977 505 : for (i = 0; i < noptions; i++)
978 : {
979 282 : char *option = options[i];
980 : char *name;
981 : char *separator;
982 : char *value;
983 :
984 : /*
985 : * Each array element should have the form name=value. If the "=" is
986 : * missing for some reason, treat it like an empty value.
987 : */
988 282 : name = option;
989 282 : separator = strchr(option, '=');
990 282 : if (separator)
991 : {
992 282 : *separator = '\0';
993 282 : value = separator + 1;
994 : }
995 : else
996 0 : value = "";
997 :
998 282 : if (i > 0)
999 59 : appendPQExpBufferStr(buffer, ", ");
1000 282 : appendPQExpBuffer(buffer, "%s%s=", prefix, fmtId(name));
1001 :
1002 : /*
1003 : * In general we need to quote the value; but to avoid unnecessary
1004 : * clutter, do not quote if it is an identifier that would not need
1005 : * quoting. (We could also allow numbers, but that is a bit trickier
1006 : * than it looks --- for example, are leading zeroes significant? We
1007 : * don't want to assume very much here about what custom reloptions
1008 : * might mean.)
1009 : */
1010 282 : if (strcmp(fmtId(value), value) == 0)
1011 32 : appendPQExpBufferStr(buffer, value);
1012 : else
1013 250 : appendStringLiteral(buffer, value, encoding, std_strings);
1014 : }
1015 :
1016 223 : free(options);
1017 :
1018 223 : return true;
1019 : }
1020 :
1021 :
1022 : /*
1023 : * processSQLNamePattern
1024 : *
1025 : * Scan a wildcard-pattern string and generate appropriate WHERE clauses
1026 : * to limit the set of objects returned. The WHERE clauses are appended
1027 : * to the already-partially-constructed query in buf. Returns whether
1028 : * any clause was added.
1029 : *
1030 : * conn: connection query will be sent to (consulted for escaping rules).
1031 : * buf: output parameter.
1032 : * pattern: user-specified pattern option, or NULL if none ("*" is implied).
1033 : * have_where: true if caller already emitted "WHERE" (clauses will be ANDed
1034 : * onto the existing WHERE clause).
1035 : * force_escape: always quote regexp special characters, even outside
1036 : * double quotes (else they are quoted only between double quotes).
1037 : * schemavar: name of query variable to match against a schema-name pattern.
1038 : * Can be NULL if no schema.
1039 : * namevar: name of query variable to match against an object-name pattern.
1040 : * altnamevar: NULL, or name of an alternative variable to match against name.
1041 : * visibilityrule: clause to use if we want to restrict to visible objects
1042 : * (for example, "pg_catalog.pg_table_is_visible(p.oid)"). Can be NULL.
1043 : * dbnamebuf: output parameter receiving the database name portion of the
1044 : * pattern, if any. Can be NULL.
1045 : * dotcnt: how many separators were parsed from the pattern, by reference.
1046 : *
1047 : * Formatting note: the text already present in buf should end with a newline.
1048 : * The appended text, if any, will end with one too.
1049 : */
1050 : bool
1051 4998 : processSQLNamePattern(PGconn *conn, PQExpBuffer buf, const char *pattern,
1052 : bool have_where, bool force_escape,
1053 : const char *schemavar, const char *namevar,
1054 : const char *altnamevar, const char *visibilityrule,
1055 : PQExpBuffer dbnamebuf, int *dotcnt)
1056 : {
1057 : PQExpBufferData schemabuf;
1058 : PQExpBufferData namebuf;
1059 4998 : bool added_clause = false;
1060 : int dcnt;
1061 :
1062 : #define WHEREAND() \
1063 : (appendPQExpBufferStr(buf, have_where ? " AND " : "WHERE "), \
1064 : have_where = true, added_clause = true)
1065 :
1066 4998 : if (dotcnt == NULL)
1067 8 : dotcnt = &dcnt;
1068 4998 : *dotcnt = 0;
1069 4998 : if (pattern == NULL)
1070 : {
1071 : /* Default: select all visible objects */
1072 336 : if (visibilityrule)
1073 : {
1074 78 : WHEREAND();
1075 78 : appendPQExpBuffer(buf, "%s\n", visibilityrule);
1076 : }
1077 336 : return added_clause;
1078 : }
1079 :
1080 4662 : initPQExpBuffer(&schemabuf);
1081 4662 : initPQExpBuffer(&namebuf);
1082 :
1083 : /*
1084 : * Convert shell-style 'pattern' into the regular expression(s) we want to
1085 : * execute. Quoting/escaping into SQL literal format will be done below
1086 : * using appendStringLiteralConn().
1087 : *
1088 : * If the caller provided a schemavar, we want to split the pattern on
1089 : * ".", otherwise not.
1090 : */
1091 4662 : patternToSQLRegex(PQclientEncoding(conn),
1092 : (schemavar ? dbnamebuf : NULL),
1093 : (schemavar ? &schemabuf : NULL),
1094 : &namebuf,
1095 : pattern, force_escape, true, dotcnt);
1096 :
1097 : /*
1098 : * Now decide what we need to emit. We may run under a hostile
1099 : * search_path, so qualify EVERY name. Note there will be a leading "^("
1100 : * in the patterns in any case.
1101 : *
1102 : * We want the regex matches to use the database's default collation where
1103 : * collation-sensitive behavior is required (for example, which characters
1104 : * match '\w'). That happened by default before PG v12, but if the server
1105 : * is >= v12 then we need to force it through explicit COLLATE clauses,
1106 : * otherwise the "C" collation attached to "name" catalog columns wins.
1107 : */
1108 4662 : if (namevar && namebuf.len > 2)
1109 : {
1110 : /* We have a name pattern, so constrain the namevar(s) */
1111 :
1112 : /* Optimize away a "*" pattern */
1113 4662 : if (strcmp(namebuf.data, "^(.*)$") != 0)
1114 : {
1115 4588 : WHEREAND();
1116 4588 : if (altnamevar)
1117 : {
1118 152 : appendPQExpBuffer(buf,
1119 : "(%s OPERATOR(pg_catalog.~) ", namevar);
1120 152 : appendStringLiteralConn(buf, namebuf.data, conn);
1121 152 : if (PQserverVersion(conn) >= 120000)
1122 152 : appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
1123 152 : appendPQExpBuffer(buf,
1124 : "\n OR %s OPERATOR(pg_catalog.~) ",
1125 : altnamevar);
1126 152 : appendStringLiteralConn(buf, namebuf.data, conn);
1127 152 : if (PQserverVersion(conn) >= 120000)
1128 152 : appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
1129 152 : appendPQExpBufferStr(buf, ")\n");
1130 : }
1131 : else
1132 : {
1133 4436 : appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", namevar);
1134 4436 : appendStringLiteralConn(buf, namebuf.data, conn);
1135 4436 : if (PQserverVersion(conn) >= 120000)
1136 4436 : appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
1137 4436 : appendPQExpBufferChar(buf, '\n');
1138 : }
1139 : }
1140 : }
1141 :
1142 4662 : if (schemavar && schemabuf.len > 2)
1143 : {
1144 : /* We have a schema pattern, so constrain the schemavar */
1145 :
1146 : /* Optimize away a "*" pattern */
1147 1994 : if (strcmp(schemabuf.data, "^(.*)$") != 0 && schemavar)
1148 : {
1149 995 : WHEREAND();
1150 995 : appendPQExpBuffer(buf, "%s OPERATOR(pg_catalog.~) ", schemavar);
1151 995 : appendStringLiteralConn(buf, schemabuf.data, conn);
1152 995 : if (PQserverVersion(conn) >= 120000)
1153 995 : appendPQExpBufferStr(buf, " COLLATE pg_catalog.default");
1154 995 : appendPQExpBufferChar(buf, '\n');
1155 : }
1156 : }
1157 : else
1158 : {
1159 : /* No schema pattern given, so select only visible objects */
1160 3663 : if (visibilityrule)
1161 : {
1162 2926 : WHEREAND();
1163 2926 : appendPQExpBuffer(buf, "%s\n", visibilityrule);
1164 : }
1165 : }
1166 :
1167 4662 : termPQExpBuffer(&schemabuf);
1168 4662 : termPQExpBuffer(&namebuf);
1169 :
1170 4662 : return added_clause;
1171 : #undef WHEREAND
1172 : }
1173 :
1174 : /*
1175 : * Transform a possibly qualified shell-style object name pattern into up to
1176 : * three SQL-style regular expressions, converting quotes, lower-casing
1177 : * unquoted letters, and adjusting shell-style wildcard characters into regexp
1178 : * notation.
1179 : *
1180 : * If the dbnamebuf and schemabuf arguments are non-NULL, and the pattern
1181 : * contains two or more dbname/schema/name separators, we parse the portions of
1182 : * the pattern prior to the first and second separators into dbnamebuf and
1183 : * schemabuf, and the rest into namebuf.
1184 : *
1185 : * If dbnamebuf is NULL and schemabuf is non-NULL, and the pattern contains at
1186 : * least one separator, we parse the first portion into schemabuf and the rest
1187 : * into namebuf.
1188 : *
1189 : * Otherwise, we parse all the pattern into namebuf.
1190 : *
1191 : * If the pattern contains more dotted parts than buffers to parse into, the
1192 : * extra dots will be treated as literal characters and written into the
1193 : * namebuf, though they will be counted. Callers should always check the value
1194 : * returned by reference in dotcnt and handle this error case appropriately.
1195 : *
1196 : * We surround the regexps with "^(...)$" to force them to match whole strings,
1197 : * as per SQL practice. We have to have parens in case strings contain "|",
1198 : * else the "^" and "$" will be bound into the first and last alternatives
1199 : * which is not what we want. Whether this is done for dbnamebuf is controlled
1200 : * by the want_literal_dbname parameter.
1201 : *
1202 : * The regexps we parse into the buffers are appended to the data (if any)
1203 : * already present. If we parse fewer fields than the number of buffers we
1204 : * were given, the extra buffers are unaltered.
1205 : *
1206 : * encoding: the character encoding for the given pattern
1207 : * dbnamebuf: output parameter receiving the database name portion of the
1208 : * pattern, if any. Can be NULL.
1209 : * schemabuf: output parameter receiving the schema name portion of the
1210 : * pattern, if any. Can be NULL.
1211 : * namebuf: output parameter receiving the database name portion of the
1212 : * pattern, if any. Can be NULL.
1213 : * pattern: user-specified pattern option, or NULL if none ("*" is implied).
1214 : * force_escape: always quote regexp special characters, even outside
1215 : * double quotes (else they are quoted only between double quotes).
1216 : * want_literal_dbname: if true, regexp special characters within the database
1217 : * name portion of the pattern will not be escaped, nor will the dbname be
1218 : * converted into a regular expression.
1219 : * dotcnt: output parameter receiving the number of separators parsed from the
1220 : * pattern.
1221 : */
1222 : void
1223 4764 : patternToSQLRegex(int encoding, PQExpBuffer dbnamebuf, PQExpBuffer schemabuf,
1224 : PQExpBuffer namebuf, const char *pattern, bool force_escape,
1225 : bool want_literal_dbname, int *dotcnt)
1226 : {
1227 : PQExpBufferData buf[3];
1228 : PQExpBufferData left_literal;
1229 : PQExpBuffer curbuf;
1230 : PQExpBuffer maxbuf;
1231 : int i;
1232 : bool inquotes;
1233 : bool left;
1234 : const char *cp;
1235 :
1236 : Assert(pattern != NULL);
1237 : Assert(namebuf != NULL);
1238 :
1239 : /* callers should never expect "dbname.relname" format */
1240 : Assert(dbnamebuf == NULL || schemabuf != NULL);
1241 : Assert(dotcnt != NULL);
1242 :
1243 4764 : *dotcnt = 0;
1244 4764 : inquotes = false;
1245 4764 : cp = pattern;
1246 :
1247 4764 : if (dbnamebuf != NULL)
1248 3976 : maxbuf = &buf[2];
1249 788 : else if (schemabuf != NULL)
1250 29 : maxbuf = &buf[1];
1251 : else
1252 759 : maxbuf = &buf[0];
1253 :
1254 4764 : curbuf = &buf[0];
1255 4764 : if (want_literal_dbname)
1256 : {
1257 4662 : left = true;
1258 4662 : initPQExpBuffer(&left_literal);
1259 : }
1260 : else
1261 102 : left = false;
1262 4764 : initPQExpBuffer(curbuf);
1263 4764 : appendPQExpBufferStr(curbuf, "^(");
1264 84071 : while (*cp)
1265 : {
1266 79307 : char ch = *cp;
1267 :
1268 79307 : if (ch == '"')
1269 : {
1270 2136 : if (inquotes && cp[1] == '"')
1271 : {
1272 : /* emit one quote, stay in inquotes mode */
1273 4 : appendPQExpBufferChar(curbuf, '"');
1274 4 : if (left)
1275 4 : appendPQExpBufferChar(&left_literal, '"');
1276 4 : cp++;
1277 : }
1278 : else
1279 2132 : inquotes = !inquotes;
1280 2136 : cp++;
1281 : }
1282 77171 : else if (!inquotes && isupper((unsigned char) ch))
1283 : {
1284 160 : appendPQExpBufferChar(curbuf,
1285 160 : pg_tolower((unsigned char) ch));
1286 160 : if (left)
1287 100 : appendPQExpBufferChar(&left_literal,
1288 100 : pg_tolower((unsigned char) ch));
1289 160 : cp++;
1290 : }
1291 77011 : else if (!inquotes && ch == '*')
1292 : {
1293 297 : appendPQExpBufferStr(curbuf, ".*");
1294 297 : if (left)
1295 213 : appendPQExpBufferChar(&left_literal, '*');
1296 297 : cp++;
1297 : }
1298 76714 : else if (!inquotes && ch == '?')
1299 : {
1300 4 : appendPQExpBufferChar(curbuf, '.');
1301 4 : if (left)
1302 4 : appendPQExpBufferChar(&left_literal, '?');
1303 4 : cp++;
1304 : }
1305 76710 : else if (!inquotes && ch == '.')
1306 : {
1307 1902 : left = false;
1308 1902 : if (dotcnt)
1309 1902 : (*dotcnt)++;
1310 1902 : if (curbuf < maxbuf)
1311 : {
1312 1521 : appendPQExpBufferStr(curbuf, ")$");
1313 1521 : curbuf++;
1314 1521 : initPQExpBuffer(curbuf);
1315 1521 : appendPQExpBufferStr(curbuf, "^(");
1316 1521 : cp++;
1317 : }
1318 : else
1319 381 : appendPQExpBufferChar(curbuf, *cp++);
1320 : }
1321 74808 : else if (ch == '$')
1322 : {
1323 : /*
1324 : * Dollar is always quoted, whether inside quotes or not. The
1325 : * reason is that it's allowed in SQL identifiers, so there's a
1326 : * significant use-case for treating it literally, while because
1327 : * we anchor the pattern automatically there is no use-case for
1328 : * having it possess its regexp meaning.
1329 : */
1330 8 : appendPQExpBufferStr(curbuf, "\\$");
1331 8 : if (left)
1332 8 : appendPQExpBufferChar(&left_literal, '$');
1333 8 : cp++;
1334 : }
1335 : else
1336 : {
1337 : /*
1338 : * Ordinary data character, transfer to pattern
1339 : *
1340 : * Inside double quotes, or at all times if force_escape is true,
1341 : * quote regexp special characters with a backslash to avoid
1342 : * regexp errors. Outside quotes, however, let them pass through
1343 : * as-is; this lets knowledgeable users build regexp expressions
1344 : * that are more powerful than shell-style patterns.
1345 : *
1346 : * As an exception to that, though, always quote "[]", as that's
1347 : * much more likely to be an attempt to write an array type name
1348 : * than it is to be the start of a regexp bracket expression.
1349 : */
1350 74800 : if ((inquotes || force_escape) &&
1351 20037 : strchr("|*+?()[]{}.^$\\", ch))
1352 2585 : appendPQExpBufferChar(curbuf, '\\');
1353 72215 : else if (ch == '[' && cp[1] == ']')
1354 4 : appendPQExpBufferChar(curbuf, '\\');
1355 74800 : i = PQmblenBounded(cp, encoding);
1356 149600 : while (i--)
1357 : {
1358 74800 : if (left)
1359 52724 : appendPQExpBufferChar(&left_literal, *cp);
1360 74800 : appendPQExpBufferChar(curbuf, *cp++);
1361 : }
1362 : }
1363 : }
1364 4764 : appendPQExpBufferStr(curbuf, ")$");
1365 :
1366 4764 : if (namebuf)
1367 : {
1368 4764 : appendPQExpBufferStr(namebuf, curbuf->data);
1369 4764 : termPQExpBuffer(curbuf);
1370 4764 : curbuf--;
1371 : }
1372 :
1373 4764 : if (schemabuf && curbuf >= buf)
1374 : {
1375 1025 : appendPQExpBufferStr(schemabuf, curbuf->data);
1376 1025 : termPQExpBuffer(curbuf);
1377 1025 : curbuf--;
1378 : }
1379 :
1380 4764 : if (dbnamebuf && curbuf >= buf)
1381 : {
1382 496 : if (want_literal_dbname)
1383 479 : appendPQExpBufferStr(dbnamebuf, left_literal.data);
1384 : else
1385 17 : appendPQExpBufferStr(dbnamebuf, curbuf->data);
1386 496 : termPQExpBuffer(curbuf);
1387 : }
1388 :
1389 4764 : if (want_literal_dbname)
1390 4662 : termPQExpBuffer(&left_literal);
1391 4764 : }
|