PostgreSQL Source Code git master
pg_ndistinct.c File Reference
#include "postgres.h"
#include "common/int.h"
#include "common/jsonapi.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "nodes/miscnodes.h"
#include "statistics/extended_stats_internal.h"
#include "statistics/statistics_format.h"
#include "utils/builtins.h"
#include "utils/fmgrprotos.h"
Include dependency graph for pg_ndistinct.c:

Go to the source code of this file.

Data Structures

struct  NDistinctParseState
 

Enumerations

enum  NDistinctSemanticState {
  NDIST_EXPECT_START = 0 , NDIST_EXPECT_ITEM , NDIST_EXPECT_KEY , NDIST_EXPECT_ATTNUM_LIST ,
  NDIST_EXPECT_ATTNUM , NDIST_EXPECT_NDISTINCT , NDIST_EXPECT_COMPLETE
}
 

Functions

static JsonParseErrorType ndistinct_object_start (void *state)
 
static JsonParseErrorType ndistinct_object_end (void *state)
 
static JsonParseErrorType ndistinct_array_start (void *state)
 
static JsonParseErrorType ndistinct_array_end (void *state)
 
static JsonParseErrorType ndistinct_object_field_start (void *state, char *fname, bool isnull)
 
static JsonParseErrorType ndistinct_array_element_start (void *state, bool isnull)
 
static bool valid_subsequent_attnum (AttrNumber prev, AttrNumber cur)
 
static JsonParseErrorType ndistinct_scalar (void *state, char *token, JsonTokenType tokentype)
 
static bool item_attributes_eq (const MVNDistinctItem *a, const MVNDistinctItem *b)
 
static bool item_has_attnum (const MVNDistinctItem *item, AttrNumber attnum)
 
static bool item_is_attnum_subset (const MVNDistinctItem *item, const MVNDistinctItem *refitem)
 
static char * item_attnum_list (const MVNDistinctItem *item)
 
static byteabuild_mvndistinct (NDistinctParseState *parse, char *str)
 
Datum pg_ndistinct_in (PG_FUNCTION_ARGS)
 
Datum pg_ndistinct_out (PG_FUNCTION_ARGS)
 
Datum pg_ndistinct_recv (PG_FUNCTION_ARGS)
 
Datum pg_ndistinct_send (PG_FUNCTION_ARGS)
 

Enumeration Type Documentation

◆ NDistinctSemanticState

Enumerator
NDIST_EXPECT_START 
NDIST_EXPECT_ITEM 
NDIST_EXPECT_KEY 
NDIST_EXPECT_ATTNUM_LIST 
NDIST_EXPECT_ATTNUM 
NDIST_EXPECT_NDISTINCT 
NDIST_EXPECT_COMPLETE 

Definition at line 28 of file pg_ndistinct.c.

