diff --git a/src/test/modules/test_extensible/expected/test_extensible.out b/src/test/modules/test_extensible/expected/test_extensible.out index 1fa3b6d2c55..acc0a1af7fa 100644 --- a/src/test/modules/test_extensible/expected/test_extensible.out +++ b/src/test/modules/test_extensible/expected/test_extensible.out @@ -91,6 +91,13 @@ SELECT test_ext_node_equal(test_ext_node_make('1234'::oid, 2), -- correct node type, missing field SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename TestExtNode}'); ERROR: unexpected end of "TestExtNode" +-- incorrect node patterns +SELECT test_ext_node_get_relid('{QUERY}'); +ERROR: argument is not a serialized "TestExtNode" +SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename NoSuchExtNode}'); +ERROR: argument is not a serialized "TestExtNode" +SELECT test_ext_node_get_relid('42'); +ERROR: argument is not a serialized "TestExtNode" -- CustomScan tests CREATE TABLE test_extensible_tbl (id integer, val text); INSERT INTO test_extensible_tbl VALUES (1, 'one'), (2, 'two'), (3, 'three'); diff --git a/src/test/modules/test_extensible/sql/test_extensible.sql b/src/test/modules/test_extensible/sql/test_extensible.sql index b23bd1cd087..72eb3cf82af 100644 --- a/src/test/modules/test_extensible/sql/test_extensible.sql +++ b/src/test/modules/test_extensible/sql/test_extensible.sql @@ -33,6 +33,10 @@ SELECT test_ext_node_equal(test_ext_node_make('1234'::oid, 2), -- correct node type, missing field SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename TestExtNode}'); +-- incorrect node patterns +SELECT test_ext_node_get_relid('{QUERY}'); +SELECT test_ext_node_get_relid('{EXTENSIBLENODE :extnodename NoSuchExtNode}'); +SELECT test_ext_node_get_relid('42'); -- CustomScan tests CREATE TABLE test_extensible_tbl (id integer, val text); diff --git a/src/test/modules/test_extensible/test_extensible.c b/src/test/modules/test_extensible/test_extensible.c index 2a1344f28d5..dafcd772f56 100644 --- a/src/test/modules/test_extensible/test_extensible.c +++ b/src/test/modules/test_extensible/test_extensible.c @@ -99,13 +99,16 @@ test_ext_node_out_cb(StringInfo str, const ExtensibleNode *node) } /* - * Fetch the next token, erroring out instead of returning NULL. + * Fetch the next token of the string being read. * - * Unlike anything in readfuncs.c, this callback is reachable with arbitrary - * strings through SQL function calls, so we need this check. + * Unlike anything in readfuncs.c, this is reachable with arbitrary strings + * through SQL function calls, so the tokens need to be checked. + * + * If "expected" is specified, check that the token fetched matches with + * the input expected. Running out of tokens is a failure. */ static const char * -test_ext_node_next_token(ReadNodeContext *ctx) +test_ext_node_next_token(ReadNodeContext *ctx, const char *expected) { int length; const char *token = pg_strtok(ctx, &length); @@ -115,6 +118,14 @@ test_ext_node_next_token(ReadNodeContext *ctx) (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("unexpected end of \"%s\"", TEST_EXT_NODE_NAME))); + if (expected != NULL) + { + if (length != (int) strlen(expected)) + return NULL; + if (memcmp(token, expected, length) != 0) + return NULL; + } + return token; } @@ -123,11 +134,11 @@ test_ext_node_read_cb(ReadNodeContext *ctx, ExtensibleNode *node) { TestExtNode *tnode = (TestExtNode *) node; - (void) test_ext_node_next_token(ctx); /* skip :relid */ - tnode->relid = atooid(test_ext_node_next_token(ctx)); + (void) test_ext_node_next_token(ctx, NULL); /* skip :relid */ + tnode->relid = atooid(test_ext_node_next_token(ctx, NULL)); - (void) test_ext_node_next_token(ctx); /* skip :repeat_count */ - tnode->repeat_count = atoi(test_ext_node_next_token(ctx)); + (void) test_ext_node_next_token(ctx, NULL); /* skip :repeat_count */ + tnode->repeat_count = atoi(test_ext_node_next_token(ctx, NULL)); } static const ExtensibleNodeMethods test_ext_node_methods = @@ -469,16 +480,26 @@ test_get_custom_scan_methods(PG_FUNCTION_ARGS) static TestExtNode * text_to_test_ext_node(text *txt) { - Node *node = stringToNode(text_to_cstring(txt)); + char *str = text_to_cstring(txt); + ReadNodeContext ctx; + TestExtNode *tnode; - if (node == NULL || !IsA(node, ExtensibleNode) || - strcmp(((ExtensibleNode *) node)->extnodename, TEST_EXT_NODE_NAME) != 0) + ctx.str = str; + + if (test_ext_node_next_token(&ctx, "{") == NULL || + test_ext_node_next_token(&ctx, "EXTENSIBLENODE") == NULL || + test_ext_node_next_token(&ctx, ":extnodename") == NULL || + test_ext_node_next_token(&ctx, TEST_EXT_NODE_NAME) == NULL) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("argument is not a serialized \"%s\"", TEST_EXT_NODE_NAME))); - return (TestExtNode *) node; + tnode = (TestExtNode *) stringToNode(str); + Assert(IsA(tnode, ExtensibleNode) && + strcmp(tnode->base.extnodename, TEST_EXT_NODE_NAME) == 0); + + return tnode; } /*