Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 2d8bff6

Browse files
committed
Make all ereport() calls within gram.y provide error locations.
This patch responds to a comment that I (tgl) made in the discussion leading up to 774171c, that really all errors occurring during raw parsing should provide error cursors. Syntax errors reported by Bison will have one, and most of the handwritten ereport's in gram.y already provide one, but there were a few stragglers. (It is not claimed that this handles every failure reachable during raw parsing --- out-of-memory is an obvious exception. But this makes a good start on cases that are likely to occur.) While we're at it, clean up the reported positions for errors associated with LIMIT/OFFSET clauses. Previously we were relying on applying exprLocation() to the contained expressions, but that leads to slightly odd cursor placement, e.g. regression=# (select * from foo limit 10) limit 10; ERROR: multiple LIMIT clauses not allowed LINE 1: (select * from foo limit 10) limit 10; ^ We can afford to keep a little more state in the transient SelectLimit structs in order to make that better. Jian He and Tom Lane (extracted from a larger patch by Jian, with some additional work by me) Discussion: https://postgr.es/m/CACJufxEmONE3P2En=jopZy1m=cCCUs65M4+1o52MW5og9oaUPA@mail.gmail.com
1 parent 89e51ab commit 2d8bff6

File tree

4 files changed

+62
-22
lines changed

4 files changed

+62
-22
lines changed

src/backend/parser/gram.y

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,15 @@ typedef struct ImportQual
105105
List *table_names;
106106
} ImportQual;
107107

108-
/* Private struct for the result of opt_select_limit production */
108+
/* Private struct for the result of select_limit & limit_clause productions */
109109
typedef struct SelectLimit
110110
{
111111
Node *limitOffset;
112112
Node *limitCount;
113-
LimitOption limitOption;
113+
LimitOption limitOption; /* indicates presence of WITH TIES */
114+
ParseLoc offsetLoc; /* location of OFFSET token, if present */
115+
ParseLoc countLoc; /* location of LIMIT/FETCH token, if present */
116+
ParseLoc optionLoc; /* location of WITH TIES, if present */
114117
} SelectLimit;
115118

116119
/* Private struct for the result of group_clause production */
@@ -195,7 +198,8 @@ static void SplitColQualList(List *qualList,
195198
static void processCASbits(int cas_bits, int location, const char *constrType,
196199
bool *deferrable, bool *initdeferred, bool *not_valid,
197200
bool *no_inherit, core_yyscan_t yyscanner);
198-
static PartitionStrategy parsePartitionStrategy(char *strategy);
201+
static PartitionStrategy parsePartitionStrategy(char *strategy, int location,
202+
core_yyscan_t yyscanner);
199203
static void preprocess_pubobj_list(List *pubobjspec_list,
200204
core_yyscan_t yyscanner);
201205
static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
@@ -3145,11 +3149,13 @@ PartitionBoundSpec:
31453149
if (n->modulus == -1)
31463150
ereport(ERROR,
31473151
(errcode(ERRCODE_SYNTAX_ERROR),
3148-
errmsg("modulus for hash partition must be specified")));
3152+
errmsg("modulus for hash partition must be specified"),
3153+
parser_errposition(@3)));
31493154
if (n->remainder == -1)
31503155
ereport(ERROR,
31513156
(errcode(ERRCODE_SYNTAX_ERROR),
3152-
errmsg("remainder for hash partition must be specified")));
3157+
errmsg("remainder for hash partition must be specified"),
3158+
parser_errposition(@3)));
31533159

31543160
n->location = @3;
31553161

@@ -4528,7 +4534,7 @@ PartitionSpec: PARTITION BY ColId '(' part_params ')'
45284534
{
45294535
PartitionSpec *n = makeNode(PartitionSpec);
45304536

4531-
n->strategy = parsePartitionStrategy($3);
4537+
n->strategy = parsePartitionStrategy($3, @3, yyscanner);
45324538
n->partParams = $5;
45334539
n->location = @1;
45344540

@@ -5962,7 +5968,8 @@ CreateTrigStmt:
59625968
if (n->replace) /* not supported, see CreateTrigger */
59635969
ereport(ERROR,
59645970
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5965-
errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported")));
5971+
errmsg("CREATE OR REPLACE CONSTRAINT TRIGGER is not supported"),
5972+
parser_errposition(@1)));
59665973
n->isconstraint = true;
59675974
n->trigname = $5;
59685975
n->relation = $9;
@@ -6247,7 +6254,8 @@ CreateAssertionStmt:
62476254
{
62486255
ereport(ERROR,
62496256
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
6250-
errmsg("CREATE ASSERTION is not yet implemented")));
6257+
errmsg("CREATE ASSERTION is not yet implemented"),
6258+
parser_errposition(@1)));
62516259