29{
NDistinctSemanticState
Definition: pg_ndistinct.c:29
@ NDIST_EXPECT_NDISTINCT
Definition: pg_ndistinct.c:35
@ NDIST_EXPECT_START
Definition: pg_ndistinct.c:30
@ NDIST_EXPECT_ATTNUM
Definition: pg_ndistinct.c:34
@ NDIST_EXPECT_ITEM
Definition: pg_ndistinct.c:31
@ NDIST_EXPECT_ATTNUM_LIST
Definition: pg_ndistinct.c:33
@ NDIST_EXPECT_KEY
Definition: pg_ndistinct.c:32
@ NDIST_EXPECT_COMPLETE
Definition: pg_ndistinct.c:36

Function Documentation

◆ build_mvndistinct()

static bytea * build_mvndistinct ( NDistinctParseState parse,
char *  str 
)
static

Definition at line 588 of file pg_ndistinct.c.

589{
590 MVNDistinct *ndistinct;
591 int nitems = list_length(parse->distinct_items);
592 bytea *bytes;
593 int item_most_attrs = 0;
594 int item_most_attrs_idx = 0;
595
596 switch (parse->state)
597 {
599
600 /*
601 * Parsing has ended correctly and we should have a list of items.
602 * If we don't, something has been done wrong in one of the
603 * earlier parsing steps.
604 */
605 if (nitems == 0)
606 elog(ERROR,
607 "cannot have empty item list after parsing success.");
608 break;
609
611 /* blank */
612 errsave(parse->escontext,
613 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
614 errmsg("malformed pg_ndistinct: \"%s\"", str),
615 errdetail("Value cannot be empty."));
616 return NULL;
617
618 default:
619 /* Unexpected end-state. */
620 errsave(parse->escontext,
621 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
622 errmsg("malformed pg_ndistinct: \"%s\"", str),
623 errdetail("Unexpected end state has been found: %d.", parse->state));
624 return NULL;
625 }
626
627 ndistinct = palloc(offsetof(MVNDistinct, items) +
628 nitems * sizeof(MVNDistinctItem));
629
630 ndistinct->magic = STATS_NDISTINCT_MAGIC;
631 ndistinct->type = STATS_NDISTINCT_TYPE_BASIC;
632 ndistinct->nitems = nitems;
633
634 for (int i = 0; i < nitems; i++)
635 {
636 MVNDistinctItem *item = list_nth(parse->distinct_items, i);
637
638 /*
639 * Ensure that this item does not duplicate the attributes of any
640 * pre-existing item.
641 */
642 for (int j = 0; j < i; j++)
643 {
644 if (item_attributes_eq(item, &ndistinct->items[j]))
645 {
646 char *s = item_attnum_list(item);
647
648 errsave(parse->escontext,
649 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
650 errmsg("malformed pg_ndistinct: \"%s\"", str),
651 errdetail("Duplicated \"%s\" array has been found: [%s].",
653 pfree(s);
654 return NULL;
655 }
656 }
657
658 ndistinct->items[i].ndistinct = item->ndistinct;
659 ndistinct->items[i].nattributes = item->nattributes;
660
661 /*
662 * This transfers free-ing responsibility from the distinct_items list
663 * to the ndistinct object.
664 */
665 ndistinct->items[i].attributes = item->attributes;
666
667 /*
668 * Keep track of the first longest attribute list. All other attribute
669 * lists must be a subset of this list.
670 */
671 if (item->nattributes > item_most_attrs)
672 {
673 item_most_attrs = item->nattributes;
674 item_most_attrs_idx = i;
675 }
676 }
677
678 /*
679 * Verify that all the sets of attribute numbers are a proper subset of
680 * the longest set recorded. This acts as an extra sanity check based on
681 * the input given. Note that this still needs to be cross-checked with
682 * the extended statistics objects this would be assigned to, but it
683 * provides one extra layer of protection.
684 */
685 for (int i = 0; i < nitems; i++)
686 {
687 if (i == item_most_attrs_idx)
688 continue;
689
690 if (!item_is_attnum_subset(&ndistinct->items[i],
691 &ndistinct->items[item_most_attrs_idx]))
692 {
693 const MVNDistinctItem *item = &ndistinct->items[i];
694 const MVNDistinctItem *refitem = &ndistinct->items[item_most_attrs_idx];
695 char *item_list = item_attnum_list(item);
696 char *refitem_list = item_attnum_list(refitem);
697
698 errsave(parse->escontext,
699 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
700 errmsg("malformed pg_ndistinct: \"%s\"", str),
701 errdetail("\"%s\" array [%s] must be a subset of array [%s].",
703 item_list, refitem_list));
704 pfree(item_list);
705 pfree(refitem_list);
706 return NULL;
707 }
708 }
709
710 bytes = statext_ndistinct_serialize(ndistinct);
711
712 /*
713 * Free the attribute lists, before the ndistinct itself.
714 */
715 for (int i = 0; i < nitems; i++)
716 pfree(ndistinct->items[i].attributes);
717 pfree(ndistinct);
718
719 return bytes;
720}
int errdetail(const char *fmt,...)
Definition: elog.c:1216
int errcode(int sqlerrcode)
Definition: elog.c:863
int errmsg(const char *fmt,...)
Definition: elog.c:1080
#define errsave(context,...)
Definition: elog.h:262
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
const char * str
#define nitems(x)
Definition: indent.h:31
int j
Definition: isn.c:78
int i
Definition: isn.c:77
void pfree(void *pointer)
Definition: mcxt.c:1616
void * palloc(Size size)
Definition: mcxt.c:1387
bytea * statext_ndistinct_serialize(MVNDistinct *ndistinct)
Definition: mvdistinct.c:176
static int list_length(const List *l)
Definition: pg_list.h:152
static void * list_nth(const List *list, int n)
Definition: pg_list.h:299
static char * item_attnum_list(const MVNDistinctItem *item)
Definition: pg_ndistinct.c:566
static bool item_attributes_eq(const MVNDistinctItem *a, const MVNDistinctItem *b)
Definition: pg_ndistinct.c:515
static bool item_is_attnum_subset(const MVNDistinctItem *item, const MVNDistinctItem *refitem)
Definition: pg_ndistinct.c:549
static struct subre * parse(struct vars *v, int stopper, int type, struct state *init, struct state *final)
Definition: regcomp.c:717
#define STATS_NDISTINCT_MAGIC
Definition: statistics.h:22
#define STATS_NDISTINCT_TYPE_BASIC
Definition: statistics.h:23
#define PG_NDISTINCT_KEY_ATTRIBUTES
double ndistinct
Definition: statistics.h:28
AttrNumber * attributes
Definition: statistics.h:30
uint32 nitems
Definition: statistics.h:38
uint32 type
Definition: statistics.h:37
uint32 magic
Definition: statistics.h:36
MVNDistinctItem items[FLEXIBLE_ARRAY_MEMBER]
Definition: statistics.h:39
Definition: c.h:712
static ItemArray items
Definition: test_tidstore.c:48

References MVNDistinctItem::attributes, elog, errcode(), errdetail(), errmsg(), ERROR, errsave, i, item_attnum_list(), item_attributes_eq(), item_is_attnum_subset(), MVNDistinct::items, items, j, list_length(), list_nth(), MVNDistinct::magic, MVNDistinctItem::nattributes, NDIST_EXPECT_COMPLETE, NDIST_EXPECT_START, MVNDistinctItem::ndistinct, MVNDistinct::nitems, nitems, palloc(), parse(), pfree(), PG_NDISTINCT_KEY_ATTRIBUTES, statext_ndistinct_serialize(), STATS_NDISTINCT_MAGIC, STATS_NDISTINCT_TYPE_BASIC, str, and MVNDistinct::type.

Referenced by pg_ndistinct_in().

◆ item_attnum_list()

static char * item_attnum_list ( const MVNDistinctItem item)
static

Definition at line 566 of file pg_ndistinct.c.

567{
569
571
572 appendStringInfo(&str, "%d", item->attributes[0]);
573
574 for (int i = 1; i < item->nattributes; i++)
575 appendStringInfo(&str, ", %d", item->attributes[i]);
576
577 return str.data;
578}
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:145
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References appendStringInfo(), MVNDistinctItem::attributes, i, initStringInfo(), MVNDistinctItem::nattributes, and str.

Referenced by build_mvndistinct().

◆ item_attributes_eq()

static bool item_attributes_eq ( const MVNDistinctItem a,
const MVNDistinctItem b 
)
static

Definition at line 515 of file pg_ndistinct.c.

516{
517 if (a->nattributes != b->nattributes)
518 return false;
519
520 for (int i = 0; i < a->nattributes; i++)
521 {
522 if (a->attributes[i] != b->attributes[i])
523 return false;
524 }
525
526 return true;
527}
int b
Definition: isn.c:74
int a
Definition: isn.c:73

References a, b, and i.

Referenced by build_mvndistinct().

◆ item_has_attnum()

static bool item_has_attnum ( const MVNDistinctItem item,
AttrNumber  attnum 
)
static

Definition at line 534 of file pg_ndistinct.c.

535{
536 for (int i = 0; i < item->nattributes; i++)
537 {
538 if (attnum == item->attributes[i])
539 return true;
540 }
541 return false;
542}
int16 attnum
Definition: pg_attribute.h:74

References attnum, MVNDistinctItem::attributes, i, and MVNDistinctItem::nattributes.

Referenced by item_is_attnum_subset().

◆ item_is_attnum_subset()

static bool item_is_attnum_subset ( const MVNDistinctItem item,
const MVNDistinctItem refitem 
)
static

Definition at line 549 of file pg_ndistinct.c.

551{
552 for (int i = 0; i < item->nattributes; i++)
553 {
554 if (!item_has_attnum(refitem, item->attributes[i]))
555 return false;
556 }
557 return true;
558}
static bool item_has_attnum(const MVNDistinctItem *item, AttrNumber attnum)
Definition: pg_ndistinct.c:534

References MVNDistinctItem::attributes, i, item_has_attnum(), and MVNDistinctItem::nattributes.

Referenced by build_mvndistinct().

◆ ndistinct_array_element_start()

static JsonParseErrorType ndistinct_array_element_start ( void *  state,
bool  isnull 
)
static

Definition at line 353 of file pg_ndistinct.c.

354{
356
357 switch (parse->state)
358 {
360 if (!isnull)
361 return JSON_SUCCESS;
362
363 errsave(parse->escontext,
364 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
365 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
366 errdetail("Attribute number array cannot be null."));
367 break;
368
370 if (!isnull)
371 return JSON_SUCCESS;
372
373 errsave(parse->escontext,
374 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
375 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
376 errdetail("Item list elements cannot be null."));
377
378 break;
379
380 default:
381 elog(ERROR,
382 "array element start of \"%s\" found in unexpected parse state: %d.",
383 "pg_ndistinct", (int) parse->state);
384 break;
385 }
386
388}
@ JSON_SEM_ACTION_FAILED
Definition: jsonapi.h:59
@ JSON_SUCCESS
Definition: jsonapi.h:36
Definition: regguts.h:323

References elog, errcode(), errdetail(), errmsg(), ERROR, errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, NDIST_EXPECT_ATTNUM, NDIST_EXPECT_ITEM, and parse().

Referenced by pg_ndistinct_in().

◆ ndistinct_array_end()

static JsonParseErrorType ndistinct_array_end ( void *  state)
static

Definition at line 240 of file pg_ndistinct.c.

241{
243
244 switch (parse->state)
245 {
247 if (list_length(parse->attnum_list) > 0)
248 {
249 /*
250 * The attribute number list is complete, look for more
251 * MVNDistinctItem keys.
252 */
253 parse->state = NDIST_EXPECT_KEY;
254 return JSON_SUCCESS;
255 }
256
257 errsave(parse->escontext,
258 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
259 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
260 errdetail("The \"%s\" key must be a non-empty array.",
262 break;
263
265 if (list_length(parse->distinct_items) > 0)
266 {
267 /* Item list is complete, we are done. */
269 return JSON_SUCCESS;
270 }
271
272 errsave(parse->escontext,
273 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
274 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
275 errdetail("Item array cannot be empty."));
276 break;
277
278 default:
279
280 /*
281 * This can only happen if a case was missed in
282 * ndistinct_array_start().
283 */
284 elog(ERROR,
285 "array end of \"%s\" found in unexpected parse state: %d.",
286 "pg_ndistinct", (int) parse->state);
287 break;
288 }
289
291}

References elog, errcode(), errdetail(), errmsg(), ERROR, errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, list_length(), NDIST_EXPECT_ATTNUM, NDIST_EXPECT_COMPLETE, NDIST_EXPECT_ITEM, NDIST_EXPECT_KEY, parse(), and PG_NDISTINCT_KEY_ATTRIBUTES.

Referenced by pg_ndistinct_in().

◆ ndistinct_array_start()

static JsonParseErrorType ndistinct_array_start ( void *  state)
static

Definition at line 208 of file pg_ndistinct.c.

209{
211
212 switch (parse->state)
213 {
215 parse->state = NDIST_EXPECT_ATTNUM;
216 break;
217
219 parse->state = NDIST_EXPECT_ITEM;
220 break;
221
222 default:
223 errsave(parse->escontext,
224 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
225 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
226 errdetail("Array has been found at an unexpected location."));
228 }
229
230 return JSON_SUCCESS;
231}

References errcode(), errdetail(), errmsg(), errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, NDIST_EXPECT_ATTNUM, NDIST_EXPECT_ATTNUM_LIST, NDIST_EXPECT_ITEM, NDIST_EXPECT_START, and parse().

Referenced by pg_ndistinct_in().

◆ ndistinct_object_end()

static JsonParseErrorType ndistinct_object_end ( void *  state)
static

Definition at line 129 of file pg_ndistinct.c.

130{
132
133 int natts = 0;
134
135 MVNDistinctItem *item;
136
137 if (parse->state != NDIST_EXPECT_KEY)
138 elog(ERROR,
139 "object end of \"%s\" found in unexpected parse state: %d.",
140 "pg_ndistinct", (int) parse->state);
141
142 if (!parse->found_attributes)
143 {
144 errsave(parse->escontext,
145 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
146 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
147 errdetail("Item must contain \"%s\" key.",
150 }
151
152 if (!parse->found_ndistinct)
153 {
154 errsave(parse->escontext,
155 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
156 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
157 errdetail("Item must contain \"%s\" key.",
160 }
161
162 /*
163 * We need at least two attribute numbers for a ndistinct item, anything
164 * less is malformed.
165 */
166 natts = list_length(parse->attnum_list);
167 if ((natts < 2) || (natts > STATS_MAX_DIMENSIONS))
168 {
169 errsave(parse->escontext,
170 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
171 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
172 errdetail("The \"%s\" key must contain an array of at least %d and no more than %d attributes.",
175 }
176
177 /* Create the MVNDistinctItem */
179 item->nattributes = natts;
180 item->attributes = palloc0(natts * sizeof(AttrNumber));
181 item->ndistinct = (double) parse->ndistinct;
182
183 for (int i = 0; i < natts; i++)
184 item->attributes[i] = (AttrNumber) list_nth_int(parse->attnum_list, i);
185
186 parse->distinct_items = lappend(parse->distinct_items, (void *) item);
187
188 /* reset item state vars */
189 list_free(parse->attnum_list);
190 parse->attnum_list = NIL;
191 parse->ndistinct = 0;
192 parse->found_attributes = false;
193 parse->found_ndistinct = false;
194
195 /* Now we are looking for the next MVNDistinctItem */
196 parse->state = NDIST_EXPECT_ITEM;
197 return JSON_SUCCESS;
198}
int16 AttrNumber
Definition: attnum.h:21
#define palloc_object(type)
Definition: fe_memutils.h:74
for(;;)
List * lappend(List *list, void *datum)
Definition: list.c:339
void list_free(List *list)
Definition: list.c:1546
void * palloc0(Size size)
Definition: mcxt.c:1417
#define NIL
Definition: pg_list.h:68
static int list_nth_int(const List *list, int n)
Definition: pg_list.h:310
#define STATS_MAX_DIMENSIONS
Definition: statistics.h:19
#define PG_NDISTINCT_KEY_NDISTINCT

References MVNDistinctItem::attributes, elog, errcode(), errdetail(), errmsg(), ERROR, errsave, for(), i, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, lappend(), list_free(), list_length(), list_nth_int(), MVNDistinctItem::nattributes, NDIST_EXPECT_ITEM, NDIST_EXPECT_KEY, MVNDistinctItem::ndistinct, NIL, palloc0(), palloc_object, parse(), PG_NDISTINCT_KEY_ATTRIBUTES, PG_NDISTINCT_KEY_NDISTINCT, and STATS_MAX_DIMENSIONS.

Referenced by pg_ndistinct_in().

◆ ndistinct_object_field_start()

static JsonParseErrorType ndistinct_object_field_start ( void *  state,
char *  fname,
bool  isnull 
)
static

Definition at line 301 of file pg_ndistinct.c.

302{
304
305 if (strcmp(fname, PG_NDISTINCT_KEY_ATTRIBUTES) == 0)
306 {
307 if (parse->found_attributes)
308 {
309 errsave(parse->escontext,
310 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
311 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
312 errdetail("Multiple \"%s\" keys are not allowed.",
315 }
316 parse->found_attributes = true;
318 return JSON_SUCCESS;
319 }
320
321 if (strcmp(fname, PG_NDISTINCT_KEY_NDISTINCT) == 0)
322 {
323 if (parse->found_ndistinct)
324 {
325 errsave(parse->escontext,
326 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
327 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
328 errdetail("Multiple \"%s\" keys are not allowed.",
331 }
332 parse->found_ndistinct = true;
334 return JSON_SUCCESS;
335 }
336
337 errsave(parse->escontext,
338 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
339 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
340 errdetail("Only allowed keys are \"%s\" and \"%s\".",
344}

References errcode(), errdetail(), errmsg(), errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, NDIST_EXPECT_ATTNUM_LIST, NDIST_EXPECT_NDISTINCT, parse(), PG_NDISTINCT_KEY_ATTRIBUTES, and PG_NDISTINCT_KEY_NDISTINCT.

Referenced by pg_ndistinct_in().

◆ ndistinct_object_start()

static JsonParseErrorType ndistinct_object_start ( void *  state)
static

Definition at line 60 of file pg_ndistinct.c.

61{
63
64 switch (parse->state)
65 {
67 /* Now we expect to see attributes/ndistinct keys */
68 parse->state = NDIST_EXPECT_KEY;
69 return JSON_SUCCESS;
70
72 /* pg_ndistinct must begin with a '[' */
73 errsave(parse->escontext,
74 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
75 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
76 errdetail("Initial element must be an array."));
77 break;
78
80 /* In an object, expecting key */
81 errsave(parse->escontext,
82 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
83 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
84 errdetail("A key was expected."));
85 break;
86
88 /* Just followed an "attributes" key */
89 errsave(parse->escontext,
90 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
91 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
92 errdetail("Value of \"%s\" must be an array of attribute numbers.",
94 break;
95
97 /* In an attribute number list, expect only scalar integers */
98 errsave(parse->escontext,
99 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
100 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
101 errdetail("Attribute lists can only contain attribute numbers."));
102 break;
103
105 /* Just followed an "ndistinct" key */
106 errsave(parse->escontext,
107 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
108 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
109 errdetail("Value of \"%s\" must be an integer.",
111 break;
112
113 default:
114 elog(ERROR,
115 "object start of \"%s\" found in unexpected parse state: %d.",
116 "pg_ndistinct", (int) parse->state);
117 break;
118 }
119
121}

References elog, errcode(), errdetail(), errmsg(), ERROR, errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, NDIST_EXPECT_ATTNUM, NDIST_EXPECT_ATTNUM_LIST, NDIST_EXPECT_ITEM, NDIST_EXPECT_KEY, NDIST_EXPECT_NDISTINCT, NDIST_EXPECT_START, parse(), PG_NDISTINCT_KEY_ATTRIBUTES, and PG_NDISTINCT_KEY_NDISTINCT.

Referenced by pg_ndistinct_in().

◆ ndistinct_scalar()

static JsonParseErrorType ndistinct_scalar ( void *  state,
char *  token,
JsonTokenType  tokentype 
)
static

Definition at line 420 of file pg_ndistinct.c.

421{
424 ErrorSaveContext escontext = {T_ErrorSaveContext};
425
426 switch (parse->state)
427 {
429 attnum = pg_strtoint16_safe(token, (Node *) &escontext);
430
431 if (escontext.error_occurred)
432 {
433 errsave(parse->escontext,
434 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
435 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
436 errdetail("Key \"%s\" has an incorrect value.", PG_NDISTINCT_KEY_ATTRIBUTES));
438 }
439
440 /*
441 * The attribute number cannot be zero a negative number beyond
442 * the number of the possible expressions.
443 */
444 if (attnum == 0 || attnum < (0 - STATS_MAX_DIMENSIONS))
445 {
446 errsave(parse->escontext,
447 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
448 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
449 errdetail("Invalid \"%s\" element has been found: %d.",
452 }
453
454 if (list_length(parse->attnum_list) > 0)
455 {
456 const AttrNumber prev = llast_int(parse->attnum_list);
457
459 {
460 errsave(parse->escontext,
461 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
462 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
463 errdetail("Invalid \"%s\" element has been found: %d cannot follow %d.",
466 }
467 }
468
469 parse->attnum_list = lappend_int(parse->attnum_list, (int) attnum);
470 return JSON_SUCCESS;
471
473
474 /*
475 * While the structure dictates that ndistinct is a double
476 * precision floating point, it has always been an integer in the
477 * output generated. Therefore, we parse it as an integer here.
478 */
479 parse->ndistinct = pg_strtoint32_safe(token, (Node *) &escontext);
480
481 if (!escontext.error_occurred)
482 {
483 parse->state = NDIST_EXPECT_KEY;
484 return JSON_SUCCESS;
485 }
486
487 errsave(parse->escontext,
488 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
489 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
490 errdetail("Key \"%s\" has an incorrect value.",
492 break;
493
494 default:
495 errsave(parse->escontext,
496 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
497 errmsg("malformed pg_ndistinct: \"%s\"", parse->str),
498 errdetail("Unexpected scalar has been found."));
499 break;
500 }
501
503}
List * lappend_int(List *list, int datum)
Definition: list.c:357
int32 pg_strtoint32_safe(const char *s, Node *escontext)
Definition: numutils.c:389
int16 pg_strtoint16_safe(const char *s, Node *escontext)
Definition: numutils.c:128
#define llast_int(l)
Definition: pg_list.h:199
static bool valid_subsequent_attnum(AttrNumber prev, AttrNumber cur)
Definition: pg_ndistinct.c:403
bool error_occurred
Definition: miscnodes.h:47
Definition: nodes.h:135

References attnum, errcode(), errdetail(), errmsg(), errsave, JSON_SEM_ACTION_FAILED, JSON_SUCCESS, lappend_int(), list_length(), llast_int, NDIST_EXPECT_ATTNUM, NDIST_EXPECT_KEY, NDIST_EXPECT_NDISTINCT, parse(), PG_NDISTINCT_KEY_ATTRIBUTES, PG_NDISTINCT_KEY_NDISTINCT, pg_strtoint16_safe(), pg_strtoint32_safe(), STATS_MAX_DIMENSIONS, and valid_subsequent_attnum().

Referenced by pg_ndistinct_in().

◆ pg_ndistinct_in()

Datum pg_ndistinct_in ( PG_FUNCTION_ARGS  )

Definition at line 727 of file pg_ndistinct.c.

728{
729 char *str = PG_GETARG_CSTRING(0);
730 NDistinctParseState parse_state;
731 JsonParseErrorType result;
732 JsonLexContext *lex;
733 JsonSemAction sem_action;
734 bytea *bytes = NULL;
735
736 /* initialize semantic state */
737 parse_state.str = str;
738 parse_state.state = NDIST_EXPECT_START;
739 parse_state.distinct_items = NIL;
740 parse_state.escontext = fcinfo->context;
741 parse_state.found_attributes = false;
742 parse_state.found_ndistinct = false;
743 parse_state.attnum_list = NIL;
744 parse_state.ndistinct = 0;
745
746 /* set callbacks */
747 sem_action.semstate = (void *) &parse_state;
749 sem_action.object_end = ndistinct_object_end;
751 sem_action.array_end = ndistinct_array_end;
753 sem_action.object_field_end = NULL;
755 sem_action.array_element_end = NULL;
756 sem_action.scalar = ndistinct_scalar;
757
758 lex = makeJsonLexContextCstringLen(NULL, str, strlen(str),
759 PG_UTF8, true);
760 result = pg_parse_json(lex, &sem_action);
762
763 if (result == JSON_SUCCESS)
764 bytes = build_mvndistinct(&parse_state, str);
765
766 list_free(parse_state.attnum_list);
767 list_free_deep(parse_state.distinct_items);
768
769 if (bytes)
770 PG_RETURN_BYTEA_P(bytes);
771
772 /*
773 * If escontext already set, just use that. Anything else is a generic
774 * JSON parse error.
775 */
776 if (!SOFT_ERROR_OCCURRED(parse_state.escontext))
777 errsave(parse_state.escontext,
778 errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
779 errmsg("malformed pg_ndistinct: \"%s\"", str),
780 errdetail("Input data must be valid JSON."));
781
783}
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:373
#define PG_GETARG_CSTRING(n)
Definition: fmgr.h:278
#define PG_RETURN_NULL()
Definition: fmgr.h:346
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
void list_free_deep(List *list)
Definition: list.c:1560
#define SOFT_ERROR_OCCURRED(escontext)
Definition: miscnodes.h:53
static JsonParseErrorType ndistinct_array_element_start(void *state, bool isnull)
Definition: pg_ndistinct.c:353
static JsonParseErrorType ndistinct_array_end(void *state)
Definition: pg_ndistinct.c:240
static JsonParseErrorType ndistinct_object_start(void *state)
Definition: pg_ndistinct.c:60
static JsonParseErrorType ndistinct_array_start(void *state)
Definition: pg_ndistinct.c:208
static JsonParseErrorType ndistinct_scalar(void *state, char *token, JsonTokenType tokentype)
Definition: pg_ndistinct.c:420
static bytea * build_mvndistinct(NDistinctParseState *parse, char *str)
Definition: pg_ndistinct.c:588
static JsonParseErrorType ndistinct_object_end(void *state)
Definition: pg_ndistinct.c:129
static JsonParseErrorType ndistinct_object_field_start(void *state, char *fname, bool isnull)
Definition: pg_ndistinct.c:301
@ PG_UTF8
Definition: pg_wchar.h:232
json_struct_action array_end
Definition: jsonapi.h:157
json_struct_action object_start
Definition: jsonapi.h:154
json_ofield_action object_field_start
Definition: jsonapi.h:158
json_aelem_action array_element_start
Definition: jsonapi.h:160
json_scalar_action scalar
Definition: jsonapi.h:162
void * semstate
Definition: jsonapi.h:153
json_aelem_action array_element_end
Definition: jsonapi.h:161
json_struct_action array_start
Definition: jsonapi.h:156
json_struct_action object_end
Definition: jsonapi.h:155
json_ofield_action object_field_end
Definition: jsonapi.h:159
const char * str
Definition: pg_ndistinct.c:41
NDistinctSemanticState state
Definition: pg_ndistinct.c:42

References JsonSemAction::array_element_end, JsonSemAction::array_element_start, JsonSemAction::array_end, JsonSemAction::array_start, NDistinctParseState::attnum_list, build_mvndistinct(), NDistinctParseState::distinct_items, errcode(), errdetail(), errmsg(), errsave, NDistinctParseState::escontext, NDistinctParseState::found_attributes, NDistinctParseState::found_ndistinct, freeJsonLexContext(), JSON_SUCCESS, list_free(), list_free_deep(), makeJsonLexContextCstringLen(), NDIST_EXPECT_START, NDistinctParseState::ndistinct, ndistinct_array_element_start(), ndistinct_array_end(), ndistinct_array_start(), ndistinct_object_end(), ndistinct_object_field_start(), ndistinct_object_start(), ndistinct_scalar(), NIL, JsonSemAction::object_end, JsonSemAction::object_field_end, JsonSemAction::object_field_start, JsonSemAction::object_start, PG_GETARG_CSTRING, pg_parse_json(), PG_RETURN_BYTEA_P, PG_RETURN_NULL, PG_UTF8, JsonSemAction::scalar, JsonSemAction::semstate, SOFT_ERROR_OCCURRED, NDistinctParseState::state, NDistinctParseState::str, and str.

◆ pg_ndistinct_out()

Datum pg_ndistinct_out ( PG_FUNCTION_ARGS  )

Definition at line 792 of file pg_ndistinct.c.

793{
796 int i;
798
801
802 for (i = 0; i < ndist->nitems; i++)
803 {
804 MVNDistinctItem item = ndist->items[i];
805
806 if (i > 0)
808
809 if (item.nattributes <= 0)
810 elog(ERROR, "invalid zero-length attribute array in MVNDistinct");
811
813 item.attributes[0]);
814
815 for (int j = 1; j < item.nattributes; j++)
816 appendStringInfo(&str, ", %d", item.attributes[j]);
817
819 (int) item.ndistinct);
820 }
821
823
825}
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:309
#define PG_RETURN_CSTRING(x)
Definition: fmgr.h:364
MVNDistinct * statext_ndistinct_deserialize(bytea *data)
Definition: mvdistinct.c:247
const void * data
void appendStringInfoString(StringInfo str, const char *s)
Definition: stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242

References appendStringInfo(), appendStringInfoChar(), appendStringInfoString(), MVNDistinctItem::attributes, data, elog, ERROR, i, initStringInfo(), MVNDistinct::items, j, MVNDistinctItem::nattributes, MVNDistinctItem::ndistinct, MVNDistinct::nitems, PG_GETARG_BYTEA_PP, PG_NDISTINCT_KEY_ATTRIBUTES, PG_NDISTINCT_KEY_NDISTINCT, PG_RETURN_CSTRING, statext_ndistinct_deserialize(), and str.

◆ pg_ndistinct_recv()

Datum pg_ndistinct_recv ( PG_FUNCTION_ARGS  )

Definition at line 832 of file pg_ndistinct.c.

833{
835 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
836 errmsg("cannot accept a value of type %s", "pg_ndistinct")));
837
838 PG_RETURN_VOID(); /* keep compiler quiet */
839}
#define ereport(elevel,...)
Definition: elog.h:150
#define PG_RETURN_VOID()
Definition: fmgr.h:350

References ereport, errcode(), errmsg(), ERROR, and PG_RETURN_VOID.

◆ pg_ndistinct_send()

Datum pg_ndistinct_send ( PG_FUNCTION_ARGS  )

Definition at line 848 of file pg_ndistinct.c.

849{
850 return byteasend(fcinfo);
851}
Datum byteasend(PG_FUNCTION_ARGS)
Definition: bytea.c:377

References byteasend().

◆ valid_subsequent_attnum()

static bool valid_subsequent_attnum ( AttrNumber  prev,
AttrNumber  cur 
)
static

Definition at line 403 of file pg_ndistinct.c.

404{
405 Assert(prev != 0);
406
407 if (prev > 0)
408 return ((cur > prev) || (cur < 0));
409
410 return (cur < prev);
411}
struct cursor * cur
Definition: ecpg.c:29
Assert(PointerIsAligned(start, uint64))

References Assert(), and cur.

Referenced by ndistinct_scalar().