Use a safer outfuncs/readfuncs representation for BitStrings.
[pgsql.git] / src / backend / nodes / outfuncs.c
blobe56392e6f9d19e91b9c403f29c354e6d12c4b3b5
1 /*-------------------------------------------------------------------------
3 * outfuncs.c
4 * Output functions for Postgres tree nodes.
6 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/nodes/outfuncs.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include <ctype.h>
19 #include "access/attnum.h"
20 #include "common/shortest_dec.h"
21 #include "lib/stringinfo.h"
22 #include "miscadmin.h"
23 #include "nodes/bitmapset.h"
24 #include "nodes/nodes.h"
25 #include "nodes/pg_list.h"
26 #include "utils/datum.h"
28 static void outChar(StringInfo str, char c);
29 static void outDouble(StringInfo str, double d);
33 * Macros to simplify output of different kinds of fields. Use these
34 * wherever possible to reduce the chance for silly typos. Note that these
35 * hard-wire conventions about the names of the local variables in an Out
36 * routine.
39 /* Write the label for the node type */
40 #define WRITE_NODE_TYPE(nodelabel) \
41 appendStringInfoString(str, nodelabel)
43 /* Write an integer field (anything written as ":fldname %d") */
44 #define WRITE_INT_FIELD(fldname) \
45 appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
47 /* Write an unsigned integer field (anything written as ":fldname %u") */
48 #define WRITE_UINT_FIELD(fldname) \
49 appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
51 /* Write an unsigned integer field (anything written with UINT64_FORMAT) */
52 #define WRITE_UINT64_FIELD(fldname) \
53 appendStringInfo(str, " :" CppAsString(fldname) " " UINT64_FORMAT, \
54 node->fldname)
56 /* Write an OID field (don't hard-wire assumption that OID is same as uint) */
57 #define WRITE_OID_FIELD(fldname) \
58 appendStringInfo(str, " :" CppAsString(fldname) " %u", node->fldname)
60 /* Write a long-integer field */
61 #define WRITE_LONG_FIELD(fldname) \
62 appendStringInfo(str, " :" CppAsString(fldname) " %ld", node->fldname)
64 /* Write a char field (ie, one ascii character) */
65 #define WRITE_CHAR_FIELD(fldname) \
66 (appendStringInfo(str, " :" CppAsString(fldname) " "), \
67 outChar(str, node->fldname))
69 /* Write an enumerated-type field as an integer code */
70 #define WRITE_ENUM_FIELD(fldname, enumtype) \
71 appendStringInfo(str, " :" CppAsString(fldname) " %d", \
72 (int) node->fldname)
74 /* Write a float field (actually, they're double) */
75 #define WRITE_FLOAT_FIELD(fldname) \
76 (appendStringInfo(str, " :" CppAsString(fldname) " "), \
77 outDouble(str, node->fldname))
79 /* Write a boolean field */
80 #define WRITE_BOOL_FIELD(fldname) \
81 appendStringInfo(str, " :" CppAsString(fldname) " %s", \
82 booltostr(node->fldname))
84 /* Write a character-string (possibly NULL) field */
85 #define WRITE_STRING_FIELD(fldname) \
86 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
87 outToken(str, node->fldname))
89 /* Write a parse location field (actually same as INT case) */
90 #define WRITE_LOCATION_FIELD(fldname) \
91 appendStringInfo(str, " :" CppAsString(fldname) " %d", node->fldname)
93 /* Write a Node field */
94 #define WRITE_NODE_FIELD(fldname) \
95 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
96 outNode(str, node->fldname))
98 /* Write a bitmapset field */
99 #define WRITE_BITMAPSET_FIELD(fldname) \
100 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
101 outBitmapset(str, node->fldname))
103 /* Write a variable-length array (not a List) of Node pointers */
104 #define WRITE_NODE_ARRAY(fldname, len) \
105 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
106 writeNodeArray(str, (const Node * const *) node->fldname, len))
108 /* Write a variable-length array of AttrNumber */
109 #define WRITE_ATTRNUMBER_ARRAY(fldname, len) \
110 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
111 writeAttrNumberCols(str, node->fldname, len))
113 /* Write a variable-length array of Oid */
114 #define WRITE_OID_ARRAY(fldname, len) \
115 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
116 writeOidCols(str, node->fldname, len))
118 /* Write a variable-length array of Index */
119 #define WRITE_INDEX_ARRAY(fldname, len) \
120 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
121 writeIndexCols(str, node->fldname, len))
123 /* Write a variable-length array of int */
124 #define WRITE_INT_ARRAY(fldname, len) \
125 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
126 writeIntCols(str, node->fldname, len))
128 /* Write a variable-length array of bool */
129 #define WRITE_BOOL_ARRAY(fldname, len) \
130 (appendStringInfoString(str, " :" CppAsString(fldname) " "), \
131 writeBoolCols(str, node->fldname, len))
133 #define booltostr(x) ((x) ? "true" : "false")
137 * outToken
138 * Convert an ordinary string (eg, an identifier) into a form that
139 * will be decoded back to a plain token by read.c's functions.
141 * If a null string pointer is given, it is encoded as '<>'.
142 * An empty string is encoded as '""'. To avoid ambiguity, input
143 * strings beginning with '<' or '"' receive a leading backslash.
145 void
146 outToken(StringInfo str, const char *s)
148 if (s == NULL)
150 appendStringInfoString(str, "<>");
151 return;
153 if (*s == '\0')
155 appendStringInfoString(str, "\"\"");
156 return;
160 * Look for characters or patterns that are treated specially by read.c
161 * (either in pg_strtok() or in nodeRead()), and therefore need a
162 * protective backslash.
164 /* These characters only need to be quoted at the start of the string */
165 if (*s == '<' ||
166 *s == '"' ||
167 isdigit((unsigned char) *s) ||
168 ((*s == '+' || *s == '-') &&
169 (isdigit((unsigned char) s[1]) || s[1] == '.')))
170 appendStringInfoChar(str, '\\');
171 while (*s)
173 /* These chars must be backslashed anywhere in the string */
174 if (*s == ' ' || *s == '\n' || *s == '\t' ||
175 *s == '(' || *s == ')' || *s == '{' || *s == '}' ||
176 *s == '\\')
177 appendStringInfoChar(str, '\\');
178 appendStringInfoChar(str, *s++);
183 * Convert one char. Goes through outToken() so that special characters are
184 * escaped.
186 static void
187 outChar(StringInfo str, char c)
189 char in[2];
191 /* Traditionally, we've represented \0 as <>, so keep doing that */
192 if (c == '\0')
194 appendStringInfoString(str, "<>");
195 return;
198 in[0] = c;
199 in[1] = '\0';
201 outToken(str, in);
205 * Convert a double value, attempting to ensure the value is preserved exactly.
207 static void
208 outDouble(StringInfo str, double d)
210 char buf[DOUBLE_SHORTEST_DECIMAL_LEN];
212 double_to_shortest_decimal_buf(d, buf);
213 appendStringInfoString(str, buf);
217 * common implementation for scalar-array-writing functions
219 * The data format is either "<>" for a NULL pointer or "(item item item)".
220 * fmtstr must include a leading space, and the rest of it must produce
221 * something that will be seen as a single simple token by pg_strtok().
222 * convfunc can be empty, or the name of a conversion macro or function.
224 #define WRITE_SCALAR_ARRAY(fnname, datatype, fmtstr, convfunc) \
225 static void \
226 fnname(StringInfo str, const datatype *arr, int len) \
228 if (arr != NULL) \
230 appendStringInfoChar(str, '('); \
231 for (int i = 0; i < len; i++) \
232 appendStringInfo(str, fmtstr, convfunc(arr[i])); \
233 appendStringInfoChar(str, ')'); \
235 else \
236 appendStringInfoString(str, "<>"); \
239 WRITE_SCALAR_ARRAY(writeAttrNumberCols, AttrNumber, " %d",)
240 WRITE_SCALAR_ARRAY(writeOidCols, Oid, " %u",)
241 WRITE_SCALAR_ARRAY(writeIndexCols, Index, " %u",)
242 WRITE_SCALAR_ARRAY(writeIntCols, int, " %d",)
243 WRITE_SCALAR_ARRAY(writeBoolCols, bool, " %s", booltostr)
246 * Print an array (not a List) of Node pointers.
248 * The decoration is identical to that of scalar arrays, but we can't
249 * quite use appendStringInfo() in the loop.
251 static void
252 writeNodeArray(StringInfo str, const Node *const *arr, int len)
254 if (arr != NULL)
256 appendStringInfoChar(str, '(');
257 for (int i = 0; i < len; i++)
259 appendStringInfoChar(str, ' ');
260 outNode(str, arr[i]);
262 appendStringInfoChar(str, ')');
264 else
265 appendStringInfoString(str, "<>");
269 * Print a List.
271 static void
272 _outList(StringInfo str, const List *node)
274 const ListCell *lc;
276 appendStringInfoChar(str, '(');
278 if (IsA(node, IntList))
279 appendStringInfoChar(str, 'i');
280 else if (IsA(node, OidList))
281 appendStringInfoChar(str, 'o');
282 else if (IsA(node, XidList))
283 appendStringInfoChar(str, 'x');
285 foreach(lc, node)
288 * For the sake of backward compatibility, we emit a slightly
289 * different whitespace format for lists of nodes vs. other types of
290 * lists. XXX: is this necessary?
292 if (IsA(node, List))
294 outNode(str, lfirst(lc));
295 if (lnext(node, lc))
296 appendStringInfoChar(str, ' ');
298 else if (IsA(node, IntList))
299 appendStringInfo(str, " %d", lfirst_int(lc));
300 else if (IsA(node, OidList))
301 appendStringInfo(str, " %u", lfirst_oid(lc));
302 else if (IsA(node, XidList))
303 appendStringInfo(str, " %u", lfirst_xid(lc));
304 else
305 elog(ERROR, "unrecognized list node type: %d",
306 (int) node->type);
309 appendStringInfoChar(str, ')');
313 * outBitmapset -
314 * converts a bitmap set of integers
316 * Note: the output format is "(b int int ...)", similar to an integer List.
318 * We export this function for use by extensions that define extensible nodes.
319 * That's somewhat historical, though, because calling outNode() will work.
321 void
322 outBitmapset(StringInfo str, const Bitmapset *bms)
324 int x;
326 appendStringInfoChar(str, '(');
327 appendStringInfoChar(str, 'b');
328 x = -1;
329 while ((x = bms_next_member(bms, x)) >= 0)
330 appendStringInfo(str, " %d", x);
331 appendStringInfoChar(str, ')');
335 * Print the value of a Datum given its type.
337 void
338 outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
340 Size length,
342 char *s;
344 length = datumGetSize(value, typbyval, typlen);
346 if (typbyval)
348 s = (char *) (&value);
349 appendStringInfo(str, "%u [ ", (unsigned int) length);
350 for (i = 0; i < (Size) sizeof(Datum); i++)
351 appendStringInfo(str, "%d ", (int) (s[i]));
352 appendStringInfoChar(str, ']');
354 else
356 s = (char *) DatumGetPointer(value);
357 if (!PointerIsValid(s))
358 appendStringInfoString(str, "0 [ ]");
359 else
361 appendStringInfo(str, "%u [ ", (unsigned int) length);
362 for (i = 0; i < length; i++)
363 appendStringInfo(str, "%d ", (int) (s[i]));
364 appendStringInfoChar(str, ']');
370 #include "outfuncs.funcs.c"
374 * Support functions for nodes with custom_read_write attribute or
375 * special_read_write attribute
378 static void
379 _outConst(StringInfo str, const Const *node)
381 WRITE_NODE_TYPE("CONST");
383 WRITE_OID_FIELD(consttype);
384 WRITE_INT_FIELD(consttypmod);
385 WRITE_OID_FIELD(constcollid);
386 WRITE_INT_FIELD(constlen);
387 WRITE_BOOL_FIELD(constbyval);
388 WRITE_BOOL_FIELD(constisnull);
389 WRITE_LOCATION_FIELD(location);
391 appendStringInfoString(str, " :constvalue ");
392 if (node->constisnull)
393 appendStringInfoString(str, "<>");
394 else
395 outDatum(str, node->constvalue, node->constlen, node->constbyval);
398 static void
399 _outBoolExpr(StringInfo str, const BoolExpr *node)
401 char *opstr = NULL;
403 WRITE_NODE_TYPE("BOOLEXPR");
405 /* do-it-yourself enum representation */
406 switch (node->boolop)
408 case AND_EXPR:
409 opstr = "and";
410 break;
411 case OR_EXPR:
412 opstr = "or";
413 break;
414 case NOT_EXPR:
415 opstr = "not";
416 break;
418 appendStringInfoString(str, " :boolop ");
419 outToken(str, opstr);
421 WRITE_NODE_FIELD(args);
422 WRITE_LOCATION_FIELD(location);
425 static void
426 _outForeignKeyOptInfo(StringInfo str, const ForeignKeyOptInfo *node)
428 int i;
430 WRITE_NODE_TYPE("FOREIGNKEYOPTINFO");
432 WRITE_UINT_FIELD(con_relid);
433 WRITE_UINT_FIELD(ref_relid);
434 WRITE_INT_FIELD(nkeys);
435 WRITE_ATTRNUMBER_ARRAY(conkey, node->nkeys);
436 WRITE_ATTRNUMBER_ARRAY(confkey, node->nkeys);
437 WRITE_OID_ARRAY(conpfeqop, node->nkeys);
438 WRITE_INT_FIELD(nmatched_ec);
439 WRITE_INT_FIELD(nconst_ec);
440 WRITE_INT_FIELD(nmatched_rcols);
441 WRITE_INT_FIELD(nmatched_ri);
442 /* for compactness, just print the number of matches per column: */
443 appendStringInfoString(str, " :eclass");
444 for (i = 0; i < node->nkeys; i++)
445 appendStringInfo(str, " %d", (node->eclass[i] != NULL));
446 appendStringInfoString(str, " :rinfos");
447 for (i = 0; i < node->nkeys; i++)
448 appendStringInfo(str, " %d", list_length(node->rinfos[i]));
451 static void
452 _outEquivalenceClass(StringInfo str, const EquivalenceClass *node)
455 * To simplify reading, we just chase up to the topmost merged EC and
456 * print that, without bothering to show the merge-ees separately.
458 while (node->ec_merged)
459 node = node->ec_merged;
461 WRITE_NODE_TYPE("EQUIVALENCECLASS");
463 WRITE_NODE_FIELD(ec_opfamilies);
464 WRITE_OID_FIELD(ec_collation);
465 WRITE_NODE_FIELD(ec_members);
466 WRITE_NODE_FIELD(ec_sources);
467 WRITE_NODE_FIELD(ec_derives);
468 WRITE_BITMAPSET_FIELD(ec_relids);
469 WRITE_BOOL_FIELD(ec_has_const);
470 WRITE_BOOL_FIELD(ec_has_volatile);
471 WRITE_BOOL_FIELD(ec_broken);
472 WRITE_UINT_FIELD(ec_sortref);
473 WRITE_UINT_FIELD(ec_min_security);
474 WRITE_UINT_FIELD(ec_max_security);
477 static void
478 _outExtensibleNode(StringInfo str, const ExtensibleNode *node)
480 const ExtensibleNodeMethods *methods;
482 methods = GetExtensibleNodeMethods(node->extnodename, false);
484 WRITE_NODE_TYPE("EXTENSIBLENODE");
486 WRITE_STRING_FIELD(extnodename);
488 /* serialize the private fields */
489 methods->nodeOut(str, node);
492 static void
493 _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
495 WRITE_NODE_TYPE("RANGETBLENTRY");
497 /* put alias + eref first to make dump more legible */
498 WRITE_NODE_FIELD(alias);
499 WRITE_NODE_FIELD(eref);
500 WRITE_ENUM_FIELD(rtekind, RTEKind);
502 switch (node->rtekind)
504 case RTE_RELATION:
505 WRITE_OID_FIELD(relid);
506 WRITE_CHAR_FIELD(relkind);
507 WRITE_INT_FIELD(rellockmode);
508 WRITE_NODE_FIELD(tablesample);
509 WRITE_UINT_FIELD(perminfoindex);
510 break;
511 case RTE_SUBQUERY:
512 WRITE_NODE_FIELD(subquery);
513 WRITE_BOOL_FIELD(security_barrier);
514 /* we re-use these RELATION fields, too: */
515 WRITE_OID_FIELD(relid);
516 WRITE_CHAR_FIELD(relkind);
517 WRITE_INT_FIELD(rellockmode);
518 WRITE_UINT_FIELD(perminfoindex);
519 break;
520 case RTE_JOIN:
521 WRITE_ENUM_FIELD(jointype, JoinType);
522 WRITE_INT_FIELD(joinmergedcols);
523 WRITE_NODE_FIELD(joinaliasvars);
524 WRITE_NODE_FIELD(joinleftcols);
525 WRITE_NODE_FIELD(joinrightcols);
526 WRITE_NODE_FIELD(join_using_alias);
527 break;
528 case RTE_FUNCTION:
529 WRITE_NODE_FIELD(functions);
530 WRITE_BOOL_FIELD(funcordinality);
531 break;
532 case RTE_TABLEFUNC:
533 WRITE_NODE_FIELD(tablefunc);
534 break;
535 case RTE_VALUES:
536 WRITE_NODE_FIELD(values_lists);
537 WRITE_NODE_FIELD(coltypes);
538 WRITE_NODE_FIELD(coltypmods);
539 WRITE_NODE_FIELD(colcollations);
540 break;
541 case RTE_CTE:
542 WRITE_STRING_FIELD(ctename);
543 WRITE_UINT_FIELD(ctelevelsup);
544 WRITE_BOOL_FIELD(self_reference);
545 WRITE_NODE_FIELD(coltypes);
546 WRITE_NODE_FIELD(coltypmods);
547 WRITE_NODE_FIELD(colcollations);
548 break;
549 case RTE_NAMEDTUPLESTORE:
550 WRITE_STRING_FIELD(enrname);
551 WRITE_FLOAT_FIELD(enrtuples);
552 WRITE_NODE_FIELD(coltypes);
553 WRITE_NODE_FIELD(coltypmods);
554 WRITE_NODE_FIELD(colcollations);
555 /* we re-use these RELATION fields, too: */
556 WRITE_OID_FIELD(relid);
557 break;
558 case RTE_RESULT:
559 /* no extra fields */
560 break;
561 default:
562 elog(ERROR, "unrecognized RTE kind: %d", (int) node->rtekind);
563 break;
566 WRITE_BOOL_FIELD(lateral);
567 WRITE_BOOL_FIELD(inh);
568 WRITE_BOOL_FIELD(inFromCl);
569 WRITE_NODE_FIELD(securityQuals);
572 static void
573 _outA_Expr(StringInfo str, const A_Expr *node)
575 WRITE_NODE_TYPE("A_EXPR");
577 switch (node->kind)
579 case AEXPR_OP:
580 WRITE_NODE_FIELD(name);
581 break;
582 case AEXPR_OP_ANY:
583 appendStringInfoString(str, " ANY");
584 WRITE_NODE_FIELD(name);
585 break;
586 case AEXPR_OP_ALL:
587 appendStringInfoString(str, " ALL");
588 WRITE_NODE_FIELD(name);
589 break;
590 case AEXPR_DISTINCT:
591 appendStringInfoString(str, " DISTINCT");
592 WRITE_NODE_FIELD(name);
593 break;
594 case AEXPR_NOT_DISTINCT:
595 appendStringInfoString(str, " NOT_DISTINCT");
596 WRITE_NODE_FIELD(name);
597 break;
598 case AEXPR_NULLIF:
599 appendStringInfoString(str, " NULLIF");
600 WRITE_NODE_FIELD(name);
601 break;
602 case AEXPR_IN:
603 appendStringInfoString(str, " IN");
604 WRITE_NODE_FIELD(name);
605 break;
606 case AEXPR_LIKE:
607 appendStringInfoString(str, " LIKE");
608 WRITE_NODE_FIELD(name);
609 break;
610 case AEXPR_ILIKE:
611 appendStringInfoString(str, " ILIKE");
612 WRITE_NODE_FIELD(name);
613 break;
614 case AEXPR_SIMILAR:
615 appendStringInfoString(str, " SIMILAR");
616 WRITE_NODE_FIELD(name);
617 break;
618 case AEXPR_BETWEEN:
619 appendStringInfoString(str, " BETWEEN");
620 WRITE_NODE_FIELD(name);
621 break;
622 case AEXPR_NOT_BETWEEN:
623 appendStringInfoString(str, " NOT_BETWEEN");
624 WRITE_NODE_FIELD(name);
625 break;
626 case AEXPR_BETWEEN_SYM:
627 appendStringInfoString(str, " BETWEEN_SYM");
628 WRITE_NODE_FIELD(name);
629 break;
630 case AEXPR_NOT_BETWEEN_SYM:
631 appendStringInfoString(str, " NOT_BETWEEN_SYM");
632 WRITE_NODE_FIELD(name);
633 break;
634 default:
635 elog(ERROR, "unrecognized A_Expr_Kind: %d", (int) node->kind);
636 break;
639 WRITE_NODE_FIELD(lexpr);
640 WRITE_NODE_FIELD(rexpr);
641 WRITE_LOCATION_FIELD(location);
644 static void
645 _outInteger(StringInfo str, const Integer *node)
647 appendStringInfo(str, "%d", node->ival);
650 static void
651 _outFloat(StringInfo str, const Float *node)
654 * We assume the value is a valid numeric literal and so does not need
655 * quoting.
657 appendStringInfoString(str, node->fval);
660 static void
661 _outBoolean(StringInfo str, const Boolean *node)
663 appendStringInfoString(str, node->boolval ? "true" : "false");
666 static void
667 _outString(StringInfo str, const String *node)
670 * We use outToken to provide escaping of the string's content, but we
671 * don't want it to convert an empty string to '""', because we're putting
672 * double quotes around the string already.
674 appendStringInfoChar(str, '"');
675 if (node->sval[0] != '\0')
676 outToken(str, node->sval);
677 appendStringInfoChar(str, '"');
680 static void
681 _outBitString(StringInfo str, const BitString *node)
684 * The lexer will always produce a string starting with 'b' or 'x'. There
685 * might be characters following that that need escaping, but outToken
686 * won't escape the 'b' or 'x'. This is relied on by nodeTokenType.
688 Assert(node->bsval[0] == 'b' || node->bsval[0] == 'x');
689 outToken(str, node->bsval);
692 static void
693 _outA_Const(StringInfo str, const A_Const *node)
695 WRITE_NODE_TYPE("A_CONST");
697 if (node->isnull)
698 appendStringInfoString(str, " NULL");
699 else
701 appendStringInfoString(str, " :val ");
702 outNode(str, &node->val);
704 WRITE_LOCATION_FIELD(location);
707 static void
708 _outConstraint(StringInfo str, const Constraint *node)
710 WRITE_NODE_TYPE("CONSTRAINT");
712 WRITE_STRING_FIELD(conname);
713 WRITE_BOOL_FIELD(deferrable);
714 WRITE_BOOL_FIELD(initdeferred);
715 WRITE_LOCATION_FIELD(location);
717 appendStringInfoString(str, " :contype ");
718 switch (node->contype)
720 case CONSTR_NULL:
721 appendStringInfoString(str, "NULL");
722 break;
724 case CONSTR_NOTNULL:
725 appendStringInfoString(str, "NOT_NULL");
726 break;
728 case CONSTR_DEFAULT:
729 appendStringInfoString(str, "DEFAULT");
730 WRITE_NODE_FIELD(raw_expr);
731 WRITE_STRING_FIELD(cooked_expr);
732 break;
734 case CONSTR_IDENTITY:
735 appendStringInfoString(str, "IDENTITY");
736 WRITE_NODE_FIELD(options);
737 WRITE_CHAR_FIELD(generated_when);
738 break;
740 case CONSTR_GENERATED:
741 appendStringInfoString(str, "GENERATED");
742 WRITE_NODE_FIELD(raw_expr);
743 WRITE_STRING_FIELD(cooked_expr);
744 WRITE_CHAR_FIELD(generated_when);
745 break;
747 case CONSTR_CHECK:
748 appendStringInfoString(str, "CHECK");
749 WRITE_BOOL_FIELD(is_no_inherit);
750 WRITE_NODE_FIELD(raw_expr);
751 WRITE_STRING_FIELD(cooked_expr);
752 WRITE_BOOL_FIELD(skip_validation);
753 WRITE_BOOL_FIELD(initially_valid);
754 break;
756 case CONSTR_PRIMARY:
757 appendStringInfoString(str, "PRIMARY_KEY");
758 WRITE_NODE_FIELD(keys);
759 WRITE_NODE_FIELD(including);
760 WRITE_NODE_FIELD(options);
761 WRITE_STRING_FIELD(indexname);
762 WRITE_STRING_FIELD(indexspace);
763 WRITE_BOOL_FIELD(reset_default_tblspc);
764 /* access_method and where_clause not currently used */
765 break;
767 case CONSTR_UNIQUE:
768 appendStringInfoString(str, "UNIQUE");
769 WRITE_BOOL_FIELD(nulls_not_distinct);
770 WRITE_NODE_FIELD(keys);
771 WRITE_NODE_FIELD(including);
772 WRITE_NODE_FIELD(options);
773 WRITE_STRING_FIELD(indexname);
774 WRITE_STRING_FIELD(indexspace);
775 WRITE_BOOL_FIELD(reset_default_tblspc);
776 /* access_method and where_clause not currently used */
777 break;
779 case CONSTR_EXCLUSION:
780 appendStringInfoString(str, "EXCLUSION");
781 WRITE_NODE_FIELD(exclusions);
782 WRITE_NODE_FIELD(including);
783 WRITE_NODE_FIELD(options);
784 WRITE_STRING_FIELD(indexname);
785 WRITE_STRING_FIELD(indexspace);
786 WRITE_BOOL_FIELD(reset_default_tblspc);
787 WRITE_STRING_FIELD(access_method);
788 WRITE_NODE_FIELD(where_clause);
789 break;
791 case CONSTR_FOREIGN:
792 appendStringInfoString(str, "FOREIGN_KEY");
793 WRITE_NODE_FIELD(pktable);
794 WRITE_NODE_FIELD(fk_attrs);
795 WRITE_NODE_FIELD(pk_attrs);
796 WRITE_CHAR_FIELD(fk_matchtype);
797 WRITE_CHAR_FIELD(fk_upd_action);
798 WRITE_CHAR_FIELD(fk_del_action);
799 WRITE_NODE_FIELD(fk_del_set_cols);
800 WRITE_NODE_FIELD(old_conpfeqop);
801 WRITE_OID_FIELD(old_pktable_oid);
802 WRITE_BOOL_FIELD(skip_validation);
803 WRITE_BOOL_FIELD(initially_valid);
804 break;
806 case CONSTR_ATTR_DEFERRABLE:
807 appendStringInfoString(str, "ATTR_DEFERRABLE");
808 break;
810 case CONSTR_ATTR_NOT_DEFERRABLE:
811 appendStringInfoString(str, "ATTR_NOT_DEFERRABLE");
812 break;
814 case CONSTR_ATTR_DEFERRED:
815 appendStringInfoString(str, "ATTR_DEFERRED");
816 break;
818 case CONSTR_ATTR_IMMEDIATE:
819 appendStringInfoString(str, "ATTR_IMMEDIATE");
820 break;
822 default:
823 elog(ERROR, "unrecognized ConstrType: %d", (int) node->contype);
824 break;
830 * outNode -
831 * converts a Node into ascii string and append it to 'str'
833 void
834 outNode(StringInfo str, const void *obj)
836 /* Guard against stack overflow due to overly complex expressions */
837 check_stack_depth();
839 if (obj == NULL)
840 appendStringInfoString(str, "<>");
841 else if (IsA(obj, List) || IsA(obj, IntList) || IsA(obj, OidList) ||
842 IsA(obj, XidList))
843 _outList(str, obj);
844 /* nodeRead does not want to see { } around these! */
845 else if (IsA(obj, Integer))
846 _outInteger(str, (Integer *) obj);
847 else if (IsA(obj, Float))
848 _outFloat(str, (Float *) obj);
849 else if (IsA(obj, Boolean))
850 _outBoolean(str, (Boolean *) obj);
851 else if (IsA(obj, String))
852 _outString(str, (String *) obj);
853 else if (IsA(obj, BitString))
854 _outBitString(str, (BitString *) obj);
855 else if (IsA(obj, Bitmapset))
856 outBitmapset(str, (Bitmapset *) obj);
857 else
859 appendStringInfoChar(str, '{');
860 switch (nodeTag(obj))
862 #include "outfuncs.switch.c"
864 default:
867 * This should be an ERROR, but it's too useful to be able to
868 * dump structures that outNode only understands part of.
870 elog(WARNING, "could not dump unrecognized node type: %d",
871 (int) nodeTag(obj));
872 break;
874 appendStringInfoChar(str, '}');
879 * nodeToString -
880 * returns the ascii representation of the Node as a palloc'd string
882 char *
883 nodeToString(const void *obj)
885 StringInfoData str;
887 /* see stringinfo.h for an explanation of this maneuver */
888 initStringInfo(&str);
889 outNode(&str, obj);
890 return str.data;
894 * bmsToString -
895 * returns the ascii representation of the Bitmapset as a palloc'd string
897 char *
898 bmsToString(const Bitmapset *bms)
900 StringInfoData str;
902 /* see stringinfo.h for an explanation of this maneuver */
903 initStringInfo(&str);
904 outBitmapset(&str, bms);
905 return str.data;