62526260
$$ = NULL;
62536261
}
@@ -13156,11 +13164,13 @@ select_limit:
1315613164
{
1315713165
$$ = $1;
1315813166
($$)->limitOffset = $2;
13167+
($$)->offsetLoc = @2;
1315913168
}
1316013169
| offset_clause limit_clause
1316113170
{
1316213171
$$ = $2;
1316313172
($$)->limitOffset = $1;
13173+
($$)->offsetLoc = @1;
1316413174
}
1316513175
| limit_clause
1316613176
{
@@ -13173,6 +13183,9 @@ select_limit:
1317313183
n->limitOffset = $1;
1317413184
n->limitCount = NULL;
1317513185
n->limitOption = LIMIT_OPTION_COUNT;
13186+
n->offsetLoc = @1;
13187+
n->countLoc = -1;
13188+
n->optionLoc = -1;
1317613189
$$ = n;
1317713190
}
1317813191
;
@@ -13190,6 +13203,9 @@ limit_clause:
1319013203
n->limitOffset = NULL;
1319113204
n->limitCount = $2;
1319213205
n->limitOption = LIMIT_OPTION_COUNT;
13206+
n->offsetLoc = -1;
13207+
n->countLoc = @1;
13208+
n->optionLoc = -1;
1319313209
$$ = n;
1319413210
}
1319513211
| LIMIT select_limit_value ',' select_offset_value
@@ -13215,6 +13231,9 @@ limit_clause:
1321513231
n->limitOffset = NULL;
1321613232
n->limitCount = $3;
1321713233
n->limitOption = LIMIT_OPTION_COUNT;
13234+
n->offsetLoc = -1;
13235+
n->countLoc = @1;
13236+
n->optionLoc = -1;
1321813237
$$ = n;
1321913238
}
1322013239
| FETCH first_or_next select_fetch_first_value row_or_rows WITH TIES
@@ -13224,6 +13243,9 @@ limit_clause:
1322413243
n->limitOffset = NULL;
1322513244
n->limitCount = $3;
1322613245
n->limitOption = LIMIT_OPTION_WITH_TIES;
13246+
n->offsetLoc = -1;
13247+
n->countLoc = @1;
13248+
n->optionLoc = @5;
1322713249
$$ = n;
1322813250
}
1322913251
| FETCH first_or_next row_or_rows ONLY
@@ -13233,6 +13255,9 @@ limit_clause:
1323313255
n->limitOffset = NULL;
1323413256
n->limitCount = makeIntConst(1, -1);
1323513257
n->limitOption = LIMIT_OPTION_COUNT;
13258+
n->offsetLoc = -1;
13259+
n->countLoc = @1;
13260+
n->optionLoc = -1;
1323613261
$$ = n;
1323713262
}
1323813263
| FETCH first_or_next row_or_rows WITH TIES
@@ -13242,6 +13267,9 @@ limit_clause:
1324213267
n->limitOffset = NULL;
1324313268
n->limitCount = makeIntConst(1, -1);
1324413269
n->limitOption = LIMIT_OPTION_WITH_TIES;
13270+
n->offsetLoc = -1;
13271+
n->countLoc = @1;
13272+
n->optionLoc = @4;
1324513273
$$ = n;
1324613274
}
1324713275
;
@@ -16954,8 +16982,9 @@ json_format_clause:
1695416982
encoding = JS_ENC_UTF32;
1695516983
else
1695616984
ereport(ERROR,
16957-
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16958-
errmsg("unrecognized JSON encoding: %s", $4));
16985+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
16986+
errmsg("unrecognized JSON encoding: %s", $4),
16987+
parser_errposition(@4)));
1695916988

