PostgreSQL Source Code git master
Loading...
Searching...
No Matches
pg_dependencies.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_dependencies.c
4 * pg_dependencies data type support.
5 *
6 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 * IDENTIFICATION
10 * src/backend/utils/adt/pg_dependencies.c
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include "common/int.h"
18#include "common/jsonapi.h"
19#include "lib/stringinfo.h"
20#include "mb/pg_wchar.h"
21#include "nodes/miscnodes.h"
24#include "utils/builtins.h"
25#include "utils/float.h"
26#include "utils/fmgrprotos.h"
27
39
40typedef struct
41{
42 const char *str;
44
47
48 bool found_attributes; /* Item has an attributes key */
49 bool found_dependency; /* Item has an dependency key */
50 bool found_degree; /* Item has degree key */
51 List *attnum_list; /* Accumulated attribute numbers */
53 double degree;
55
56/*
57 * Invoked at the start of each MVDependency object.
58 *
59 * The entire JSON document should be one array of MVDependency objects.
60 *
61 * If we are anywhere else in the document, it's an error.
62 */
65{
67
68 switch (parse->state)
69 {
71 /* Now we expect to see attributes/dependency/degree keys */
72 parse->state = DEPS_EXPECT_KEY;
73 return JSON_SUCCESS;
74
76 /* pg_dependencies must begin with a '[' */
77 errsave(parse->escontext,
79 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
80 errdetail("Initial element must be an array."));
81 break;
82
83 case DEPS_EXPECT_KEY:
84 /* In an object, expecting key */
85 errsave(parse->escontext,
87 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
88 errdetail("A key was expected."));
89 break;
90
92 /* Just followed an "attributes": key */
93 errsave(parse->escontext,
95 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
96 errdetail("Value of \"%s\" must be an array of attribute numbers.",
98 break;
99
101 /* In an attribute number list, expect only scalar integers */
102 errsave(parse->escontext,
104 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
105 errdetail("Attribute lists can only contain attribute numbers."));
106 break;
107
109 /* Just followed a "dependency" key */
110 errsave(parse->escontext,
112 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
113 errdetail("Value of \"%s\" must be an integer.",
115 break;
116
118 /* Just followed a "degree" key */
119 errsave(parse->escontext,
121 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
122 errdetail("Value of \"%s\" must be an integer.",
124 break;
125
126 default:
127 elog(ERROR,
128 "object start of \"%s\" found in unexpected parse state: %d.",
129 "pg_dependencies", (int) parse->state);
130 break;
131 }
132
134}
135
136/*
137 * Invoked at the end of an object.
138 *
139 * Handle the end of an MVDependency object's JSON representation.
140 */
143{
145
147
148 int natts = 0;
149
150 if (parse->state != DEPS_EXPECT_KEY)
151 elog(ERROR,
152 "object end of \"%s\" found in unexpected parse state: %d.",
153 "pg_dependencies", (int) parse->state);
154
155 if (!parse->found_attributes)
156 {
157 errsave(parse->escontext,
159 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
160 errdetail("Item must contain \"%s\" key.",
163 }
164
165 if (!parse->found_dependency)
166 {
167 errsave(parse->escontext,
169 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
170 errdetail("Item must contain \"%s\" key.",
173 }
174
175 if (!parse->found_degree)
176 {
177 errsave(parse->escontext,
179 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
180 errdetail("Item must contain \"%s\" key.",
183 }
184
185 /*
186 * We need at least one attribute number in a dependencies item, anything
187 * less is malformed.
188 */
189 natts = list_length(parse->attnum_list);
190 if ((natts < 1) || (natts > (STATS_MAX_DIMENSIONS - 1)))
191 {
192 errsave(parse->escontext,
194 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
195 errdetail("The \"%s\" key must contain an array of at least %d and no more than %d elements.",
199 }
200
201 /*
202 * Allocate enough space for the dependency, the attribute numbers in the
203 * list and the final attribute number for the dependency.
204 */
205 dep = palloc0(offsetof(MVDependency, attributes) + ((natts + 1) * sizeof(AttrNumber)));
206 dep->nattributes = natts + 1;
207
208 dep->attributes[natts] = parse->dependency;
209 dep->degree = parse->degree;
210
211 /*
212 * Assign attribute numbers to the attributes array, comparing each one
213 * against the dependency attribute to ensure that there are no matches.
214 */
215 for (int i = 0; i < natts; i++)
216 {
217 dep->attributes[i] = (AttrNumber) list_nth_int(parse->attnum_list, i);
218 if (dep->attributes[i] == parse->dependency)
219 {
220 errsave(parse->escontext,
222 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
223 errdetail("Item \"%s\" with value %d has been found in the \"%s\" list.",
227 }
228 }
229
230 parse->dependency_list = lappend(parse->dependency_list, (void *) dep);
231
232 /*
233 * Reset dependency item state variables to look for the next
234 * MVDependency.
235 */
236 list_free(parse->attnum_list);
237 parse->attnum_list = NIL;
238 parse->dependency = 0;
239 parse->degree = 0.0;
240 parse->found_attributes = false;
241 parse->found_dependency = false;
242 parse->found_degree = false;
243 parse->state = DEPS_EXPECT_ITEM;
244
245 return JSON_SUCCESS;
246}
247
248/*
249 * Invoked at the start of an array.
250 *
251 * Dependency input format does not have arrays, so any array elements
252 * encountered are an error.
253 */
256{
258
259 switch (parse->state)
260 {
262 parse->state = DEPS_EXPECT_ATTNUM;
263 break;
265 parse->state = DEPS_EXPECT_ITEM;
266 break;
267 default:
268 errsave(parse->escontext,
270 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
271 errdetail("Array has been found at an unexpected location."));
273 }
274
275 return JSON_SUCCESS;
276}
277
278/*
279 * Invoked at the end of an array.
280 *
281 * Either the end of an attribute number list or the whole object.
282 */
285{
287
288 switch (parse->state)
289 {
291 if (list_length(parse->attnum_list) > 0)
292 {
293 parse->state = DEPS_EXPECT_KEY;
294 return JSON_SUCCESS;
295 }
296
297 errsave(parse->escontext,
299 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
300 errdetail("The \"%s\" key must be a non-empty array.",
302 break;
303
304 case DEPS_EXPECT_ITEM:
305 if (list_length(parse->dependency_list) > 0)
306 {
307 parse->state = DEPS_PARSE_COMPLETE;
308 return JSON_SUCCESS;
309 }
310
311 errsave(parse->escontext,
313 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
314 errdetail("Item array cannot be empty."));
315 break;
316
317 default:
318
319 /*
320 * This can only happen if a case was missed in
321 * dependencies_array_start().
322 */
323 elog(ERROR,
324 "array end of \"%s\" found in unexpected parse state: %d.",
325 "pg_dependencies", (int) parse->state);
326 break;
327 }
329}
330
331/*
332 * Invoked at the start of a key/value field.
333 *
334 * The valid keys for the MVDependency object are:
335 * - attributes
336 * - dependency
337 * - degree
338 */
340dependencies_object_field_start(void *state, char *fname, bool isnull)
341{
343
344 if (strcmp(fname, PG_DEPENDENCIES_KEY_ATTRIBUTES) == 0)
345 {
346 if (parse->found_attributes)
347 {
348 errsave(parse->escontext,
350 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
351 errdetail("Multiple \"%s\" keys are not allowed.",
354 }
355
356 parse->found_attributes = true;
358 return JSON_SUCCESS;
359 }
360
361 if (strcmp(fname, PG_DEPENDENCIES_KEY_DEPENDENCY) == 0)
362 {
363 if (parse->found_dependency)
364 {
365 errsave(parse->escontext,
367 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
368 errdetail("Multiple \"%s\" keys are not allowed.",
371 }
372
373 parse->found_dependency = true;
375 return JSON_SUCCESS;
376 }
377
378 if (strcmp(fname, PG_DEPENDENCIES_KEY_DEGREE) == 0)
379 {
380 if (parse->found_degree)
381 {
382 errsave(parse->escontext,
384 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
385 errdetail("Multiple \"%s\" keys are not allowed.",
388 }
389
390 parse->found_degree = true;
391 parse->state = DEPS_EXPECT_DEGREE;
392 return JSON_SUCCESS;
393 }
394
395 errsave(parse->escontext,
397 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
398 errdetail("Only allowed keys are \"%s\", \"%s\", and \"%s\".",
403}
404
405/*
406 * Invoked at the start of an array element.
407 *
408 * pg_dependencies input format does not have arrays, so any array elements
409 * encountered are an error.
410 */
413{
415
416 switch (parse->state)
417 {
419 if (!isnull)
420 return JSON_SUCCESS;
421
422 errsave(parse->escontext,
424 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
425 errdetail("Attribute number array cannot be null."));
426 break;
427
428 case DEPS_EXPECT_ITEM:
429 if (!isnull)
430 return JSON_SUCCESS;
431
432 errsave(parse->escontext,
434 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
435 errdetail("Item list elements cannot be null."));
436 break;
437
438 default:
439 elog(ERROR,
440 "array element start of \"%s\" found in unexpected parse state: %d.",
441 "pg_dependencies", (int) parse->state);
442 break;
443 }
444
446}
447
448/*
449 * Test for valid subsequent attribute number.
450 *
451 * If the previous value is positive, then current value must either be
452 * greater than the previous value, or negative.
453 *
454 * If the previous value is negative, then the value must be less than
455 * the previous value.
456 *
457 * Duplicate values are not allowed; that is already covered by the rules
458 * described above.
459 */
460static bool
462{
463 Assert(prev != 0);
464
465 if (prev > 0)
466 return ((cur > prev) || (cur < 0));
467
468 return (cur < prev);
469}
470
471/*
472 * Handle scalar events from the dependencies input parser.
473 *
474 * There is only one case where we will encounter a scalar, and that is the
475 * dependency degree for the previous object key.
476 */
479{
483
484 switch (parse->state)
485 {
487 attnum = pg_strtoint16_safe(token, (Node *) &escontext);
488
489 if (escontext.error_occurred)
490 {
491 errsave(parse->escontext,
493 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
494 errdetail("Key \"%s\" has an incorrect value.", PG_DEPENDENCIES_KEY_ATTRIBUTES));
496 }
497
498 /*
499 * An attribute number cannot be zero or a negative number beyond
500 * the number of the possible expressions.
501 */
502 if (attnum == 0 || attnum < (0 - STATS_MAX_DIMENSIONS))
503 {
504 errsave(parse->escontext,
506 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
507 errdetail("Invalid \"%s\" element has been found: %d.",
510 }
511
512 if (parse->attnum_list != NIL)
513 {
514 const AttrNumber prev = llast_int(parse->attnum_list);
515
517 {
518 errsave(parse->escontext,
520 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
521 errdetail("Invalid \"%s\" element has been found: %d cannot follow %d.",
524 }
525 }
526
527 parse->attnum_list = lappend_int(parse->attnum_list, (int) attnum);
528 return JSON_SUCCESS;
529
531 parse->dependency = (AttrNumber)
532 pg_strtoint16_safe(token, (Node *) &escontext);
533
534 if (escontext.error_occurred)
535 {
536 errsave(parse->escontext,
538 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
539 errdetail("Key \"%s\" has an incorrect value.", PG_DEPENDENCIES_KEY_DEPENDENCY));
541 }
542
543 /*
544 * The dependency attribute number cannot be zero or a negative
545 * number beyond the number of the possible expressions.
546 */
547 if (parse->dependency == 0 || parse->dependency < (0 - STATS_MAX_DIMENSIONS))
548 {
549 errsave(parse->escontext,
551 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
552 errdetail("Key \"%s\" has an incorrect value: %d.",
555 }
556
557 parse->state = DEPS_EXPECT_KEY;
558 return JSON_SUCCESS;
559
561 parse->degree = float8in_internal(token, NULL, "double",
562 token, (Node *) &escontext);
563
564 if (escontext.error_occurred)
565 {
566 errsave(parse->escontext,
568 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
569 errdetail("Key \"%s\" has an incorrect value.", PG_DEPENDENCIES_KEY_DEGREE));
571 }
572
573 parse->state = DEPS_EXPECT_KEY;
574 return JSON_SUCCESS;
575
576 default:
577 errsave(parse->escontext,
579 errmsg("malformed pg_dependencies: \"%s\"", parse->str),
580 errdetail("Unexpected scalar has been found."));
581 break;
582 }
583
585}
586
587/*
588 * Compare the attribute arrays of two MVDependency values,
589 * looking for duplicated sets.
590 */
591static bool
593{
594 int i;
595
596 if (a->nattributes != b->nattributes)
597 return false;
598
599 for (i = 0; i < a->nattributes; i++)
600 {
601 if (a->attributes[i] != b->attributes[i])
602 return false;
603 }
604
605 return true;
606}
607
608/*
609 * Generate a string representing an array of attribute numbers.
610 * Internally, the dependency attribute is the last element, so we
611 * leave that off.
612 *
613 * Freeing the allocated string is the responsibility of the caller.
614 */
615static char *
617{
619
621
622 appendStringInfo(&str, "%d", item->attributes[0]);
623
624 for (int i = 1; i < item->nattributes - 1; i++)
625 appendStringInfo(&str, ", %d", item->attributes[i]);
626
627 return str.data;
628}
629
630/*
631 * Return the dependency, which is the last attribute element.
632 */
633static AttrNumber
635{
636 return item->attributes[item->nattributes - 1];
637}
638
639/*
640 * Attempt to build and serialize the MVDependencies object.
641 *
642 * This can only be executed after the completion of the JSON parsing.
643 *
644 * In the event of an error, set the error context and return NULL.
645 */
646static bytea *
648{
649 int ndeps = list_length(parse->dependency_list);
650
652 bytea *bytes;
653
654 switch (parse->state)
655 {
657
658 /*
659 * Parse ended in the expected place. We should have a list of
660 * items, but if we do not there is an issue with one of the
661 * earlier parse steps.
662 */
663 if (ndeps == 0)
664 elog(ERROR,
665 "pg_dependencies parsing claims success with an empty item list.");
666 break;
667
669 /* blank */
670 errsave(parse->escontext,
672 errmsg("malformed pg_dependencies: \"%s\"", str),
673 errdetail("Value cannot be empty."));
674 return NULL;
675
676 default:
677 /* Unexpected end-state. */
678 errsave(parse->escontext,
680 errmsg("malformed pg_dependencies: \"%s\"", str),
681 errdetail("Unexpected end state has been found: %d.", parse->state));
682 return NULL;
683 }
684
686 + (ndeps * sizeof(MVDependency *)));
687 mvdeps->magic = STATS_DEPS_MAGIC;
689 mvdeps->ndeps = ndeps;
690
691 for (int i = 0; i < ndeps; i++)
692 {
693 /*
694 * Use the MVDependency objects in the dependency_list.
695 *
696 * Because we free the dependency_list after parsing is done, we
697 * cannot free it here.
698 */
699 mvdeps->deps[i] = list_nth(parse->dependency_list, i);
700
701 /*
702 * Ensure that this item does not duplicate the attributes of any
703 * pre-existing item.
704 */
705 for (int j = 0; j < i; j++)
706 {
707 if (dep_attributes_eq(mvdeps->deps[i], mvdeps->deps[j]))
708 {
709 MVDependency *dep = mvdeps->deps[i];
710 char *attnum_list = dep_attnum_list(dep);
712
713 errsave(parse->escontext,
715 errmsg("malformed pg_dependencies: \"%s\"", str),
716 errdetail("Duplicated \"%s\" array has been found: [%s] for key \"%s\" and value %d.",
719 pfree(mvdeps);
720 return NULL;
721 }
722 }
723 }
724
726
727 /*
728 * No need to free the individual MVDependency objects, because they are
729 * still in the dependency_list, and will be freed with that.
730 */
731 pfree(mvdeps);
732
733 return bytes;
734}
735
736
737/*
738 * pg_dependencies_in - input routine for type pg_dependencies.
739 *
740 * This format is valid JSON, with the expected format:
741 * [{"attributes": [1,2], "dependency": -1, "degree": 1.0000},
742 * {"attributes": [1,-1], "dependency": 2, "degree": 0.0000},
743 * {"attributes": [2,-1], "dependency": 1, "degree": 1.0000}]
744 *
745 */
746Datum
748{
749 char *str = PG_GETARG_CSTRING(0);
750 bytea *bytes = NULL;
751
754 JsonLexContext *lex;
756
757 /* initialize the semantic state */
758 parse_state.str = str;
760 parse_state.dependency_list = NIL;
761 parse_state.attnum_list = NIL;
762 parse_state.dependency = 0;
763 parse_state.degree = 0.0;
764 parse_state.found_attributes = false;
765 parse_state.found_dependency = false;
766 parse_state.found_degree = false;
767 parse_state.escontext = fcinfo->context;
768
769 /* set callbacks */
770 sem_action.semstate = (void *) &parse_state;
775 sem_action.array_element_start = dependencies_array_element_start;
776 sem_action.array_element_end = NULL;
777 sem_action.object_field_start = dependencies_object_field_start;
778 sem_action.object_field_end = NULL;
780
782
785
786 if (result == JSON_SUCCESS)
788
789 list_free_deep(parse_state.dependency_list);
790 list_free(parse_state.attnum_list);
791
792 if (bytes)
793 PG_RETURN_BYTEA_P(bytes);
794
795 /*
796 * If escontext already set, just use that. Anything else is a generic
797 * JSON parse error.
798 */
799 if (!SOFT_ERROR_OCCURRED(parse_state.escontext))
800 errsave(parse_state.escontext,
802 errmsg("malformed pg_dependencies: \"%s\"", str),
803 errdetail("Input data must be valid JSON."));
804
806}
807
808
809/*
810 * pg_dependencies_out - output routine for type pg_dependencies.
811 */
812Datum
814{
818
821
822 for (int i = 0; i < dependencies->ndeps; i++)
823 {
824 MVDependency *dependency = dependencies->deps[i];
825
826 if (i > 0)
828
829 if (dependency->nattributes <= 1)
830 elog(ERROR, "invalid zero-length nattributes array in MVDependencies");
831
833 dependency->attributes[0]);
834
835 for (int j = 1; j < dependency->nattributes - 1; j++)
836 appendStringInfo(&str, ", %d", dependency->attributes[j]);
837
839 "\"" PG_DEPENDENCIES_KEY_DEGREE "\": %f}",
840 dependency->attributes[dependency->nattributes - 1],
841 dependency->degree);
842 }
843
845
847}
848
849/*
850 * pg_dependencies_recv - binary input routine for type pg_dependencies.
851 */
852Datum
854{
857 errmsg("cannot accept a value of type %s", "pg_dependencies")));
858
859 PG_RETURN_VOID(); /* keep compiler quiet */
860}
861
862/*
863 * pg_dependencies_send - binary output routine for type pg_dependencies.
864 *
865 * Functional dependencies are serialized in a bytea value (although the type
866 * is named differently), so let's just send that.
867 */
868Datum
870{
871 return byteasend(fcinfo);
872}
int16 AttrNumber
Definition attnum.h:21
Datum byteasend(PG_FUNCTION_ARGS)
Definition bytea.c:377
#define Assert(condition)
Definition c.h:999
uint32 result
MVDependencies * statext_dependencies_deserialize(bytea *data)
bytea * statext_dependencies_serialize(MVDependencies *dependencies)
struct cursor * cur
Definition ecpg.c:29
int errcode(int sqlerrcode)
Definition elog.c:875
#define errsave(context,...)
Definition elog.h:264
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define ERROR
Definition elog.h:40
#define elog(elevel,...)
Definition elog.h:228
#define ereport(elevel,...)
Definition elog.h:152
float8 float8in_internal(char *num, char **endptr_p, const char *type_name, const char *orig_string, struct Node *escontext)
Definition float.c:436
#define PG_RETURN_VOID()
Definition fmgr.h:350
#define PG_GETARG_BYTEA_PP(n)
Definition fmgr.h:309
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#define PG_GETARG_CSTRING(n)
Definition fmgr.h:278
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
const char * str
void parse(int)
Definition parse.c:49
int b
Definition isn.c:74
int a
Definition isn.c:73
int j
Definition isn.c:78
int i
Definition isn.c:77
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
Definition jsonapi.c:744
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
Definition jsonapi.c:392
void freeJsonLexContext(JsonLexContext *lex)
Definition jsonapi.c:687
JsonParseErrorType
Definition jsonapi.h:35
@ JSON_SEM_ACTION_FAILED
Definition jsonapi.h:59
@ JSON_SUCCESS
Definition jsonapi.h:36
JsonTokenType
Definition jsonapi.h:18
List * lappend(List *list, void *datum)
Definition list.c:339
List * lappend_int(List *list, int datum)
Definition list.c:357
void list_free(List *list)
Definition list.c:1546
void list_free_deep(List *list)
Definition list.c:1560
#define PG_UTF8
Definition mbprint.c:43
void pfree(void *pointer)
Definition mcxt.c:1619
void * palloc0(Size size)
Definition mcxt.c:1420
#define SOFT_ERROR_OCCURRED(escontext)
Definition miscnodes.h:53
int16 pg_strtoint16_safe(const char *s, Node *escontext)
Definition numutils.c:127
static char * errmsg
int16 attnum
const void * data
static JsonParseErrorType dependencies_array_end(void *state)
static JsonParseErrorType dependencies_array_start(void *state)
Datum pg_dependencies_in(PG_FUNCTION_ARGS)
static JsonParseErrorType dependencies_array_element_start(void *state, bool isnull)
DependenciesSemanticState
@ DEPS_EXPECT_START
@ DEPS_EXPECT_ATTNUM
@ DEPS_PARSE_COMPLETE
@ DEPS_EXPECT_ITEM
@ DEPS_EXPECT_DEPENDENCY
@ DEPS_EXPECT_ATTNUM_LIST
@ DEPS_EXPECT_KEY
@ DEPS_EXPECT_DEGREE
static JsonParseErrorType dependencies_object_end(void *state)
static bytea * build_mvdependencies(DependenciesParseState *parse, char *str)
static bool valid_subsequent_attnum(const AttrNumber prev, const AttrNumber cur)
static char * dep_attnum_list(const MVDependency *item)
Datum pg_dependencies_out(PG_FUNCTION_ARGS)
static AttrNumber dep_attnum_dependency(const MVDependency *item)
static JsonParseErrorType dependencies_scalar(void *state, char *token, JsonTokenType tokentype)
Datum pg_dependencies_send(PG_FUNCTION_ARGS)
static JsonParseErrorType dependencies_object_field_start(void *state, char *fname, bool isnull)
Datum pg_dependencies_recv(PG_FUNCTION_ARGS)
static bool dep_attributes_eq(const MVDependency *a, const MVDependency *b)
static JsonParseErrorType dependencies_object_start(void *state)
#define llast_int(l)
Definition pg_list.h:199
static int list_length(const List *l)
Definition pg_list.h:152
#define NIL
Definition pg_list.h:68
static void * list_nth(const List *list, int n)
Definition pg_list.h:331
static int list_nth_int(const List *list, int n)
Definition pg_list.h:342
uint64_t Datum
Definition postgres.h:70
static int fb(int x)
#define STATS_MAX_DIMENSIONS
Definition statistics.h:19
#define STATS_DEPS_MAGIC
Definition statistics.h:43
#define STATS_DEPS_TYPE_BASIC
Definition statistics.h:44
#define PG_DEPENDENCIES_KEY_ATTRIBUTES
#define PG_DEPENDENCIES_KEY_DEGREE
#define PG_DEPENDENCIES_KEY_DEPENDENCY
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
DependenciesSemanticState state
void * semstate
Definition jsonapi.h:153
Definition pg_list.h:54
MVDependency * deps[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:62
AttrNumber nattributes
Definition statistics.h:53
double degree
Definition statistics.h:52
AttrNumber attributes[FLEXIBLE_ARRAY_MEMBER]
Definition statistics.h:54
Definition nodes.h:133
Definition c.h:832