On Tue, Oct 29, 2024 at 10:49 PM Alvaro Herrera <alvhe...@alvh.no-ip.org> wrote: > > Why remove parsePartitionStrategy? You could just add an "int location" > parameter to it. >
now changed to static PartitionStrategy parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner);
From 2ec4466576778e42d3936252c90fc1936082c640 Mon Sep 17 00:00:00 2001 From: jian he <jian.universal...@gmail.com> Date: Wed, 30 Oct 2024 09:53:15 +0800 Subject: [PATCH v2 1/1] add cursor position in various ereport function in gram.y inspired by this[1] [1]: https://postgr.es/m/3482022.1728839631%40sss.pgh.pa.us but i am not so sure the handing in insertSelectOptions is correct. discussion: https://postgr.es/m/CACJufxEmONE3P2En=jopZy1m=cccus65m4+1o52mw5og9oa...@mail.gmail.com --- src/backend/parser/gram.y | 66 +++++++++++++------ src/include/nodes/parsenodes.h | 1 + .../regress/expected/create_function_sql.out | 11 ++++ src/test/regress/expected/create_table.out | 2 + src/test/regress/expected/foreign_key.out | 4 ++ src/test/regress/expected/limit.out | 4 ++ src/test/regress/expected/sqljson.out | 4 ++ src/test/regress/sql/create_function_sql.sql | 7 ++ src/test/regress/sql/foreign_key.sql | 1 + 9 files changed, 81 insertions(+), 19 deletions(-) diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index dd458182f0..d1cb8a84c4 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -111,6 +111,7 @@ typedef struct SelectLimit Node *limitOffset; Node *limitCount; LimitOption limitOption; + ParseLoc location; } SelectLimit; /* Private struct for the result of group_clause production */ @@ -184,7 +185,7 @@ static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location); static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, int location); -static List *mergeTableFuncParameters(List *func_args, List *columns); +static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner); static TypeName *TableFuncTypeName(List *columns); static RangeVar *makeRangeVarFromAnyName(List *names, int position, core_yyscan_t yyscanner); static RangeVar *makeRangeVarFromQualifiedName(char *name, List *namelist, int location, @@ -195,7 +196,8 @@ static void SplitColQualList(List *qualList, static void processCASbits(int cas_bits, int location, const char *constrType, bool *deferrable, bool *initdeferred, bool *not_valid, bool *no_inherit, core_yyscan_t yyscanner); -static PartitionStrategy parsePartitionStrategy(char *strategy); +static PartitionStrategy parsePartitionStrategy(char *strategy, int location, + core_yyscan_t yyscanner); static void preprocess_pubobj_list(List *pubobjspec_list, core_yyscan_t yyscanner); static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); @@ -3145,11 +3147,14 @@ PartitionBoundSpec: if (n->modulus == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("modulus for hash partition must be specified"))); + errmsg("modulus for hash partition must be specified"), + parser_errposition(@4))); + if (n->remainder == -1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("remainder for hash partition must be specified"))); + errmsg("remainder for hash partition must be specified"), + parser_errposition(@4))); n->location = @3; @@ -4528,7 +4533,7 @@ PartitionSpec: PARTITION BY ColId '(' part_params ')' { PartitionSpec *n = makeNode(PartitionSpec); - n->strategy = parsePartitionStrategy($3); + n->strategy = parsePartitionStrategy($3, @3, yyscanner); n->partParams = $5; n->location = @1; @@ -5962,7 +5967,8 @@ CreateTrigStmt: if (n->replace) /* not supported, see CreateTrigger */ ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"))); + errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"), + parser_errposition(@2))); n->isconstraint = true; n->trigname = $5; n->relation = $9; @@ -6247,7 +6253,8 @@ CreateAssertionStmt: { ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("CREATE ASSERTION is not yet implemented"))); + errmsg("CREATE ASSERTION is not yet implemented"), + parser_errposition(@2))); $$ = NULL; } @@ -8290,7 +8297,7 @@ CreateFunctionStmt: n->is_procedure = false; n->replace = $2; n->funcname = $4; - n->parameters = mergeTableFuncParameters($5, $9); + n->parameters = mergeTableFuncParameters($5, $9, yyscanner); n->returnType = TableFuncTypeName($9); n->returnType->location = @7; n->options = $11; @@ -8423,6 +8430,7 @@ func_arg: n->argType = $3; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name arg_class func_type @@ -8433,6 +8441,7 @@ func_arg: n->argType = $3; n->mode = $2; n->defexpr = NULL; + n->location = @1; $$ = n; } | param_name func_type @@ -8443,6 +8452,7 @@ func_arg: n->argType = $2; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } | arg_class func_type @@ -8453,6 +8463,7 @@ func_arg: n->argType = $2; n->mode = $1; n->defexpr = NULL; + n->location = @1; $$ = n; } | func_type @@ -8463,6 +8474,7 @@ func_arg: n->argType = $1; n->mode = FUNC_PARAM_DEFAULT; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -8799,6 +8811,7 @@ table_func_column: param_name func_type n->argType = $2; n->mode = FUNC_PARAM_TABLE; n->defexpr = NULL; + n->location = @1; $$ = n; } ; @@ -13167,6 +13180,7 @@ select_limit: n->limitOffset = $1; n->limitCount = NULL; n->limitOption = LIMIT_OPTION_COUNT; + n->location = @1; $$ = n; } ; @@ -13184,6 +13198,7 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $2; n->limitOption = LIMIT_OPTION_COUNT; + n->location = @1; $$ = n; } | LIMIT select_limit_value ',' select_offset_value @@ -13209,6 +13224,7 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_COUNT; + n->location = @1; $$ = n; } | FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES @@ -13218,6 +13234,7 @@ limit_clause: n->limitOffset = NULL; n->limitCount = $3; n->limitOption = LIMIT_OPTION_WITH_TIES; + n->location = @5; $$ = n; } | FETCH first_or_next row_or_rows ONLY @@ -13227,6 +13244,7 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_COUNT; + n->location = @1; $$ = n; } | FETCH first_or_next row_or_rows WITH TIES @@ -13236,6 +13254,7 @@ limit_clause: n->limitOffset = NULL; n->limitCount = makeIntConst(1, -1); n->limitOption = LIMIT_OPTION_WITH_TIES; + n->location = @1; $$ = n; } ; @@ -16948,8 +16967,9 @@ json_format_clause: encoding = JS_ENC_UTF32; else ereport(ERROR, - errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized JSON encoding: %s", $4)); + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized JSON encoding: %s", $4), + parser_errposition(@4))); $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, encoding, @1); } @@ -17451,7 +17471,8 @@ PLpgSQL_Expr: opt_distinct_clause opt_target_list $9->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition(@9))); n->limitOption = $9->limitOption; } n->lockingClause = $10; @@ -18973,11 +18994,15 @@ insertSelectOptions(SelectStmt *stmt, if (stmt->limitOption) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("multiple limit options not allowed"))); + errmsg("multiple limit options not allowed"), + parser_errposition(limitClause->location))); + if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("WITH TIES cannot be specified without ORDER BY clause"))); + errmsg("WITH TIES cannot be specified without ORDER BY clause"), + parser_errposition(limitClause->location))); + if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause) { ListCell *lc; @@ -18990,7 +19015,8 @@ insertSelectOptions(SelectStmt *stmt, ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("%s and %s options cannot be used together", - "SKIP LOCKED", "WITH TIES"))); + "SKIP LOCKED", "WITH TIES"), + parser_errposition(limitClause->location))); } } stmt->limitOption = limitClause->limitOption; @@ -19183,7 +19209,7 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args, * Merge the input and output parameters of a table function. */ static List * -mergeTableFuncParameters(List *func_args, List *columns) +mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner) { ListCell *lc; @@ -19197,7 +19223,8 @@ mergeTableFuncParameters(List *func_args, List *columns) p->mode != FUNC_PARAM_VARIADIC) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"))); + errmsg("OUT and INOUT arguments aren't allowed in TABLE functions"), + parser_errposition(p->location))); } return list_concat(func_args, columns); @@ -19418,7 +19445,7 @@ processCASbits(int cas_bits, int location, const char *constrType, * PartitionStrategy representation, or die trying. */ static PartitionStrategy -parsePartitionStrategy(char *strategy) +parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner) { if (pg_strcasecmp(strategy, "list") == 0) return PARTITION_STRATEGY_LIST; @@ -19429,8 +19456,9 @@ parsePartitionStrategy(char *strategy) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), - errmsg("unrecognized partitioning strategy \"%s\"", - strategy))); + errmsg("unrecognized partitioning strategy \"%s\"",strategy), + parser_errposition(location))); + return PARTITION_STRATEGY_LIST; /* keep compiler quiet */ } diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index b40b661ec8..0d96db5638 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -3482,6 +3482,7 @@ typedef struct FunctionParameter TypeName *argType; /* TypeName for parameter type */ FunctionParameterMode mode; /* IN/OUT/etc */ Node *defexpr; /* raw default expr, or NULL if not given */ + ParseLoc location; /* token location, or -1 if unknown */ } FunctionParameter; typedef struct AlterFunctionStmt diff --git a/src/test/regress/expected/create_function_sql.out b/src/test/regress/expected/create_function_sql.out index 50aca5940f..a44986afa3 100644 --- a/src/test/regress/expected/create_function_sql.out +++ b/src/test/regress/expected/create_function_sql.out @@ -49,6 +49,17 @@ SELECT functest_A_3(); f (1 row) +-- OUT and INOUT arguments aren't allowed in TABLE functions +CREATE FUNCTION fn_intout(out c int) +RETURNS TABLE(a int) LANGUAGE sql AS $BODY$ select 1 $BODY$; +ERROR: OUT and INOUT arguments aren't allowed in TABLE functions +LINE 1: CREATE FUNCTION fn_intout(out c int) + ^ +CREATE FUNCTION fn_intout(inout c int) +RETURNS TABLE(a int) LANGUAGE sql AS $BODY$ select 1 $BODY$; +ERROR: OUT and INOUT arguments aren't allowed in TABLE functions +LINE 1: CREATE FUNCTION fn_intout(inout c int) + ^ -- -- IMMUTABLE | STABLE | VOLATILE -- diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out index c45e02d42f..57a24050ab 100644 --- a/src/test/regress/expected/create_table.out +++ b/src/test/regress/expected/create_table.out @@ -198,6 +198,8 @@ CREATE TABLE partitioned ( a int ) PARTITION BY MAGIC (a); ERROR: unrecognized partitioning strategy "magic" +LINE 3: ) PARTITION BY MAGIC (a); + ^ -- specified column must be present in the table CREATE TABLE partitioned ( a int diff --git a/src/test/regress/expected/foreign_key.out b/src/test/regress/expected/foreign_key.out index b73e7dced8..ed16dea924 100644 --- a/src/test/regress/expected/foreign_key.out +++ b/src/test/regress/expected/foreign_key.out @@ -2916,6 +2916,10 @@ $$; CREATE TRIGGER trig_upd_pk AFTER UPDATE ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE TRIGGER trig_del_pk AFTER DELETE ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE TRIGGER trig_ins_pk AFTER INSERT ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); +CREATE OR REPLACE CONSTRAINT TRIGGER trig_upd_fk_parted AFTER UPDATE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); +ERROR: CREATE OR REPLACE CONSTRAINT TRIGGER is not supported +LINE 1: CREATE OR REPLACE CONSTRAINT TRIGGER trig_upd_fk_parted AFTE... + ^ CREATE CONSTRAINT TRIGGER trig_upd_fk_parted AFTER UPDATE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE CONSTRAINT TRIGGER trig_del_fk_parted AFTER DELETE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE CONSTRAINT TRIGGER trig_ins_fk_parted AFTER INSERT ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); diff --git a/src/test/regress/expected/limit.out b/src/test/regress/expected/limit.out index a2cd0f9f5b..f4267c002d 100644 --- a/src/test/regress/expected/limit.out +++ b/src/test/regress/expected/limit.out @@ -624,11 +624,15 @@ SELECT thousand FROM onek WHERE thousand < 5 ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE SKIP LOCKED; ERROR: SKIP LOCKED and WITH TIES options cannot be used together +LINE 3: ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE S... + ^ -- should fail SELECT ''::text AS two, unique1, unique2, stringu1 FROM onek WHERE unique1 > 50 FETCH FIRST 2 ROW WITH TIES; ERROR: WITH TIES cannot be specified without ORDER BY clause +LINE 3: FETCH FIRST 2 ROW WITH TIES; + ^ -- test ruleutils CREATE VIEW limit_thousand_v_1 AS SELECT thousand FROM onek WHERE thousand < 995 ORDER BY thousand FETCH FIRST 5 ROWS WITH TIES OFFSET 10; diff --git a/src/test/regress/expected/sqljson.out b/src/test/regress/expected/sqljson.out index 70721c9a5a..435d61dd4a 100644 --- a/src/test/regress/expected/sqljson.out +++ b/src/test/regress/expected/sqljson.out @@ -337,6 +337,8 @@ LINE 1: SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8)... ^ SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); ERROR: unrecognized JSON encoding: invalid_encoding +LINE 1: ...T JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_EN... + ^ SELECT JSON_OBJECT(RETURNING bytea); json_object ------------- @@ -620,6 +622,8 @@ LINE 1: SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8); ^ SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING); ERROR: unrecognized JSON encoding: invalid_encoding +LINE 1: ...CT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_EN... + ^ SELECT JSON_ARRAY(RETURNING bytea); json_array ------------ diff --git a/src/test/regress/sql/create_function_sql.sql b/src/test/regress/sql/create_function_sql.sql index 89e9af3a49..384a7c0c3a 100644 --- a/src/test/regress/sql/create_function_sql.sql +++ b/src/test/regress/sql/create_function_sql.sql @@ -35,6 +35,13 @@ SELECT functest_A_1('abcd', '2020-01-01'); SELECT functest_A_2(ARRAY['1', '2', '3']); SELECT functest_A_3(); +-- OUT and INOUT arguments aren't allowed in TABLE functions +CREATE FUNCTION fn_intout(out c int) +RETURNS TABLE(a int) LANGUAGE sql AS $BODY$ select 1 $BODY$; + +CREATE FUNCTION fn_intout(inout c int) +RETURNS TABLE(a int) LANGUAGE sql AS $BODY$ select 1 $BODY$; + -- -- IMMUTABLE | STABLE | VOLATILE -- diff --git a/src/test/regress/sql/foreign_key.sql b/src/test/regress/sql/foreign_key.sql index 9b2a6b6bff..393e8524f8 100644 --- a/src/test/regress/sql/foreign_key.sql +++ b/src/test/regress/sql/foreign_key.sql @@ -2079,6 +2079,7 @@ $$; CREATE TRIGGER trig_upd_pk AFTER UPDATE ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE TRIGGER trig_del_pk AFTER DELETE ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE TRIGGER trig_ins_pk AFTER INSERT ON fkpart11.pk FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); +CREATE OR REPLACE CONSTRAINT TRIGGER trig_upd_fk_parted AFTER UPDATE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE CONSTRAINT TRIGGER trig_upd_fk_parted AFTER UPDATE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE CONSTRAINT TRIGGER trig_del_fk_parted AFTER DELETE ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); CREATE CONSTRAINT TRIGGER trig_ins_fk_parted AFTER INSERT ON fkpart11.fk_parted INITIALLY DEFERRED FOR EACH ROW EXECUTE FUNCTION fkpart11.print_row(); -- 2.34.1