1696016989
$$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, encoding, @1);
1696116990
}
@@ -17457,7 +17486,8 @@ PLpgSQL_Expr: opt_distinct_clause opt_target_list
1745717486
$9->limitOption == LIMIT_OPTION_WITH_TIES)
1745817487
ereport(ERROR,
1745917488
(errcode(ERRCODE_SYNTAX_ERROR),
17460-
errmsg("WITH TIES cannot be specified without ORDER BY clause")));
17489+
errmsg("WITH TIES cannot be specified without ORDER BY clause"),
17490+
parser_errposition($9->optionLoc)));
1746117491
n->limitOption = $9->limitOption;
1746217492
}
1746317493
n->lockingClause = $10;
@@ -18962,7 +18992,7 @@ insertSelectOptions(SelectStmt *stmt,
1896218992
ereport(ERROR,
1896318993
(errcode(ERRCODE_SYNTAX_ERROR),
1896418994
errmsg("multiple OFFSET clauses not allowed"),
18965-
parser_errposition(exprLocation(limitClause->limitOffset))));
18995+
parser_errposition(limitClause->offsetLoc)));
1896618996
stmt->limitOffset = limitClause->limitOffset;
1896718997
}
1896818998
if (limitClause && limitClause->limitCount)
@@ -18971,19 +19001,18 @@ insertSelectOptions(SelectStmt *stmt,
1897119001
ereport(ERROR,
1897219002
(errcode(ERRCODE_SYNTAX_ERROR),
1897319003
errmsg("multiple LIMIT clauses not allowed"),
18974-
parser_errposition(exprLocation(limitClause->limitCount))));
19004+
parser_errposition(limitClause->countLoc)));
1897519005
stmt->limitCount = limitClause->limitCount;
1897619006
}
1897719007
if (limitClause)
1897819008
{
18979-
if (stmt->limitOption)
18980-
ereport(ERROR,
18981-
(errcode(ERRCODE_SYNTAX_ERROR),
18982-
errmsg("multiple limit options not allowed")));
19009+
/* If there was a conflict, we must have detected it above */
19010+
Assert(!stmt->limitOption);
1898319011
if (!stmt->sortClause && limitClause->limitOption == LIMIT_OPTION_WITH_TIES)
1898419012
ereport(ERROR,
1898519013
(errcode(ERRCODE_SYNTAX_ERROR),
18986-
errmsg("WITH TIES cannot be specified without ORDER BY clause")));
19014+
errmsg("WITH TIES cannot be specified without ORDER BY clause"),
19015+
parser_errposition(limitClause->optionLoc)));
1898719016
if (limitClause->limitOption == LIMIT_OPTION_WITH_TIES && stmt->lockingClause)
1898819017
{
1898919018
ListCell *lc;
@@ -18996,7 +19025,8 @@ insertSelectOptions(SelectStmt *stmt,
1899619025
ereport(ERROR,
1899719026
(errcode(ERRCODE_SYNTAX_ERROR),
1899819027
errmsg("%s and %s options cannot be used together",
18999-
"SKIP LOCKED", "WITH TIES")));
19028+
"SKIP LOCKED", "WITH TIES"),
19029+
parser_errposition(limitClause->optionLoc)));
1900019030
}
1900119031
}
1900219032
stmt->limitOption = limitClause->limitOption;
@@ -19425,7 +19455,7 @@ processCASbits(int cas_bits, int location, const char *constrType,
1942519455
* PartitionStrategy representation, or die trying.
1942619456
*/
1942719457
static PartitionStrategy
19428-
parsePartitionStrategy(char *strategy)
19458+
parsePartitionStrategy(char *strategy, int location, core_yyscan_t yyscanner)
1942919459
{
1943019460
if (pg_strcasecmp(strategy, "list") == 0)
1943119461
return PARTITION_STRATEGY_LIST;
@@ -19436,8 +19466,8 @@ parsePartitionStrategy(char *strategy)
1943619466

1943719467
ereport(ERROR,
1943819468
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
19439-
errmsg("unrecognized partitioning strategy \"%s\"",
19440-
strategy)));
19469+
errmsg("unrecognized partitioning strategy \"%s\"", strategy),
19470+
parser_errposition(location)));
1944119471
return PARTITION_STRATEGY_LIST; /* keep compiler quiet */
1944219472

1944319473
}

src/test/regress/expected/create_table.out

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ CREATE TABLE partitioned (
198198
a int
199199
) PARTITION BY MAGIC (a);
200200
ERROR: unrecognized partitioning strategy "magic"
201+
LINE 3: ) PARTITION BY MAGIC (a);
202+
^
201203
-- specified column must be present in the table
202204
CREATE TABLE partitioned (
203205
a int

src/test/regress/expected/limit.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,11 +624,15 @@ SELECT thousand
624624
FROM onek WHERE thousand < 5
625625
ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE SKIP LOCKED;
626626
ERROR: SKIP LOCKED and WITH TIES options cannot be used together
627+
LINE 3: ORDER BY thousand FETCH FIRST 1 ROW WITH TIES FOR UPDATE S...
628+
^
627629
-- should fail
628630
SELECT ''::text AS two, unique1, unique2, stringu1
629631
FROM onek WHERE unique1 > 50
630632
FETCH FIRST 2 ROW WITH TIES;
631633
ERROR: WITH TIES cannot be specified without ORDER BY clause
634+
LINE 3: FETCH FIRST 2 ROW WITH TIES;
635+
^
632636
-- test ruleutils
633637
CREATE VIEW limit_thousand_v_1 AS SELECT thousand FROM onek WHERE thousand < 995
634638
ORDER BY thousand FETCH FIRST 5 ROWS WITH TIES OFFSET 10;

src/test/regress/expected/sqljson.out

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,8 @@ LINE 1: SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING UTF8)...
337337
^
338338
SELECT JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
339339
ERROR: unrecognized JSON encoding: invalid_encoding
340+
LINE 1: ...T JSON_OBJECT(RETURNING text FORMAT JSON ENCODING INVALID_EN...
341+
^
340342
SELECT JSON_OBJECT(RETURNING bytea);
341343
json_object
342344
-------------
@@ -620,6 +622,8 @@ LINE 1: SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING UTF8);
620622
^
621623
SELECT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_ENCODING);
622624
ERROR: unrecognized JSON encoding: invalid_encoding
625+
LINE 1: ...CT JSON_ARRAY(RETURNING text FORMAT JSON ENCODING INVALID_EN...
626+
^
623627
SELECT JSON_ARRAY(RETURNING bytea);
624628
json_array
625629
------------

0 commit comments

Comments
 (0)