From dbbba5eb02e4466e8d477a6fef89cc437d57690c Mon Sep 17 00:00:00 2001 From: jian he Date: Wed, 19 Nov 2025 15:40:20 +0800 Subject: [PATCH v15 1/1] miscellaneous refactoring/tests for v15 discussion: https://postgr.es/m/CADkLM=czQ0UUyBn3AiHZfJJWRwXH5e2xn056yG0mpuXpW09RSw@mail.gmail.com --- src/backend/utils/adt/pg_ndistinct.c | 38 ++++++++++++---------- src/test/regress/expected/pg_ndistinct.out | 36 +++++++++++++++++--- src/test/regress/sql/pg_ndistinct.sql | 5 +++ 3 files changed, 57 insertions(+), 22 deletions(-) diff --git a/src/backend/utils/adt/pg_ndistinct.c b/src/backend/utils/adt/pg_ndistinct.c index 87bc3cf41ae..b777f142f37 100644 --- a/src/backend/utils/adt/pg_ndistinct.c +++ b/src/backend/utils/adt/pg_ndistinct.c @@ -33,7 +33,7 @@ typedef enum NDIST_EXPECT_ATTNUM_LIST, NDIST_EXPECT_ATTNUM, NDIST_EXPECT_NDISTINCT, - NDIST_EXPECT_COMPLETE + NDIST_EXPECT_COMPLETE, } NDistinctSemanticState; typedef struct @@ -116,6 +116,7 @@ ndistinct_object_start(void *state) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Unexpected parse state: %d", (int) parse->state)); + break; } return JSON_SEM_ACTION_FAILED; @@ -176,7 +177,7 @@ ndistinct_object_end(void *state) errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("The \"%s\" key must contain an array of at least %d " "and no more than %d attributes.", - PG_NDISTINCT_KEY_NDISTINCT, 2, STATS_MAX_DIMENSIONS)); + PG_NDISTINCT_KEY_ATTRIBUTES, 2, STATS_MAX_DIMENSIONS)); return JSON_SEM_ACTION_FAILED; } @@ -247,7 +248,7 @@ ndistinct_array_end(void *state) switch (parse->state) { case NDIST_EXPECT_ATTNUM: - if (parse->attnum_list != NIL) + if (list_length(parse->attnum_list) > 0) { /* * The attribute number list is complete, look for more @@ -265,7 +266,7 @@ ndistinct_array_end(void *state) break; case NDIST_EXPECT_ITEM: - if (parse->distinct_items != NIL) + if (list_length(parse->distinct_items) > 0) { /* Item list is complete, we are done. */ parse->state = NDIST_EXPECT_COMPLETE; @@ -287,6 +288,7 @@ ndistinct_array_end(void *state) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Array found in unexpected place.")); + break; } return JSON_SEM_ACTION_FAILED; @@ -326,7 +328,7 @@ ndistinct_object_field_start(void *state, char *fname, bool isnull) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Multiple \"%s\" keys are not allowed.", - PG_NDISTINCT_KEY_NDISTINCT)); + PG_NDISTINCT_KEY_NDISTINCT)); return JSON_SEM_ACTION_FAILED; } parse->found_ndistinct = true; @@ -379,6 +381,7 @@ ndistinct_array_element_start(void *state, bool isnull) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Unexpected array element.")); + break; } return JSON_SEM_ACTION_FAILED; @@ -444,11 +447,11 @@ ndistinct_scalar(void *state, char *token, JsonTokenType tokentype) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Invalid \"%s\" element: %d.", - PG_NDISTINCT_KEY_ATTRIBUTES, attnum)); + PG_NDISTINCT_KEY_ATTRIBUTES, attnum)); return JSON_SEM_ACTION_FAILED; } - if (parse->attnum_list != NIL) + if (list_length(parse->attnum_list) > 0) { const AttrNumber prev = llast_int(parse->attnum_list); @@ -463,7 +466,7 @@ ndistinct_scalar(void *state, char *token, JsonTokenType tokentype) } } - parse->attnum_list = lappend_int(parse->attnum_list, (int) attnum); + parse->attnum_list = lappend_int(parse->attnum_list, attnum); return JSON_SUCCESS; break; @@ -493,6 +496,7 @@ ndistinct_scalar(void *state, char *token, JsonTokenType tokentype) errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("malformed pg_ndistinct: \"%s\"", parse->str), errdetail("Unexpected scalar.")); + break; } return JSON_SEM_ACTION_FAILED; @@ -614,7 +618,7 @@ pg_ndistinct_in(PG_FUNCTION_ARGS) if (result == JSON_SUCCESS) { MVNDistinct *ndistinct; - int nitems = parse_state.distinct_items->length; + int nitems = list_length(parse_state.distinct_items); bytea *bytes; switch (parse_state.state) @@ -626,7 +630,7 @@ pg_ndistinct_in(PG_FUNCTION_ARGS) * items. If we don't, something has been done wrong in one * of the earlier parsing steps. */ - if (parse_state.distinct_items == NIL) + if (list_length(parse_state.distinct_items) == 0) elog(ERROR, "cannot have empty item list after parsing success."); break; @@ -657,15 +661,15 @@ pg_ndistinct_in(PG_FUNCTION_ARGS) ndistinct->type = STATS_NDISTINCT_TYPE_BASIC; ndistinct->nitems = nitems; - for (int i = 0; i < nitems; i++) + foreach_ptr(MVNDistinctItem, item, parse_state.distinct_items) { - MVNDistinctItem *item = parse_state.distinct_items->elements[i].ptr_value; + int idx = foreach_current_index(item); /* * Ensure that this item does not duplicate the attributes of any * pre-existing item. */ - for (int j = 0; j < i; j++) + for (int j = 0; j < idx; j++) { if (has_duplicate_attributes(item, &ndistinct->items[j])) { @@ -679,9 +683,9 @@ pg_ndistinct_in(PG_FUNCTION_ARGS) } } - ndistinct->items[i].ndistinct = item->ndistinct; - ndistinct->items[i].nattributes = item->nattributes; - ndistinct->items[i].attributes = item->attributes; + ndistinct->items[idx].ndistinct = item->ndistinct; + ndistinct->items[idx].nattributes = item->nattributes; + ndistinct->items[idx].attributes = item->attributes; /* * Keep track of the first longest attribute list. All other @@ -690,7 +694,7 @@ pg_ndistinct_in(PG_FUNCTION_ARGS) if (item->nattributes > item_most_attrs) { item_most_attrs = item->nattributes; - item_most_attrs_idx = i; + item_most_attrs_idx = idx; } /* diff --git a/src/test/regress/expected/pg_ndistinct.out b/src/test/regress/expected/pg_ndistinct.out index eb3f74a3fff..d2f59efdc15 100644 --- a/src/test/regress/expected/pg_ndistinct.out +++ b/src/test/regress/expected/pg_ndistinct.out @@ -71,6 +71,11 @@ ERROR: malformed pg_ndistinct: "[{"attributes" : [2,3], "attributes" : [1,3], " LINE 1: SELECT '[{"attributes" : [2,3], "attributes" : [1,3], "ndist... ^ DETAIL: Multiple "attributes" keys are not allowed. +SELECT '[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]'::pg_ndistinct; +ERROR: malformed pg_ndistinct: "[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]" +LINE 1: SELECT '[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct"... + ^ +DETAIL: Multiple "ndistinct" keys are not allowed. SELECT * FROM pg_input_error_info('[{"attributes_invalid" : [2,3], "ndistinct" : 4}]', 'pg_ndistinct'); message | detail | hint | sql_error_code -----------------------------------------------------------------------------+-----------------------------------------------------+------+---------------- @@ -89,6 +94,12 @@ SELECT * FROM pg_input_error_info('[{"attributes" : [2,3], "attributes" : [1,3], malformed pg_ndistinct: "[{"attributes" : [2,3], "attributes" : [1,3], "ndistinct" : 4}]" | Multiple "attributes" keys are not allowed. | | 22P02 (1 row) +SELECT * FROM pg_input_error_info('[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]', 'pg_ndistinct'); + message | detail | hint | sql_error_code +--------------------------------------------------------------------------------------+--------------------------------------------+------+---------------- + malformed pg_ndistinct: "[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]" | Multiple "ndistinct" keys are not allowed. | | 22P02 +(1 row) + -- Missing key SELECT '[{"attributes" : [2,3]}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"attributes" : [2,3]}]" @@ -117,7 +128,7 @@ SELECT '[{"attributes" : [1,2,3,4,5,6,7,8,9], "ndistinct" : 4}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"attributes" : [1,2,3,4,5,6,7,8,9], "ndistinct" : 4}]" LINE 1: SELECT '[{"attributes" : [1,2,3,4,5,6,7,8,9], "ndistinct" : ... ^ -DETAIL: The "ndistinct" key must contain an array of at least 2 and no more than 8 attributes. +DETAIL: The "attributes" key must contain an array of at least 2 and no more than 8 attributes. -- Special characters SELECT '[{"\ud83d\ude04\ud83d\udc36" : [1, 2], "ndistinct" : 4}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"\ud83d\ude04\ud83d\udc36" : [1, 2], "ndistinct" : 4}]" @@ -154,7 +165,7 @@ SELECT '[{"attributes" : [2], "ndistinct" : 4}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"attributes" : [2], "ndistinct" : 4}]" LINE 1: SELECT '[{"attributes" : [2], "ndistinct" : 4}]'::pg_ndistin... ^ -DETAIL: The "ndistinct" key must contain an array of at least 2 and no more than 8 attributes. +DETAIL: The "attributes" key must contain an array of at least 2 and no more than 8 attributes. SELECT '[{"attributes" : [2,null], "ndistinct" : 4}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"attributes" : [2,null], "ndistinct" : 4}]" LINE 1: SELECT '[{"attributes" : [2,null], "ndistinct" : 4}]'::pg_nd... @@ -195,6 +206,21 @@ ERROR: malformed pg_ndistinct: "[{"attributes" : [2,3], "ndistinct" : {"a": 1}} LINE 1: SELECT '[{"attributes" : [2,3], "ndistinct" : {"a": 1}}]'::p... ^ DETAIL: Value of "ndistinct" must be an integer. +SELECT '[{"attributes" : [0,1], "ndistinct" : 1}}]'::pg_ndistinct; +ERROR: malformed pg_ndistinct: "[{"attributes" : [0,1], "ndistinct" : 1}}]" +LINE 1: SELECT '[{"attributes" : [0,1], "ndistinct" : 1}}]'::pg_ndis... + ^ +DETAIL: Invalid "attributes" element: 0. +SELECT '[{"attributes" : [-7, -9], "ndistinct" : 1}]'::pg_ndistinct; +ERROR: malformed pg_ndistinct: "[{"attributes" : [-7, -9], "ndistinct" : 1}]" +LINE 1: SELECT '[{"attributes" : [-7, -9], "ndistinct" : 1}]'::pg_nd... + ^ +DETAIL: Invalid "attributes" element: -9. +SELECT '[{"attributes" : [1, -9], "ndistinct" : 1}]'::pg_ndistinct; +ERROR: malformed pg_ndistinct: "[{"attributes" : [1, -9], "ndistinct" : 1}]" +LINE 1: SELECT '[{"attributes" : [1, -9], "ndistinct" : 1}]'::pg_ndi... + ^ +DETAIL: Invalid "attributes" element: -9. SELECT '[{"attributes" : 1, "ndistinct" : 4}]'::pg_ndistinct; ERROR: malformed pg_ndistinct: "[{"attributes" : 1, "ndistinct" : 4}]" LINE 1: SELECT '[{"attributes" : 1, "ndistinct" : 4}]'::pg_ndistinct... @@ -228,9 +254,9 @@ SELECT * FROM pg_input_error_info('[{"attributes" : [], "ndistinct" : 1}]', 'pg_ (1 row) SELECT * FROM pg_input_error_info('[{"attributes" : [2], "ndistinct" : 4}]', 'pg_ndistinct'); - message | detail | hint | sql_error_code --------------------------------------------------------------------+----------------------------------------------------------------------------------------+------+---------------- - malformed pg_ndistinct: "[{"attributes" : [2], "ndistinct" : 4}]" | The "ndistinct" key must contain an array of at least 2 and no more than 8 attributes. | | 22P02 + message | detail | hint | sql_error_code +-------------------------------------------------------------------+-----------------------------------------------------------------------------------------+------+---------------- + malformed pg_ndistinct: "[{"attributes" : [2], "ndistinct" : 4}]" | The "attributes" key must contain an array of at least 2 and no more than 8 attributes. | | 22P02 (1 row) SELECT * FROM pg_input_error_info('[{"attributes" : [2,null], "ndistinct" : 4}]', 'pg_ndistinct'); diff --git a/src/test/regress/sql/pg_ndistinct.sql b/src/test/regress/sql/pg_ndistinct.sql index 7646dedc2d0..9ba940589d4 100644 --- a/src/test/regress/sql/pg_ndistinct.sql +++ b/src/test/regress/sql/pg_ndistinct.sql @@ -15,9 +15,11 @@ SELECT * FROM pg_input_error_info('[null]', 'pg_ndistinct'); SELECT '[{"attributes_invalid" : [2,3], "ndistinct" : 4}]'::pg_ndistinct; SELECT '[{"attributes" : [2,3], "invalid" : 3, "ndistinct" : 4}]'::pg_ndistinct; SELECT '[{"attributes" : [2,3], "attributes" : [1,3], "ndistinct" : 4}]'::pg_ndistinct; +SELECT '[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]'::pg_ndistinct; SELECT * FROM pg_input_error_info('[{"attributes_invalid" : [2,3], "ndistinct" : 4}]', 'pg_ndistinct'); SELECT * FROM pg_input_error_info('[{"attributes" : [2,3], "invalid" : 3, "ndistinct" : 4}]', 'pg_ndistinct'); SELECT * FROM pg_input_error_info('[{"attributes" : [2,3], "attributes" : [1,3], "ndistinct" : 4}]', 'pg_ndistinct'); +SELECT * FROM pg_input_error_info('[{"attributes" : [2,3], "ndistinct" : 4, "ndistinct" : 4}]', 'pg_ndistinct'); -- Missing key SELECT '[{"attributes" : [2,3]}]'::pg_ndistinct; @@ -46,6 +48,9 @@ SELECT '[{"attributes" : [2,3], "ndistinct" : []}]'::pg_ndistinct; SELECT '[{"attributes" : [2,3], "ndistinct" : [null]}]'::pg_ndistinct; SELECT '[{"attributes" : [2,3], "ndistinct" : [1,null]}]'::pg_ndistinct; SELECT '[{"attributes" : [2,3], "ndistinct" : {"a": 1}}]'::pg_ndistinct; +SELECT '[{"attributes" : [0,1], "ndistinct" : 1}}]'::pg_ndistinct; +SELECT '[{"attributes" : [-7, -9], "ndistinct" : 1}]'::pg_ndistinct; +SELECT '[{"attributes" : [1, -9], "ndistinct" : 1}]'::pg_ndistinct; SELECT '[{"attributes" : 1, "ndistinct" : 4}]'::pg_ndistinct; SELECT '[{"attributes" : "a", "ndistinct" : 4}]'::pg_ndistinct; SELECT '[{"attributes" : {"a": 1}, "ndistinct" : 1}]'::pg_ndistinct; -- 2.34.1