pg_stat_statements_norm_v4.patch
text/x-patch
Filename: pg_stat_statements_norm_v4.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
Series: patch v4
| File | + | − |
|---|---|---|
| contrib/pg_stat_statements/pg_stat_statements.c | 931 | 54 |
| src/backend/catalog/heap.c | 1 | 1 |
| src/backend/commands/prepare.c | 1 | 1 |
| src/backend/commands/tablecmds.c | 3 | 3 |
| src/backend/nodes/copyfuncs.c | 2 | 0 |
| src/backend/parser/gram.y | 397 | 386 |
| src/backend/parser/parse_clause.c | 4 | 4 |
| src/backend/parser/parse_coerce.c | 18 | 8 |
| src/backend/parser/parse_expr.c | 7 | 5 |
| src/backend/parser/parse_func.c | 3 | 3 |
| src/backend/parser/parse_node.c | 6 | 4 |
| src/backend/parser/parse_target.c | 3 | 3 |
| src/backend/parser/scan.l | 91 | 31 |
| src/backend/rewrite/rewriteHandler.c | 1 | 1 |
| src/include/nodes/parsenodes.h | 2 | 0 |
| src/include/nodes/primnodes.h | 1 | 0 |
| src/include/parser/parse_coerce.h | 3 | 2 |
| src/include/parser/parse_node.h | 1 | 1 |
| src/include/parser/scanner.h | 9 | 5 |
| src/pl/plpgsql/src/gram.y | 105 | 105 |
| src/pl/plpgsql/src/pl_scanner.c | 6 | 6 |
diff --git a/contrib/pg_stat_statements/pg_stat_statements.c b/contrib/pg_stat_statements/pg_stat_statements.c
index 8dc3054..6e241c1 100644
--- a/contrib/pg_stat_statements/pg_stat_statements.c
+++ b/contrib/pg_stat_statements/pg_stat_statements.c
@@ -10,6 +10,13 @@
* an entry, one must hold the lock shared or exclusive (so the entry doesn't
* disappear!) and also take the entry's mutex spinlock.
*
+ * Statements go through a normalization process before being stored.
+ * Normalization is ignoring components of the query that don't normally
+ * make it significantly different. For example, the statements
+ * 'SELECT * FROM t WHERE f=1' and 'SELECT * FROM t WHERE f=2' would both
+ * be considered equivalent after normalization. This is implemented
+ * by generating a series of integers from the parsed query tree, into
+ * what's referred to as a query jumble here.
*
* Copyright (c) 2008-2011, PostgreSQL Global Development Group
*
@@ -27,12 +34,15 @@
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
+#include "optimizer/planner.h"
+#include "parser/parsetree.h"
#include "pgstat.h"
#include "storage/fd.h"
#include "storage/ipc.h"
#include "storage/spin.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
+#include "utils/memutils.h"
PG_MODULE_MAGIC;
@@ -48,6 +58,7 @@ static const uint32 PGSS_FILE_HEADER = 0x20100108;
#define USAGE_INIT (1.0) /* including initial planning */
#define USAGE_DECREASE_FACTOR (0.99) /* decreased every entry_dealloc */
#define USAGE_DEALLOC_PERCENT 5 /* free this % of entries at once */
+#define JUMBLE_SIZE 512 /* query serialization buffer size */
/*
* Hashtable key that defines the identity of a hashtable entry. The
@@ -63,8 +74,7 @@ typedef struct pgssHashKey
Oid userid; /* user OID */
Oid dbid; /* database OID */
int encoding; /* query encoding */
- int query_len; /* # of valid bytes in query string */
- const char *query_ptr; /* query string proper */
+ char parsed_jumble[JUMBLE_SIZE]; /* Integers from a query tree */
} pgssHashKey;
/*
@@ -95,6 +105,7 @@ typedef struct pgssEntry
{
pgssHashKey key; /* hash key of entry - MUST BE FIRST */
Counters counters; /* the statistics for this query */
+ int query_len; /* # of valid bytes in query string */
slock_t mutex; /* protects the counters only */
char query[1]; /* VARIABLE LENGTH ARRAY - MUST BE LAST */
/* Note: the allocated length of query[] is actually pgss->query_size */
@@ -109,7 +120,22 @@ typedef struct pgssSharedState
int query_size; /* max query length in bytes */
} pgssSharedState;
+typedef struct pgssTokenOffset
+{
+ int offset; /* Token offset in query string */
+ int len;
+} pgssTokenOffset;
+
/*---- Local variables ----*/
+/* Some integers jumbled from last query tree seen */
+static char *last_jumble = NULL;
+/*
+ * Array that represents where
+ * normalized characters will be
+ */
+static pgssTokenOffset *offsets = NULL;
+/* Current size of offsets array */
+static size_t offset_num = 0;
/* Current nesting depth of ExecutorRun calls */
static int nested_level = 0;
@@ -121,6 +147,7 @@ static ExecutorRun_hook_type prev_ExecutorRun = NULL;
static ExecutorFinish_hook_type prev_ExecutorFinish = NULL;
static ExecutorEnd_hook_type prev_ExecutorEnd = NULL;
static ProcessUtility_hook_type prev_ProcessUtility = NULL;
+static planner_hook_type prev_Planner = NULL;
/* Links to shared memory state */
static pgssSharedState *pgss = NULL;
@@ -148,7 +175,6 @@ static int pgss_track; /* tracking level */
static bool pgss_track_utility; /* whether to track utility commands */
static bool pgss_save; /* whether to save stats across shutdown */
-
#define pgss_enabled() \
(pgss_track == PGSS_TRACK_ALL || \
(pgss_track == PGSS_TRACK_TOP && nested_level == 0))
@@ -166,6 +192,16 @@ PG_FUNCTION_INFO_V1(pg_stat_statements);
static void pgss_shmem_startup(void);
static void pgss_shmem_shutdown(int code, Datum arg);
+static PlannedStmt *PluginPlanner(Query *parse, int cursorOptions, ParamListInfo boundParams);
+static int comp_offset(const void *a, const void *b);
+static void JumbleCurQuery(Query *parse);
+static bool AppendJumb(char* item, char jumble[], size_t size, int *i);
+static bool PerformJumble(const Query *parse, char jumble[], size_t size, int *i);
+static bool QualsNode(const OpExpr *node, char jumble[], size_t size, int *i, List *rtable);
+static bool SerLeafNodes(const Node *arg, char jumble[], size_t size, int *i, List *rtable);
+static bool LimitOffsetNode(const Node *node, char jumble[], size_t size, int *i, List *rtable);
+static bool JoinExprNode(JoinExpr *node, char jumble[], size_t size, int *i, List *rtable);
+static bool JoinExprNodeChild(const Node *node, char jumble[], size_t size, int *i, List *rtable);
static void pgss_ExecutorStart(QueryDesc *queryDesc, int eflags);
static void pgss_ExecutorRun(QueryDesc *queryDesc,
ScanDirection direction,
@@ -177,10 +213,10 @@ static void pgss_ProcessUtility(Node *parsetree,
DestReceiver *dest, char *completionTag);
static uint32 pgss_hash_fn(const void *key, Size keysize);
static int pgss_match_fn(const void *key1, const void *key2, Size keysize);
-static void pgss_store(const char *query, double total_time, uint64 rows,
+static void pgss_store(const char *query, char parsed_jumble[], double total_time, uint64 rows,
const BufferUsage *bufusage);
static Size pgss_memsize(void);
-static pgssEntry *entry_alloc(pgssHashKey *key);
+static pgssEntry *entry_alloc(pgssHashKey *key, const char* query, int new_query_len);
static void entry_dealloc(void);
static void entry_reset(void);
@@ -262,6 +298,14 @@ _PG_init(void)
RequestAddinShmemSpace(pgss_memsize());
RequestAddinLWLocks(1);
+ /* Allocate a buffer to store selective serialization of the query tree
+ * for the purposes of query normalization.
+ */
+ last_jumble = MemoryContextAlloc(TopMemoryContext, JUMBLE_SIZE);
+ /* Allocate space for bookkeeping information for query str normalization */
+ /* TODO: Use a more frugal memory allocation strategy than this */
+ offsets = MemoryContextAlloc(TopMemoryContext, JUMBLE_SIZE * sizeof(pgssTokenOffset));
+
/*
* Install hooks.
*/
@@ -277,6 +321,11 @@ _PG_init(void)
ExecutorEnd_hook = pgss_ExecutorEnd;
prev_ProcessUtility = ProcessUtility_hook;
ProcessUtility_hook = pgss_ProcessUtility;
+ /*
+ * Install hooks for query normalization
+ */
+ prev_Planner = planner_hook;
+ planner_hook = PluginPlanner;
}
/*
@@ -292,6 +341,10 @@ _PG_fini(void)
ExecutorFinish_hook = prev_ExecutorFinish;
ExecutorEnd_hook = prev_ExecutorEnd;
ProcessUtility_hook = prev_ProcessUtility;
+ prev_Planner = planner_hook;
+
+ pfree(last_jumble);
+ pfree(offsets);
}
/*
@@ -300,7 +353,7 @@ _PG_fini(void)
*/
static void
pgss_shmem_startup(void)
-{
+{
bool found;
HASHCTL info;
FILE *file;
@@ -395,27 +448,28 @@ pgss_shmem_startup(void)
if (!PG_VALID_BE_ENCODING(temp.key.encoding))
goto error;
+
/* Previous incarnation might have had a larger query_size */
- if (temp.key.query_len >= buffer_size)
+ if (temp.query_len >= buffer_size)
{
- buffer = (char *) repalloc(buffer, temp.key.query_len + 1);
- buffer_size = temp.key.query_len + 1;
+ buffer = (char *) repalloc(buffer, temp.query_len + 1);
+ buffer_size = temp.query_len + 1;
}
- if (fread(buffer, 1, temp.key.query_len, file) != temp.key.query_len)
+ if (fread(buffer, 1, temp.query_len, file) != temp.query_len)
goto error;
- buffer[temp.key.query_len] = '\0';
+ buffer[temp.query_len] = '\0';
+
/* Clip to available length if needed */
- if (temp.key.query_len >= query_size)
- temp.key.query_len = pg_encoding_mbcliplen(temp.key.encoding,
+ if (temp.query_len >= query_size)
+ temp.query_len = pg_encoding_mbcliplen(temp.key.encoding,
buffer,
- temp.key.query_len,
+ temp.query_len,
query_size - 1);
- temp.key.query_ptr = buffer;
/* make the hashtable entry (discards old entries if too many) */
- entry = entry_alloc(&temp.key);
+ entry = entry_alloc(&temp.key, buffer, temp.query_len);
/* copy in the actual stats */
entry->counters = temp.counters;
@@ -477,7 +531,7 @@ pgss_shmem_shutdown(int code, Datum arg)
hash_seq_init(&hash_seq, pgss_hash);
while ((entry = hash_seq_search(&hash_seq)) != NULL)
{
- int len = entry->key.query_len;
+ int len = entry->query_len;
if (fwrite(entry, offsetof(pgssEntry, mutex), 1, file) != 1 ||
fwrite(entry->query, 1, len, file) != len)
@@ -500,6 +554,768 @@ error:
if (file)
FreeFile(file);
unlink(PGSS_DUMP_FILE);
+
+}
+
+/*
+ * PluginPlanner: Selectively serialize the query tree for the purposes of
+ * query normalization.
+ */
+PlannedStmt *
+PluginPlanner(Query *parse, int cursorOptions, ParamListInfo boundParams)
+{
+ JumbleCurQuery(parse);
+ /* Invoke the planner */
+ if (prev_Planner)
+ return prev_Planner(parse, cursorOptions, boundParams);
+ else
+ return standard_planner(parse, cursorOptions, boundParams);
+}
+
+static int comp_offset(const void *a, const void *b)
+{
+ int l = ((pgssTokenOffset*) a)->offset;
+ int r = ((pgssTokenOffset*) b)->offset;
+ if (l < r)
+ return -1;
+ else if (l > r)
+ return +1;
+ else
+ return 0;
+}
+
+/*
+ * JumbleCurQuery: Selectively serialize query tree, and store it until
+ * needed to hash the current query
+ */
+static void JumbleCurQuery(Query *parse)
+{
+ int i = 0;
+ offset_num = 0;
+ memset(last_jumble, 0, JUMBLE_SIZE);
+ PerformJumble(parse, last_jumble, JUMBLE_SIZE, &i);
+ /* Sort offsets for query string normalization */
+ qsort(offsets, offset_num, sizeof(pgssTokenOffset), comp_offset);
+}
+
+/*
+ * AppendJumb: Append a given value that is substantive to a given
+ * query to jumble, while incrementing the iterator. If we've run
+ * out of space in the buffer, simply give up
+ */
+static bool AppendJumb(char* item, char jumble[], size_t size, int *i)
+{
+ if (size + *i >= JUMBLE_SIZE)
+ return false;
+ memcpy(jumble + *i, item, size);
+ *i += size;
+
+ return true;
+}
+
+/*
+ * Wrapper around AppendJumb to encapsulate details of serialization
+ * of individual elements.
+ */
+#define APP_JUMB(item) \
+if (!AppendJumb((char*)&item, jumble, sizeof(item), i))\
+ return false;
+
+/*
+ * Simple wrappers around functions so that they return upon reaching
+ * end of buffer
+ */
+
+
+#define DoPerformJumble(item, jumble, size, i) \
+if (!PerformJumble(item, jumble, size, i)) \
+ return false;\
+
+#define DoQualsNode(item, jumble, size, i, rtable) \
+if (!QualsNode(item, jumble, size, i, rtable)) \
+ return false;\
+
+#define DoSerLeafNodes(item, jumble, size, i, rtable) \
+if (!SerLeafNodes(item, jumble, size, i, rtable)) \
+ return false;\
+
+#define DoLimitOffsetNode(item, jumble, size, i, rtable) \
+if (!LimitOffsetNode(item, jumble, size, i, rtable)) \
+ return false;\
+
+#define DoJoinExprNode(item, jumble, size, i, rtable) \
+if (!JoinExprNode(item, jumble, size, i, rtable)) \
+ return false;\
+
+#define DoJoinExprNodeChild(item, jumble, size, i, rtable) \
+if (!JoinExprNodeChild(item, jumble, size, i, rtable)) \
+ return false;\
+
+/*
+ * PerformJumble: Serialize the query tree "parse" such that it
+ * is usefully normalized, excluding constants that are not
+ * essential to the query itself.
+ *
+ * A guiding principal as to whether two queries should
+ * be considered equivalent is whether whatever difference
+ * exists between the two queries could be expected to result
+ * in two different plans. A non-obvious example of such a
+ * differentiator is a change in the "limit" constant.
+ *
+ * The resulting "jumble" can be hashed to uniquely identify
+ * a query that may use different constants in successive calls.
+ */
+static bool PerformJumble(const Query *parse, char jumble[], size_t size, int *i)
+{
+ ListCell *l;
+ FromExpr* jt = (FromExpr *) parse->jointree; /* table join tree (FROM and WHERE clauses) */
+ FuncExpr *off = (FuncExpr *) parse->limitOffset; /* # of result tuples to skip (int8 expr) */
+ FuncExpr *limcount = (FuncExpr *) parse->limitCount; /* # of result tuples to skip (int8 expr) */
+
+ APP_JUMB(parse->resultRelation);
+ if (parse->utilityStmt)
+ {
+ /*
+ * non-null if this is DECLARE CURSOR
+ * or a non-optimizable statement
+ */
+
+ /* TODO: Serialize utilityStmt */
+ }
+
+ if (parse->intoClause)
+ {
+ IntoClause *ic = parse->intoClause;
+ APP_JUMB(ic->onCommit)
+ /* TODO: Serialize more from intoClause */
+ }
+
+ /* WITH list (of CommonTableExpr's) */
+ foreach(l, parse->cteList)
+ {
+ CommonTableExpr *cte = (CommonTableExpr *) lfirst(l);
+ Query *cte_query = (Query*) cte->ctequery;
+ if (cte_query)
+ DoPerformJumble(cte_query, jumble, size, i);
+ }
+ if (jt)
+ {
+ if (jt->quals)
+ {
+ if (IsA(jt->quals, OpExpr))
+ {
+ DoQualsNode((OpExpr*) jt->quals, jumble, size, i, parse->rtable);
+ }
+ else
+ {
+ DoSerLeafNodes((Node*) jt->quals, jumble, size, i, parse->rtable);
+ }
+ }
+ /* table join tree */
+ foreach(l, jt->fromlist)
+ {
+ Node* fr = lfirst(l);
+ if (IsA(fr, JoinExpr))
+ {
+ DoJoinExprNode((JoinExpr*) fr, jumble, size, i, parse->rtable);
+ }
+ else if (IsA(fr, RangeTblRef))
+ {
+ RangeTblRef *rtf = (RangeTblRef *) fr;
+ RangeTblEntry *rte = rt_fetch(rtf->rtindex, parse->rtable);
+ APP_JUMB(rte->relid);
+ APP_JUMB(rte->rtekind);
+ /* Subselection in where clause */
+ if (rte->subquery)
+ DoPerformJumble(rte->subquery, jumble, size, i);
+
+ /* Function call in where clause */
+ if (rte->funcexpr)
+ DoSerLeafNodes((Node*) rte->funcexpr, jumble, size, i, parse->rtable);
+ }
+ else
+ {
+ elog(ERROR, "unrecognized fromlist node type: %d",
+ (int) nodeTag(fr));
+ }
+ }
+ }
+ /*
+ * target list (of TargetEntry)
+ * columns returned by query
+ */
+ foreach(l, parse->targetList)
+ {
+ TargetEntry *tg = (TargetEntry *) lfirst(l);
+ Node *e = (Node*) tg->expr;
+ if (tg->ressortgroupref)
+ APP_JUMB(tg->ressortgroupref); /* nonzero if referenced by a sort/group - for ORDER BY */
+ APP_JUMB(tg->resno); /* column number for select */
+ /* Handle the various types of nodes in
+ * the select list of this query
+ */
+ DoSerLeafNodes(e, jumble, size, i, parse->rtable);
+ }
+ /* return-values list (of TargetEntry) */
+ foreach(l, parse->returningList)
+ {
+ TargetEntry *rt = (TargetEntry *) lfirst(l);
+ Expr *e = (Expr*) rt->expr;
+ /*
+ * Handle the various types of nodes in
+ * the select list of this query
+ */
+ if (IsA(e, Var)) /* table column */
+ {
+ Var *v = (Var*) e;
+ RangeTblEntry *rte = rt_fetch(v->varno, parse->rtable);
+ APP_JUMB(rte->relid);
+ APP_JUMB(v->varattno);
+ }
+ else
+ {
+ elog(ERROR, "unrecognized node type for returnlist node: %d",
+ (int) nodeTag(e));
+ }
+ }
+ /* a list of SortGroupClause's */
+ foreach(l, parse->groupClause)
+ {
+ SortGroupClause *gc = (SortGroupClause *) lfirst(l);
+ APP_JUMB(gc->tleSortGroupRef);
+ APP_JUMB(gc->nulls_first);
+ }
+
+ if (parse->havingQual)
+ {
+ if (IsA(parse->havingQual, OpExpr))
+ {
+ OpExpr *na = (OpExpr *) parse->havingQual;
+ DoQualsNode(na, jumble, size, i, parse->rtable);
+ }
+ else
+ {
+ elog(ERROR, "unrecognized node type for havingclause node: %d",
+ (int) nodeTag(parse->havingQual));
+ }
+ }
+ foreach(l, parse->windowClause)
+ {
+ WindowClause *wc = (WindowClause *) lfirst(l);
+ ListCell *il;
+ APP_JUMB(wc->frameOptions);
+ foreach(il, wc->partitionClause) /* PARTITION BY list */
+ {
+ Node *n = (Node *) lfirst(il);
+ DoSerLeafNodes(n, jumble, size, i, parse->rtable);
+ }
+ foreach(il, wc->orderClause) /* ORDER BY list */
+ {
+ Node *n = (Node *) lfirst(il);
+ DoSerLeafNodes(n, jumble, size, i, parse->rtable);
+ }
+ }
+
+ foreach(l, parse->distinctClause)
+ {
+ SortGroupClause *dc = (SortGroupClause *) lfirst(l);
+ APP_JUMB(dc->tleSortGroupRef);
+ APP_JUMB(dc->nulls_first);
+ }
+
+ /* Don't look at parse->sortClause,
+ * because the value ressortgroupref is already
+ * serialized when we iterate through targetList
+ */
+
+ if (off)
+ DoLimitOffsetNode((Node*) off, jumble, size, i, parse->rtable);
+
+ if (limcount)
+ DoLimitOffsetNode((Node*) limcount, jumble, size, i, parse->rtable);
+
+ foreach(l, parse->rowMarks)
+ {
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+ APP_JUMB(rc->rti); /* range table index of target relation */
+ APP_JUMB(rc->forUpdate); /* true = FOR UPDATE, false = FOR SHARE */
+ APP_JUMB(rc->noWait); /* NOWAIT option */
+ APP_JUMB(rc->pushedDown); /* pushed down from higher query level? */
+ }
+
+ if (parse->setOperations)
+ {
+ /*
+ * set-operation tree if this is top
+ * level of a UNION/INTERSECT/EXCEPT query
+ */
+ SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations;
+ APP_JUMB(topop->op);
+ APP_JUMB(topop->all);
+
+ /* leaf selects are RTE subselections */
+ foreach(l, parse->rtable)
+ {
+ RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
+ if (rte->subquery)
+ DoPerformJumble(rte->subquery, jumble, size, i);
+ }
+ }
+ return true;
+}
+
+/*
+ * Perform selective serialization of "Quals" nodes when
+ * they're IsA(*, OpExpr)
+ */
+static bool QualsNode(const OpExpr *node, char jumble[], size_t size, int *i, List *rtable)
+{
+ ListCell *l;
+ APP_JUMB(node->opno);
+ foreach(l, node->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ return true;
+}
+
+/*
+ * SerLeafNodes: Serialize a selection of parser/prim nodes that are frequently,
+ * though certainly not necesssarily leaf nodes, such as Variables (columns),
+ * constants and function calls
+ */
+static bool SerLeafNodes(const Node *arg, char jumble[], size_t size, int *i, List *rtable)
+{
+ ListCell *l;
+ if (IsA(arg, Const))
+ {
+ /*
+ * Serialize generic magic value to
+ * normalize constants
+ */
+ char magic = 0xC0;
+ Const *c = (Const *) arg;
+ APP_JUMB(magic);
+ /* Datatype of the constant is a
+ * differentiator
+ */
+ APP_JUMB(c->consttype);
+ /* Some Const nodes naturally don't have a location.
+ * Also, views that have constants in their
+ * definitions will have a tok_len of 0
+ */
+ elog(DEBUG1, " (Consttype %d) c->location: %d, c->tok_len: %d",c->consttype, c->location, c->tok_len);
+ if (c->location > 0 && c->tok_len > 0)
+ {
+ offsets[offset_num].offset = c->location;
+ offsets[offset_num].len = c->tok_len;
+ /* should be added in the same order that as query string */
+ offset_num++;
+ }
+ }
+ else if (IsA(arg, Var))
+ {
+ char magic = 0xFA;
+ Var *v = (Var *) arg;
+ RangeTblEntry *rte = rt_fetch(v->varno, rtable);
+ APP_JUMB(magic);
+ APP_JUMB(rte->relid);
+ APP_JUMB(v->varattno); /* column number of table */
+ }
+ else if (IsA(arg, Param))
+ {
+ Param *p = ((Param *) arg);
+ APP_JUMB(p->paramkind);
+ APP_JUMB(p->paramid);
+ }
+ else if (IsA(arg, RelabelType))
+ {
+ APP_JUMB(((RelabelType *) arg)->resulttype);
+ }
+ else if (IsA(arg, WindowFunc))
+ {
+ WindowFunc *wf = (WindowFunc *) arg;
+ APP_JUMB(wf->winfnoid);
+ foreach(l, wf->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, FuncExpr))
+ {
+ FuncExpr *f = (FuncExpr *) arg;
+ APP_JUMB(f->funcid);
+ foreach(l, f->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, OpExpr))
+ {
+ DoQualsNode((OpExpr*) arg, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, CoerceViaIO))
+ {
+ APP_JUMB(((CoerceViaIO*) arg)->coerceformat);
+ APP_JUMB(((CoerceViaIO*) arg)->resulttype);
+ }
+ else if (IsA(arg, Aggref))
+ {
+ Aggref *a = (Aggref *) arg;
+ APP_JUMB(a->aggfnoid);
+ foreach(l, a->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, SubLink))
+ {
+ SubLink *s = (SubLink*) arg;
+ APP_JUMB(s->subLinkType);
+ /* Serialize select-list subselect recursively */
+ if (s->subselect)
+ DoPerformJumble( (Query*) s->subselect, jumble, size, i);
+ }
+ else if (IsA(arg, TargetEntry))
+ {
+ TargetEntry *rt = (TargetEntry *) arg;
+ Node *e = (Node*) rt->expr;
+ APP_JUMB(rt->resorigtbl); /* OID of column's source table */
+ APP_JUMB(rt->ressortgroupref); /* nonzero if referenced by a sort/group - for ORDER BY */
+ DoSerLeafNodes(e, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, BoolExpr))
+ {
+ BoolExpr *be = (BoolExpr *) arg;
+ APP_JUMB(be->boolop);
+ foreach(l, be->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, NullTest))
+ {
+ NullTest *nt = (NullTest *) arg;
+ Node *arg = (Node *) nt->arg;
+ APP_JUMB(nt->nulltesttype); /* IS NULL, IS NOT NULL */
+ APP_JUMB(nt->argisrow); /* is input a composite type ? */
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, ArrayExpr))
+ {
+ ArrayExpr *ae = (ArrayExpr *) arg;
+ APP_JUMB(ae->array_typeid); /* type of expression result */
+ APP_JUMB(ae->element_typeid); /* common type of array elements */
+ foreach(l, ae->elements)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, CaseExpr))
+ {
+ CaseExpr *ce = (CaseExpr*) arg;
+ Assert(ce->casetype != InvalidOid);
+ APP_JUMB(ce->casetype);
+ foreach(l, ce->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ if (ce->arg)
+ DoSerLeafNodes((Node*) ce->arg, jumble, size, i, rtable);
+
+ if (ce->defresult)
+ {
+ /* Default result (ELSE clause)
+ * The ptr may be NULL, because no else clause
+ * was actually specified, and thus the value is
+ * equivalent to SQL ELSE NULL
+ */
+ DoSerLeafNodes((Node*) ce->defresult, jumble, size, i, rtable); /* the default result (ELSE clause) */
+ }
+ }
+ else if (IsA(arg, CaseTestExpr))
+ {
+ CaseTestExpr *ct = (CaseTestExpr*) arg;
+ APP_JUMB(ct->typeId);
+ }
+ else if (IsA(arg, CaseWhen))
+ {
+ CaseWhen *cw = (CaseWhen*) arg;
+ Node *res = (Node*) cw->result;
+ Node *exp = (Node*) cw->expr;
+ if (res)
+ DoSerLeafNodes(res, jumble, size, i, rtable);
+ if (exp)
+ DoSerLeafNodes(exp, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, MinMaxExpr))
+ {
+ MinMaxExpr *cw = (MinMaxExpr*) arg;
+ APP_JUMB(cw->minmaxtype);
+ APP_JUMB(cw->op);
+ foreach(l, cw->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, ScalarArrayOpExpr))
+ {
+ ScalarArrayOpExpr *sa = (ScalarArrayOpExpr*) arg;
+ APP_JUMB(sa->opfuncid);
+ APP_JUMB(sa->useOr);
+ foreach(l, sa->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, CoalesceExpr))
+ {
+ CoalesceExpr *ca = (CoalesceExpr*) arg;
+ foreach(l, ca->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, ArrayCoerceExpr))
+ {
+ ArrayCoerceExpr *ac = (ArrayCoerceExpr *) arg;
+ DoSerLeafNodes((Node*) ac->arg, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, WindowClause))
+ {
+ WindowClause *wc = (WindowClause*) arg;
+ foreach(l, wc->partitionClause)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ foreach(l, wc->orderClause)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, SortGroupClause))
+ {
+ SortGroupClause *sgc = (SortGroupClause*) arg;
+ APP_JUMB(sgc->tleSortGroupRef);
+ APP_JUMB(sgc->nulls_first);
+ }
+ else if (IsA(arg, Integer) ||
+ IsA(arg, Float) ||
+ IsA(arg, String) ||
+ IsA(arg, BitString) ||
+ IsA(arg, Null)
+ )
+ {
+ /* It is not necessary to
+ * serialize integral values
+ */
+ }
+ else if (IsA(arg, BooleanTest))
+ {
+ BooleanTest *bt = (BooleanTest *) arg;
+ APP_JUMB(bt->booltesttype);
+ DoSerLeafNodes((Node*) bt->arg, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, ArrayRef))
+ {
+ ArrayRef *ar = (ArrayRef*) arg;
+ APP_JUMB(ar->refarraytype);
+ foreach(l, ar->refupperindexpr)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ foreach(l, ar->reflowerindexpr)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, NullIfExpr))
+ {
+ /* NullIfExpr is just a typedef for OpExpr */
+ DoQualsNode((OpExpr*) arg, jumble, size, i, rtable);
+ }
+ else if (IsA(arg, RowExpr))
+ {
+ RowExpr *re = (RowExpr*) arg;
+ APP_JUMB(re->row_format);
+ foreach(l, re->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+
+ }
+ else if (IsA(arg, XmlExpr))
+ {
+ XmlExpr *xml = (XmlExpr*) arg;
+ APP_JUMB(xml->op);
+ foreach(l, xml->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ foreach(l, xml->named_args) /* non-XML expressions for xml_attributes */
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ foreach(l, xml->arg_names) /* parallel list of Value strings */
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(arg, RowCompareExpr))
+ {
+ RowCompareExpr *rc = (RowCompareExpr*) arg;
+ foreach(l, rc->largs)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ foreach(l, rc->rargs)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else
+ {
+ elog(ERROR, "unrecognized node type for SerLeafNodes node: %d",
+ (int) nodeTag(arg));
+ }
+ return true;
+}
+
+/*
+ * Perform selective serialization of limit or offset nodes
+ */
+static bool LimitOffsetNode(const Node *node, char jumble[], size_t size, int *i, List *rtable)
+{
+ ListCell *l;
+ if (IsA(node, FuncExpr))
+ {
+ foreach(l, ((FuncExpr*) node)->args)
+ {
+ Node *arg = (Node *) lfirst(l);
+ if (IsA(arg, Const))
+ {
+ /*
+ * A different limit and/or offset constitutes a different
+ * query, so this is one constant that we actually want to
+ * hash
+ */
+ Datum constvalue = ((Const*) arg)->constvalue;
+ int64 val = DatumGetInt64(constvalue);
+ APP_JUMB(val);
+ }
+ else
+ {
+ elog(ERROR, "unrecognized node type for FuncExpr limit/offset node: %d",
+ (int) nodeTag(arg));
+ }
+ }
+ }
+ else if (IsA(node, Const))
+ {
+ /* This should be a differentiator, as it results in the addition of a limit node */
+ char magic = 0xEA;
+ APP_JUMB(magic);
+ return true;
+ }
+ else
+ {
+ /* Fall back on leaf node representation */
+ DoSerLeafNodes(node, jumble, size, i, rtable);
+ }
+ return true;
+}
+
+/*
+ * Perform selective serialization of JoinExpr nodes
+ */
+static bool JoinExprNode(JoinExpr *node, char jumble[], size_t size, int *i, List *rtable)
+{
+ Node *larg = node->larg; /* left subtree */
+ Node *rarg = node->rarg; /* right subtree */
+ ListCell *l;
+
+ Assert( IsA(node, JoinExpr));
+
+ APP_JUMB(node->jointype);
+ APP_JUMB(node->isNatural);
+
+ if (node->quals)
+ {
+ if ( IsA(node, OpExpr))
+ {
+ DoQualsNode((OpExpr*) node->quals, jumble, size, i, rtable);
+ }
+ else
+ {
+ DoSerLeafNodes((Node*) node->quals, jumble, size, i, rtable);
+ }
+
+ }
+ foreach(l, node->usingClause) /* USING clause, if any (list of String) */
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ if (larg)
+ DoJoinExprNodeChild(larg, jumble, size, i, rtable);
+ if (rarg)
+ DoJoinExprNodeChild(rarg, jumble, size, i, rtable);
+
+ return true;
+}
+
+/*
+ * Serialize children of the JoinExpr node
+ */
+static bool JoinExprNodeChild(const Node *node, char jumble[], size_t size, int *i, List *rtable)
+{
+ if (IsA(node, RangeTblRef))
+ {
+ RangeTblRef *rt = (RangeTblRef*) node;
+ RangeTblEntry *rte = rt_fetch(rt->rtindex, rtable);
+ ListCell *l;
+
+ APP_JUMB(rte->relid);
+ APP_JUMB(rte->jointype);
+
+ if (rte->subquery)
+ DoPerformJumble(rte->subquery, jumble, size, i);
+
+ foreach(l, rte->joinaliasvars)
+ {
+ Node *arg = (Node *) lfirst(l);
+ DoSerLeafNodes(arg, jumble, size, i, rtable);
+ }
+ }
+ else if (IsA(node, JoinExpr))
+ {
+ DoJoinExprNode((JoinExpr*) node, jumble, size, i, rtable);
+ }
+ else
+ {
+ DoSerLeafNodes(node, jumble, size, i, rtable);
+ }
+ return true;
}
/*
@@ -592,6 +1408,7 @@ pgss_ExecutorEnd(QueryDesc *queryDesc)
InstrEndLoop(queryDesc->totaltime);
pgss_store(queryDesc->sourceText,
+ last_jumble,
queryDesc->totaltime->total,
queryDesc->estate->es_processed,
&queryDesc->totaltime->bufusage);
@@ -665,7 +1482,8 @@ pgss_ProcessUtility(Node *parsetree, const char *queryString,
bufusage.temp_blks_written =
pgBufferUsage.temp_blks_written - bufusage.temp_blks_written;
- pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows,
+ memset(last_jumble, 0, JUMBLE_SIZE); /* Utility statements are all equivalent */
+ pgss_store(queryString, last_jumble, INSTR_TIME_GET_DOUBLE(duration), rows,
&bufusage);
}
else
@@ -690,8 +1508,7 @@ pgss_hash_fn(const void *key, Size keysize)
/* we don't bother to include encoding in the hash */
return hash_uint32((uint32) k->userid) ^
hash_uint32((uint32) k->dbid) ^
- DatumGetUInt32(hash_any((const unsigned char *) k->query_ptr,
- k->query_len));
+ DatumGetUInt32(hash_any((const unsigned char* ) k->parsed_jumble, JUMBLE_SIZE) );
}
/*
@@ -706,8 +1523,7 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
if (k1->userid == k2->userid &&
k1->dbid == k2->dbid &&
k1->encoding == k2->encoding &&
- k1->query_len == k2->query_len &&
- memcmp(k1->query_ptr, k2->query_ptr, k1->query_len) == 0)
+ memcmp(k1->parsed_jumble, k2->parsed_jumble, JUMBLE_SIZE) == 0)
return 0;
else
return 1;
@@ -717,12 +1533,13 @@ pgss_match_fn(const void *key1, const void *key2, Size keysize)
* Store some statistics for a statement.
*/
static void
-pgss_store(const char *query, double total_time, uint64 rows,
+pgss_store(const char *query, char parsed_jumble[], double total_time, uint64 rows,
const BufferUsage *bufusage)
{
pgssHashKey key;
double usage;
pgssEntry *entry;
+ int new_query_len = strlen(query);
Assert(query != NULL);
@@ -734,14 +1551,13 @@ pgss_store(const char *query, double total_time, uint64 rows,
key.userid = GetUserId();
key.dbid = MyDatabaseId;
key.encoding = GetDatabaseEncoding();
- key.query_len = strlen(query);
- if (key.query_len >= pgss->query_size)
- key.query_len = pg_encoding_mbcliplen(key.encoding,
+ memcpy(key.parsed_jumble, parsed_jumble, JUMBLE_SIZE);
+
+ if (new_query_len >= pgss->query_size)
+ new_query_len = pg_encoding_mbcliplen(key.encoding,
query,
- key.query_len,
+ new_query_len,
pgss->query_size - 1);
- key.query_ptr = query;
-
usage = USAGE_EXEC(duration);
/* Lookup the hash table entry with shared lock. */
@@ -750,10 +1566,71 @@ pgss_store(const char *query, double total_time, uint64 rows,
entry = (pgssEntry *) hash_search(pgss_hash, &key, HASH_FIND, NULL);
if (!entry)
{
- /* Must acquire exclusive lock to add a new entry. */
- LWLockRelease(pgss->lock);
- LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
- entry = entry_alloc(&key);
+ /*
+ * It is necessary to generate a normalized version
+ * of the query string that will be used for this query.
+ *
+ * Note that the representation seen by the user will
+ * only have non-differentiating Const tokens swapped
+ * with '?' characters, and does not for example take
+ * account of the fact that alias names could vary
+ * between successive calls of what we regard as the
+ * same query.
+ */
+ if (offset_num > 0)
+ {
+ int i,
+ last_off = 0,
+ quer_it = 0,
+ n_quer_it = 0,
+ off = 0,
+ tok_len = 0,
+ len_to_wrt = 0,
+ last_tok_len = 0;
+ char *norm_query = palloc0(new_query_len + 1);
+ for(i = 0; i < offset_num; i++)
+ {
+ off = offsets[i].offset;
+ tok_len = offsets[i].len;
+ len_to_wrt = off - last_off;
+ len_to_wrt -= last_tok_len;
+ /*
+ * Copy everything prior to the current offset/token to be
+ * replaced, except previously copied things
+ */
+
+ if (off + tok_len > new_query_len)
+ break;
+ memcpy(norm_query + n_quer_it, query + quer_it, len_to_wrt);
+ n_quer_it += len_to_wrt;
+ norm_query[n_quer_it++] = '?';
+ quer_it += len_to_wrt + tok_len;
+ last_off = off;
+ last_tok_len = tok_len;
+ }
+ /* Finish off last bit of query string */
+ memcpy(norm_query + n_quer_it, query + (off + tok_len),
+ Min( strlen(query) - (off + tok_len ),
+ new_query_len - n_quer_it ) );
+ elog(DEBUG1, "norm_query: '%s', orig query: '%s'", norm_query, query);
+ /*
+ * Must acquire exclusive lock to add a new entry.
+ * Leave that until as late as possible.
+ */
+ LWLockRelease(pgss->lock);
+ LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
+
+ entry = entry_alloc(&key, norm_query, strlen(norm_query));
+ pfree(norm_query);
+ }
+ else
+ {
+ /* Acquire exclusive lock as required by entry_alloc() */
+ LWLockRelease(pgss->lock);
+ LWLockAcquire(pgss->lock, LW_EXCLUSIVE);
+
+ entry = entry_alloc(&key, query, new_query_len);
+ }
}
/* Grab the spinlock while updating the counters. */
@@ -775,7 +1652,6 @@ pgss_store(const char *query, double total_time, uint64 rows,
e->counters.usage += usage;
SpinLockRelease(&e->mutex);
}
-
LWLockRelease(pgss->lock);
}
@@ -857,13 +1733,22 @@ pg_stat_statements(PG_FUNCTION_ARGS)
values[i++] = ObjectIdGetDatum(entry->key.userid);
values[i++] = ObjectIdGetDatum(entry->key.dbid);
+ /* copy counters to a local variable to keep locking time short */
+ {
+ volatile pgssEntry *e = (volatile pgssEntry *) entry;
+
+ SpinLockAcquire(&e->mutex);
+ tmp = e->counters;
+ SpinLockRelease(&e->mutex);
+ }
+
if (is_superuser || entry->key.userid == userid)
{
char *qstr;
qstr = (char *)
pg_do_encoding_conversion((unsigned char *) entry->query,
- entry->key.query_len,
+ entry->query_len,
entry->key.encoding,
GetDatabaseEncoding());
values[i++] = CStringGetTextDatum(qstr);
@@ -873,15 +1758,6 @@ pg_stat_statements(PG_FUNCTION_ARGS)
else
values[i++] = CStringGetTextDatum("<insufficient privilege>");
- /* copy counters to a local variable to keep locking time short */
- {
- volatile pgssEntry *e = (volatile pgssEntry *) entry;
-
- SpinLockAcquire(&e->mutex);
- tmp = e->counters;
- SpinLockRelease(&e->mutex);
- }
-
values[i++] = Int64GetDatumFast(tmp.calls);
values[i++] = Float8GetDatumFast(tmp.total_time);
values[i++] = Int64GetDatumFast(tmp.rows);
@@ -933,14 +1809,11 @@ pgss_memsize(void)
* have made the entry while we waited to get exclusive lock.
*/
static pgssEntry *
-entry_alloc(pgssHashKey *key)
+entry_alloc(pgssHashKey *key, const char* query, int new_query_len)
{
pgssEntry *entry;
bool found;
- /* Caller must have clipped query properly */
- Assert(key->query_len < pgss->query_size);
-
/* Make space if needed */
while (hash_get_num_entries(pgss_hash) >= pgss_max)
entry_dealloc();
@@ -950,19 +1823,23 @@ entry_alloc(pgssHashKey *key)
if (!found)
{
+ entry->query_len = new_query_len;
+ Assert(entry->query_len > 0);
/* New entry, initialize it */
- /* dynahash tried to copy the key for us, but must fix query_ptr */
- entry->key.query_ptr = entry->query;
/* reset the statistics */
memset(&entry->counters, 0, sizeof(Counters));
entry->counters.usage = USAGE_INIT;
/* re-initialize the mutex each time ... we assume no one using it */
SpinLockInit(&entry->mutex);
/* ... and don't forget the query text */
- memcpy(entry->query, key->query_ptr, key->query_len);
- entry->query[key->query_len] = '\0';
+ /* memset previous entry in the slot */
+ memset(entry->query, 0, pgss->query_size);
+ memcpy(entry->query, query, entry->query_len);
+ entry->query[entry->query_len] = '\0';
}
+ /* Caller must have clipped query properly */
+ Assert(entry->query_len < pgss->query_size);
return entry;
}
@@ -971,7 +1848,7 @@ entry_alloc(pgssHashKey *key)
* qsort comparator for sorting into increasing usage order
*/
static int
-entry_cmp(const void *lhs, const void *rhs)
+entry_cmp_usage(const void *lhs, const void *rhs)
{
double l_usage = (*(pgssEntry * const *) lhs)->counters.usage;
double r_usage = (*(pgssEntry * const *) rhs)->counters.usage;
@@ -1009,7 +1886,7 @@ entry_dealloc(void)
entry->counters.usage *= USAGE_DECREASE_FACTOR;
}
- qsort(entries, i, sizeof(pgssEntry *), entry_cmp);
+ qsort(entries, i, sizeof(pgssEntry *), entry_cmp_usage);
nvictims = Max(10, i * USAGE_DEALLOC_PERCENT / 100);
nvictims = Min(nvictims, i);
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index e11d896..ccd92d3 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2441,7 +2441,7 @@ cookDefault(ParseState *pstate,
atttypid, atttypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index a949215..e80d57f 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -365,7 +365,7 @@ EvaluateParams(PreparedStatement *pstmt, List *params,
expected_type_id, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (expr == NULL)
ereport(ERROR,
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c4622c0..342e168 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4464,7 +4464,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
typmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (defval == NULL) /* should not happen */
elog(ERROR, "failed to coerce base type to domain");
}
@@ -6958,7 +6958,7 @@ ATPrepAlterColumnType(List **wqueue,
targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (transform == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -7125,7 +7125,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
targettype, targettypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (defaultexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 63958c3..c372f20 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2129,6 +2129,7 @@ _copyAConst(A_Const *from)
}
COPY_LOCATION_FIELD(location);
+ COPY_LOCATION_FIELD(tok_len);
return newnode;
}
@@ -2283,6 +2284,7 @@ _copyTypeCast(TypeCast *from)
COPY_NODE_FIELD(arg);
COPY_NODE_FIELD(typeName);
COPY_LOCATION_FIELD(location);
+ COPY_LOCATION_FIELD(tok_len);
return newnode;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index c135465..2a3118d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -65,7 +65,6 @@
#include "utils/numeric.h"
#include "utils/xml.h"
-
/* Location tracking support --- simpler than bison's default */
#define YYLLOC_DEFAULT(Current, Rhs, N) \
do { \
@@ -109,15 +108,15 @@ static void base_yyerror(YYLTYPE *yylloc, core_yyscan_t yyscanner,
const char *msg);
static Node *makeColumnRef(char *colname, List *indirection,
int location, core_yyscan_t yyscanner);
-static Node *makeTypeCast(Node *arg, TypeName *typename, int location);
-static Node *makeStringConst(char *str, int location);
-static Node *makeStringConstCast(char *str, int location, TypeName *typename);
-static Node *makeIntConst(int val, int location);
-static Node *makeFloatConst(char *str, int location);
-static Node *makeBitStringConst(char *str, int location);
-static Node *makeNullAConst(int location);
-static Node *makeAConst(Value *v, int location);
-static Node *makeBoolAConst(bool state, int location);
+static Node *makeTypeCast(Node *arg, TypeName *typename, int location, int length);
+static Node *makeStringConst(char *str, int location, int length);
+static Node *makeStringConstCast(char *str, int location, int length, TypeName *typename);
+static Node *makeIntConst(int val, int location, int length);
+static Node *makeFloatConst(char *str, int location, int length);
+static Node *makeBitStringConst(char *str, int location, int length);
+static Node *makeNullAConst(int location, int length);
+static Node *makeAConst(Value *v, int location, int length);
+static Node *makeBoolAConst(bool state, int location, int length);
static FuncCall *makeOverlaps(List *largs, List *rargs,
int location, core_yyscan_t yyscanner);
static void check_qualified_name(List *names, core_yyscan_t yyscanner);
@@ -131,7 +130,7 @@ static void insertSelectOptions(SelectStmt *stmt,
WithClause *withClause,
core_yyscan_t yyscanner);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
-static Node *doNegate(Node *n, int location);
+static Node *doNegate(Node *n, int location, int length);
static void doNegateFloat(Value *v);
static Node *makeAArrayExpr(List *elements, int location);
static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
@@ -913,7 +912,7 @@ AlterOptRoleElem:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("unrecognized role option \"%s\"", $1),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
;
@@ -1299,7 +1298,7 @@ set_rest: /* Generic SET syntaxes: */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("current database cannot be changed"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
$$ = NULL; /*not reached*/
}
| SCHEMA Sconst
@@ -1307,7 +1306,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "search_path";
- n->args = list_make1(makeStringConst($2, @2));
+ n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
$$ = n;
}
| NAMES opt_encoding
@@ -1316,7 +1315,7 @@ set_rest: /* Generic SET syntaxes: */
n->kind = VAR_SET_VALUE;
n->name = "client_encoding";
if ($2 != NULL)
- n->args = list_make1(makeStringConst($2, @2));
+ n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
else
n->kind = VAR_SET_DEFAULT;
$$ = n;
@@ -1326,7 +1325,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "role";
- n->args = list_make1(makeStringConst($2, @2));
+ n->args = list_make1(makeStringConst($2, @2.begins, @2.length));
$$ = n;
}
| SESSION AUTHORIZATION ColId_or_Sconst
@@ -1334,7 +1333,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "session_authorization";
- n->args = list_make1(makeStringConst($3, @3));
+ n->args = list_make1(makeStringConst($3, @3.begins, @3.length));
$$ = n;
}
| SESSION AUTHORIZATION DEFAULT
@@ -1349,7 +1348,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_VALUE;
n->name = "xmloption";
- n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3));
+ n->args = list_make1(makeStringConst($3 == XMLOPTION_DOCUMENT ? "DOCUMENT" : "CONTENT", @3.begins, @3.length));
$$ = n;
}
/* Special syntaxes invented by PostgreSQL: */
@@ -1358,7 +1357,7 @@ set_rest: /* Generic SET syntaxes: */
VariableSetStmt *n = makeNode(VariableSetStmt);
n->kind = VAR_SET_MULTI;
n->name = "TRANSACTION SNAPSHOT";
- n->args = list_make1(makeStringConst($3, @3));
+ n->args = list_make1(makeStringConst($3, @3.begins, @3.length));
$$ = n;
}
;
@@ -1376,9 +1375,9 @@ var_list: var_value { $$ = list_make1($1); }
;
var_value: opt_boolean_or_string
- { $$ = makeStringConst($1, @1); }
+ { $$ = makeStringConst($1, @1.begins, @1.length); }
| NumericOnly
- { $$ = makeAConst($1, @1); }
+ { $$ = makeAConst($1, @1.begins, @1.length); }
;
iso_level: READ UNCOMMITTED { $$ = "read uncommitted"; }
@@ -1410,11 +1409,11 @@ opt_boolean_or_string:
zone_value:
Sconst
{
- $$ = makeStringConst($1, @1);
+ $$ = makeStringConst($1, @1.begins, @1.length);
}
| IDENT
{
- $$ = makeStringConst($1, @1);
+ $$ = makeStringConst($1, @1.begins, @1.length);
}
| ConstInterval Sconst opt_interval
{
@@ -1426,10 +1425,10 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
- parser_errposition(@3)));
+ parser_errposition(@3.begins)));
}
t->typmods = $3;
- $$ = makeStringConstCast($2, @2, t);
+ $$ = makeStringConstCast($2, @2.begins, @2.length, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
@@ -1441,20 +1440,20 @@ zone_value:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("time zone interval must be HOUR or HOUR TO MINUTE"),
- parser_errposition(@6)));
+ parser_errposition(@6.begins)));
if (list_length($6) != 1)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("interval precision specified twice"),
- parser_errposition(@1)));
- t->typmods = lappend($6, makeIntConst($3, @3));
+ parser_errposition(@1.begins)));
+ t->typmods = lappend($6, makeIntConst($3, @3.begins, @3.length));
}
else
- t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
- makeIntConst($3, @3));
- $$ = makeStringConstCast($5, @5, t);
+ t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
+ makeIntConst($3, @3.begins, @3.length));
+ $$ = makeStringConstCast($5, @5.begins, @5.length, t);
}
- | NumericOnly { $$ = makeAConst($1, @1); }
+ | NumericOnly { $$ = makeAConst($1, @1.begins, @1.length); }
| DEFAULT { $$ = NULL; }
| LOCAL { $$ = NULL; }
;
@@ -1966,7 +1965,7 @@ alter_table_cmd:
{
AlterTableCmd *n = makeNode(AlterTableCmd);
TypeName *def = makeTypeNameFromNameList($2);
- def->location = @2;
+ def->location = @2.begins;
n->subtype = AT_AddOf;
n->def = (Node *) def;
$$ = (Node *)n;
@@ -2036,7 +2035,7 @@ opt_collate_clause:
CollateClause *n = makeNode(CollateClause);
n->arg = NULL;
n->collname = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
| /* EMPTY */ { $$ = NULL; }
@@ -2095,7 +2094,7 @@ AlterCompositeTypeStmt:
AlterTableStmt *n = makeNode(AlterTableStmt);
/* can't use qualified_name, sigh */
- n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
+ n->relation = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
n->cmds = $4;
n->relkind = OBJECT_TYPE;
$$ = (Node *)n;
@@ -2429,7 +2428,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->relation = $4;
n->tableElts = $7;
n->ofTypename = makeTypeNameFromNameList($6);
- n->ofTypename->location = @6;
+ n->ofTypename->location = @6.begins;
n->constraints = NIL;
n->options = $8;
n->oncommit = $9;
@@ -2445,7 +2444,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->relation = $7;
n->tableElts = $10;
n->ofTypename = makeTypeNameFromNameList($9);
- n->ofTypename->location = @9;
+ n->ofTypename->location = @9.begins;
n->constraints = NIL;
n->options = $11;
n->oncommit = $12;
@@ -2565,7 +2564,7 @@ ColConstraint:
Constraint *n = (Constraint *) $3;
Assert(IsA(n, Constraint));
n->conname = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
| ColConstraintElem { $$ = $1; }
@@ -2580,7 +2579,7 @@ ColConstraint:
CollateClause *n = makeNode(CollateClause);
n->arg = NULL;
n->collname = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
;
@@ -2605,21 +2604,21 @@ ColConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_NOTNULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| NULL_P
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| UNIQUE opt_definition OptConsTableSpace
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
- n->location = @1;
+ n->location = @1.begins;
n->keys = NULL;
n->options = $2;
n->indexname = NULL;
@@ -2630,7 +2629,7 @@ ColConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
- n->location = @1;
+ n->location = @1.begins;
n->keys = NULL;
n->options = $3;
n->indexname = NULL;
@@ -2641,7 +2640,7 @@ ColConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
- n->location = @1;
+ n->location = @1.begins;
n->raw_expr = $3;
n->cooked_expr = NULL;
$$ = (Node *)n;
@@ -2650,7 +2649,7 @@ ColConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_DEFAULT;
- n->location = @1;
+ n->location = @1.begins;
n->raw_expr = $2;
n->cooked_expr = NULL;
$$ = (Node *)n;
@@ -2659,7 +2658,7 @@ ColConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_FOREIGN;
- n->location = @1;
+ n->location = @1.begins;
n->pktable = $2;
n->fk_attrs = NIL;
n->pk_attrs = $3;
@@ -2692,28 +2691,28 @@ ConstraintAttr:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_ATTR_DEFERRABLE;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| NOT DEFERRABLE
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_ATTR_NOT_DEFERRABLE;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| INITIALLY DEFERRED
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_ATTR_DEFERRED;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| INITIALLY IMMEDIATE
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_ATTR_IMMEDIATE;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
;
@@ -2763,7 +2762,7 @@ TableConstraint:
Constraint *n = (Constraint *) $3;
Assert(IsA(n, Constraint));
n->conname = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
| ConstraintElem { $$ = $1; }
@@ -2774,10 +2773,10 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_CHECK;
- n->location = @1;
+ n->location = @1.begins;
n->raw_expr = $3;
n->cooked_expr = NULL;
- processCASbits($5, @5, "CHECK",
+ processCASbits($5, @5.begins, "CHECK",
NULL, NULL, &n->skip_validation,
yyscanner);
n->initially_valid = !n->skip_validation;
@@ -2788,12 +2787,12 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
- n->location = @1;
+ n->location = @1.begins;
n->keys = $3;
n->options = $5;
n->indexname = NULL;
n->indexspace = $6;
- processCASbits($7, @7, "UNIQUE",
+ processCASbits($7, @7.begins, "UNIQUE",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
$$ = (Node *)n;
@@ -2802,12 +2801,12 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_UNIQUE;
- n->location = @1;
+ n->location = @1.begins;
n->keys = NIL;
n->options = NIL;
n->indexname = $2;
n->indexspace = NULL;
- processCASbits($3, @3, "UNIQUE",
+ processCASbits($3, @3.begins, "UNIQUE",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
$$ = (Node *)n;
@@ -2817,12 +2816,12 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
- n->location = @1;
+ n->location = @1.begins;
n->keys = $4;
n->options = $6;
n->indexname = NULL;
n->indexspace = $7;
- processCASbits($8, @8, "PRIMARY KEY",
+ processCASbits($8, @8.begins, "PRIMARY KEY",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
$$ = (Node *)n;
@@ -2831,12 +2830,12 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_PRIMARY;
- n->location = @1;
+ n->location = @1.begins;
n->keys = NIL;
n->options = NIL;
n->indexname = $3;
n->indexspace = NULL;
- processCASbits($4, @4, "PRIMARY KEY",
+ processCASbits($4, @4.begins, "PRIMARY KEY",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
$$ = (Node *)n;
@@ -2847,14 +2846,14 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_EXCLUSION;
- n->location = @1;
+ n->location = @1.begins;
n->access_method = $2;
n->exclusions = $4;
n->options = $6;
n->indexname = NULL;
n->indexspace = $7;
n->where_clause = $8;
- processCASbits($9, @9, "EXCLUDE",
+ processCASbits($9, @9.begins, "EXCLUDE",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
$$ = (Node *)n;
@@ -2864,14 +2863,14 @@ ConstraintElem:
{
Constraint *n = makeNode(Constraint);
n->contype = CONSTR_FOREIGN;
- n->location = @1;
+ n->location = @1.begins;
n->pktable = $7;
n->fk_attrs = $4;
n->pk_attrs = $8;
n->fk_matchtype = $9;
n->fk_upd_action = (char) ($10 >> 8);
n->fk_del_action = (char) ($10 & 0xFF);
- processCASbits($11, @11, "FOREIGN KEY",
+ processCASbits($11, @11.begins, "FOREIGN KEY",
&n->deferrable, &n->initdeferred,
&n->skip_validation,
yyscanner);
@@ -2905,7 +2904,7 @@ key_match: MATCH FULL
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("MATCH PARTIAL not yet implemented"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = FKCONSTR_MATCH_PARTIAL;
}
| MATCH SIMPLE
@@ -3028,7 +3027,7 @@ CreateAsStmt:
n->intoClause = $4;
/* Implement WITH NO DATA by forcing top-level LIMIT 0 */
if (!$7)
- ((SelectStmt *) $6)->limitCount = makeIntConst(0, -1);
+ ((SelectStmt *) $6)->limitCount = makeIntConst(0, -1, -1);
$$ = $6;
}
;
@@ -4050,7 +4049,7 @@ CreateTrigStmt:
n->columns = (List *) lsecond($6);
n->whenClause = $14;
n->isconstraint = TRUE;
- processCASbits($10, @10, "TRIGGER",
+ processCASbits($10, @10.begins, "TRIGGER",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
n->constrrel = $9;
@@ -4171,14 +4170,14 @@ ConstraintAttributeSpec:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("constraint declared INITIALLY DEFERRED must be DEFERRABLE"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
/* generic message for other conflicts */
if ((newspec & (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE)) == (CAS_NOT_DEFERRABLE | CAS_DEFERRABLE) ||
(newspec & (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED)) == (CAS_INITIALLY_IMMEDIATE | CAS_INITIALLY_DEFERRED))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting constraint properties"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
$$ = newspec;
}
;
@@ -4232,7 +4231,7 @@ CreateAssertStmt:
n->trigname = $3;
n->args = list_make1($6);
n->isconstraint = TRUE;
- processCASbits($8, @8, "ASSERTION",
+ processCASbits($8, @8.begins, "ASSERTION",
&n->deferrable, &n->initdeferred, NULL,
yyscanner);
@@ -4325,7 +4324,7 @@ DefineStmt:
CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
/* can't use qualified_name, sigh */
- n->typevar = makeRangeVarFromAnyName($3, @3, yyscanner);
+ n->typevar = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
n->coldeflist = $6;
$$ = (Node *)n;
}
@@ -4599,7 +4598,7 @@ opt_recheck: RECHECK
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RECHECK is no longer required"),
errhint("Update your data type."),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = TRUE;
}
| /*EMPTY*/ { $$ = FALSE; }
@@ -5841,7 +5840,7 @@ CreateFunctionStmt:
n->funcname = $4;
n->parameters = mergeTableFuncParameters($5, $9);
n->returnType = TableFuncTypeName($9);
- n->returnType->location = @7;
+ n->returnType->location = @7.begins;
n->options = $11;
n->withClause = $12;
$$ = (Node *)n;
@@ -5982,14 +5981,14 @@ func_type: Typename { $$ = $1; }
{
$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
$$->pct_type = true;
- $$->location = @1;
+ $$->location = @1.begins;
}
| SETOF type_function_name attrs '%' TYPE_P
{
$$ = makeTypeNameFromNameList(lcons(makeString($2), $3));
$$->pct_type = true;
$$->setof = TRUE;
- $$->location = @2;
+ $$->location = @2.begins;
}
;
@@ -6246,7 +6245,7 @@ oper_argtypes:
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("missing argument"),
errhint("Use NONE to denote the missing argument of a unary operator."),
- parser_errposition(@3)));
+ parser_errposition(@3.begins)));
}
| '(' Typename ',' Typename ')'
{ $$ = list_make2($2, $4); }
@@ -6660,7 +6659,7 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
RenameStmt *n = makeNode(RenameStmt);
n->renameType = OBJECT_ATTRIBUTE;
n->relationType = OBJECT_TYPE;
- n->relation = makeRangeVarFromAnyName($3, @3, yyscanner);
+ n->relation = makeRangeVarFromAnyName($3, @3.begins, yyscanner);
n->subname = $6;
n->newname = $8;
n->behavior = $9;
@@ -7255,19 +7254,19 @@ opt_transaction: WORK {}
transaction_mode_item:
ISOLATION LEVEL iso_level
{ $$ = makeDefElem("transaction_isolation",
- makeStringConst($3, @3)); }
+ makeStringConst($3, @3.begins, @3.length)); }
| READ ONLY
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(TRUE, @1)); }
+ makeIntConst(TRUE, @1.begins, @1.length)); }
| READ WRITE
{ $$ = makeDefElem("transaction_read_only",
- makeIntConst(FALSE, @1)); }
+ makeIntConst(FALSE, @1.begins, @1.length)); }
| DEFERRABLE
{ $$ = makeDefElem("transaction_deferrable",
- makeIntConst(TRUE, @1)); }
+ makeIntConst(TRUE, @1.begins, @1.length)); }
| NOT DEFERRABLE
{ $$ = makeDefElem("transaction_deferrable",
- makeIntConst(FALSE, @1)); }
+ makeIntConst(FALSE, @1.begins, @1.length)); }
;
/* Syntax with commas is SQL-spec, without commas is Postgres historical */
@@ -8117,7 +8116,7 @@ insert_column_item:
$$->name = $1;
$$->indirection = check_indirection($2, yyscanner);
$$->val = NULL;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -8247,7 +8246,7 @@ multiple_set_clause:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("number of columns does not match number of values"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
forboth(col_cell, $2, val_cell, $5)
{
ResTarget *res_col = (ResTarget *) lfirst(col_cell);
@@ -8267,7 +8266,7 @@ set_target:
$$->name = $1;
$$->indirection = check_indirection($2, yyscanner);
$$->val = NULL; /* upper production sets this */
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -8524,14 +8523,14 @@ with_clause:
$$ = makeNode(WithClause);
$$->ctes = $2;
$$->recursive = false;
- $$->location = @1;
+ $$->location = @1.begins;
}
| WITH RECURSIVE cte_list
{
$$ = makeNode(WithClause);
$$->ctes = $3;
$$->recursive = true;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -8546,7 +8545,7 @@ common_table_expr: name opt_name_list AS '(' PreparableStmt ')'
n->ctename = $1;
n->aliascolnames = $2;
n->ctequery = $5;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
;
@@ -8662,7 +8661,7 @@ sortby: a_expr USING qual_all_Op opt_nulls_order
$$->sortby_dir = SORTBY_USING;
$$->sortby_nulls = $4;
$$->useOp = $3;
- $$->location = @3;
+ $$->location = @3.begins;
}
| a_expr opt_asc_desc opt_nulls_order
{
@@ -8698,7 +8697,7 @@ limit_clause:
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("LIMIT #,# syntax is not supported"),
errhint("Use separate LIMIT and OFFSET clauses."),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
/* SQL:2008 syntax */
| FETCH first_or_next opt_select_fetch_first_value row_or_rows ONLY
@@ -8718,7 +8717,7 @@ select_limit_value:
| ALL
{
/* LIMIT ALL is represented as a NULL constant */
- $$ = makeNullAConst(@1);
+ $$ = makeNullAConst(@1.begins, @1.length);
}
;
@@ -8733,9 +8732,9 @@ select_offset_value:
* default to 1.
*/
opt_select_fetch_first_value:
- SignedIconst { $$ = makeIntConst($1, @1); }
+ SignedIconst { $$ = makeIntConst($1, @1.begins, @1.length); }
| '(' a_expr ')' { $$ = $2; }
- | /*EMPTY*/ { $$ = makeIntConst(1, -1); }
+ | /*EMPTY*/ { $$ = makeIntConst(1, -1, -1); }
;
/*
@@ -8917,13 +8916,13 @@ table_ref: relation_expr
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("VALUES in FROM must have an alias"),
errhint("For example, FROM (VALUES ...) [AS] foo."),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("subquery in FROM must have an alias"),
errhint("For example, FROM (SELECT ...) [AS] foo."),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = NULL;
}
| select_with_parens alias_clause
@@ -9283,12 +9282,12 @@ SimpleTypename:
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("interval precision specified twice"),
- parser_errposition(@1)));
- $$->typmods = lappend($5, makeIntConst($3, @3));
+ parser_errposition(@1.begins)));
+ $$->typmods = lappend($5, makeIntConst($3, @3.begins, @3.length));
}
else
- $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
- makeIntConst($3, @3));
+ $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
+ makeIntConst($3, @3.begins, @3.length));
}
;
@@ -9322,13 +9321,13 @@ GenericType:
{
$$ = makeTypeName($1);
$$->typmods = $2;
- $$->location = @1;
+ $$->location = @1.begins;
}
| type_function_name attrs opt_type_modifiers
{
$$ = makeTypeNameFromNameList(lcons(makeString($1), $2));
$$->typmods = $3;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9342,60 +9341,60 @@ opt_type_modifiers: '(' expr_list ')' { $$ = $2; }
Numeric: INT_P
{
$$ = SystemTypeName("int4");
- $$->location = @1;
+ $$->location = @1.begins;
}
| INTEGER
{
$$ = SystemTypeName("int4");
- $$->location = @1;
+ $$->location = @1.begins;
}
| SMALLINT
{
$$ = SystemTypeName("int2");
- $$->location = @1;
+ $$->location = @1.begins;
}
| BIGINT
{
$$ = SystemTypeName("int8");
- $$->location = @1;
+ $$->location = @1.begins;
}
| REAL
{
$$ = SystemTypeName("float4");
- $$->location = @1;
+ $$->location = @1.begins;
}
| FLOAT_P opt_float
{
$$ = $2;
- $$->location = @1;
+ $$->location = @1.begins;
}
| DOUBLE_P PRECISION
{
$$ = SystemTypeName("float8");
- $$->location = @1;
+ $$->location = @1.begins;
}
| DECIMAL_P opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmods = $2;
- $$->location = @1;
+ $$->location = @1.begins;
}
| DEC opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmods = $2;
- $$->location = @1;
+ $$->location = @1.begins;
}
| NUMERIC opt_type_modifiers
{
$$ = SystemTypeName("numeric");
$$->typmods = $2;
- $$->location = @1;
+ $$->location = @1.begins;
}
| BOOLEAN_P
{
$$ = SystemTypeName("bool");
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9409,7 +9408,7 @@ opt_float: '(' Iconst ')'
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("precision for type float must be at least 1 bit"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
else if ($2 <= 24)
$$ = SystemTypeName("float4");
else if ($2 <= 53)
@@ -9418,7 +9417,7 @@ opt_float: '(' Iconst ')'
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("precision for type float must be less than 54 bits"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
}
| /*EMPTY*/
{
@@ -9461,7 +9460,7 @@ BitWithLength:
typname = $2 ? "varbit" : "bit";
$$ = SystemTypeName(typname);
$$->typmods = $4;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9476,9 +9475,9 @@ BitWithoutLength:
else
{
$$ = SystemTypeName("bit");
- $$->typmods = list_make1(makeIntConst(1, -1));
+ $$->typmods = list_make1(makeIntConst(1, -1, -1));
}
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9528,8 +9527,8 @@ CharacterWithLength: character '(' Iconst ')' opt_charset
}
$$ = SystemTypeName($1);
- $$->typmods = list_make1(makeIntConst($3, @3));
- $$->location = @1;
+ $$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$->location = @1.begins;
}
;
@@ -9550,9 +9549,9 @@ CharacterWithoutLength: character opt_charset
/* char defaults to char(1), varchar to no limit */
if (strcmp($1, "bpchar") == 0)
- $$->typmods = list_make1(makeIntConst(1, -1));
+ $$->typmods = list_make1(makeIntConst(1, -1, -1));
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9590,8 +9589,8 @@ ConstDatetime:
$$ = SystemTypeName("timestamptz");
else
$$ = SystemTypeName("timestamp");
- $$->typmods = list_make1(makeIntConst($3, @3));
- $$->location = @1;
+ $$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$->location = @1.begins;
}
| TIMESTAMP opt_timezone
{
@@ -9599,7 +9598,7 @@ ConstDatetime:
$$ = SystemTypeName("timestamptz");
else
$$ = SystemTypeName("timestamp");
- $$->location = @1;
+ $$->location = @1.begins;
}
| TIME '(' Iconst ')' opt_timezone
{
@@ -9607,8 +9606,8 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
- $$->typmods = list_make1(makeIntConst($3, @3));
- $$->location = @1;
+ $$->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$->location = @1.begins;
}
| TIME opt_timezone
{
@@ -9616,7 +9615,7 @@ ConstDatetime:
$$ = SystemTypeName("timetz");
else
$$ = SystemTypeName("time");
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9624,7 +9623,7 @@ ConstInterval:
INTERVAL
{
$$ = SystemTypeName("interval");
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -9636,32 +9635,32 @@ opt_timezone:
opt_interval:
YEAR_P
- { $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1)); }
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR), @1.begins, @1.length)); }
| MONTH_P
- { $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1)); }
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(MONTH), @1.begins, @1.length)); }
| DAY_P
- { $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1)); }
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(DAY), @1.begins, @1.length)); }
| HOUR_P
- { $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1)); }
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR), @1.begins, @1.length)); }
| MINUTE_P
- { $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1)); }
+ { $$ = list_make1(makeIntConst(INTERVAL_MASK(MINUTE), @1.begins, @1.length)); }
| interval_second
{ $$ = $1; }
| YEAR_P TO MONTH_P
{
$$ = list_make1(makeIntConst(INTERVAL_MASK(YEAR) |
- INTERVAL_MASK(MONTH), @1));
+ INTERVAL_MASK(MONTH), @1.begins, @1.length));
}
| DAY_P TO HOUR_P
{
$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
- INTERVAL_MASK(HOUR), @1));
+ INTERVAL_MASK(HOUR), @1.begins, @1.length));
}
| DAY_P TO MINUTE_P
{
$$ = list_make1(makeIntConst(INTERVAL_MASK(DAY) |
INTERVAL_MASK(HOUR) |
- INTERVAL_MASK(MINUTE), @1));
+ INTERVAL_MASK(MINUTE), @1.begins, @1.length));
}
| DAY_P TO interval_second
{
@@ -9669,25 +9668,25 @@ opt_interval:
linitial($$) = makeIntConst(INTERVAL_MASK(DAY) |
INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE) |
- INTERVAL_MASK(SECOND), @1);
+ INTERVAL_MASK(SECOND), @1.begins, @1.length);
}
| HOUR_P TO MINUTE_P
{
$$ = list_make1(makeIntConst(INTERVAL_MASK(HOUR) |
- INTERVAL_MASK(MINUTE), @1));
+ INTERVAL_MASK(MINUTE), @1.begins, @1.length));
}
| HOUR_P TO interval_second
{
$$ = $3;
linitial($$) = makeIntConst(INTERVAL_MASK(HOUR) |
INTERVAL_MASK(MINUTE) |
- INTERVAL_MASK(SECOND), @1);
+ INTERVAL_MASK(SECOND), @1.begins, @1.length);
}
| MINUTE_P TO interval_second
{
$$ = $3;
linitial($$) = makeIntConst(INTERVAL_MASK(MINUTE) |
- INTERVAL_MASK(SECOND), @1);
+ INTERVAL_MASK(SECOND), @1.begins, @1.length);
}
| /*EMPTY*/
{ $$ = NIL; }
@@ -9696,12 +9695,12 @@ opt_interval:
interval_second:
SECOND_P
{
- $$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1));
+ $$ = list_make1(makeIntConst(INTERVAL_MASK(SECOND), @1.begins, @1.length));
}
| SECOND_P '(' Iconst ')'
{
- $$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1),
- makeIntConst($3, @3));
+ $$ = list_make2(makeIntConst(INTERVAL_MASK(SECOND), @1.begins, @1.length),
+ makeIntConst($3, @3.begins, @3.length));
}
;
@@ -9730,13 +9729,13 @@ interval_second:
*/
a_expr: c_expr { $$ = $1; }
| a_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3, @2); }
+ { $$ = makeTypeCast($1, $3, @2.begins, @2.length); }
| a_expr COLLATE any_name
{
CollateClause *n = makeNode(CollateClause);
n->arg = $1;
n->collname = $3;
- n->location = @2;
+ n->location = @2.begins;
$$ = (Node *) n;
}
| a_expr AT TIME ZONE a_expr %prec AT
@@ -9749,7 +9748,7 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
+ n->location = @2.begins;
$$ = (Node *) n;
}
/*
@@ -9762,44 +9761,44 @@ a_expr: c_expr { $$ = $1; }
* also to b_expr and to the MathOp list above.
*/
| '+' a_expr %prec UMINUS
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1.begins); }
| '-' a_expr %prec UMINUS
- { $$ = doNegate($2, @1); }
+ { $$ = doNegate($2, @1.begins, @1.length); }
| a_expr '+' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2.begins); }
| a_expr '-' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2.begins); }
| a_expr '*' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2.begins); }
| a_expr '/' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2.begins); }
| a_expr '%' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2.begins); }
| a_expr '^' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2.begins); }
| a_expr '<' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2.begins); }
| a_expr '>' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2.begins); }
| a_expr '=' a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2.begins); }
| a_expr qual_Op a_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2.begins); }
| qual_Op a_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1.begins); }
| a_expr qual_Op %prec POSTFIXOP
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2.begins); }
| a_expr AND a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_AND, NIL, $1, $3, @2.begins); }
| a_expr OR a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OR, NIL, $1, $3, @2.begins); }
| NOT a_expr
- { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1); }
+ { $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, $2, @1.begins); }
| a_expr LIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, $3, @2.begins); }
| a_expr LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -9810,11 +9809,11 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~", $1, (Node *) n, @2.begins);
}
| a_expr NOT LIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, $4, @2.begins); }
| a_expr NOT LIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -9825,11 +9824,11 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~", $1, (Node *) n, @2.begins);
}
| a_expr ILIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, $3, @2.begins); }
| a_expr ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -9840,11 +9839,11 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~~*", $1, (Node *) n, @2.begins);
}
| a_expr NOT ILIKE a_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, $4, @2.begins); }
| a_expr NOT ILIKE a_expr ESCAPE a_expr
{
FuncCall *n = makeNode(FuncCall);
@@ -9855,22 +9854,22 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~~*", $1, (Node *) n, @2.begins);
}
| a_expr SIMILAR TO a_expr %prec SIMILAR
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($4, makeNullAConst(-1));
+ n->args = list_make2($4, makeNullAConst(-1, -1));
n->agg_order = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2.begins);
}
| a_expr SIMILAR TO a_expr ESCAPE a_expr
{
@@ -9882,21 +9881,21 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "~", $1, (Node *) n, @2.begins);
}
| a_expr NOT SIMILAR TO a_expr %prec SIMILAR
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("similar_escape");
- n->args = list_make2($5, makeNullAConst(-1));
+ n->args = list_make2($5, makeNullAConst(-1, -1));
n->agg_order = NIL;
n->agg_star = FALSE;
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2.begins);
}
| a_expr NOT SIMILAR TO a_expr ESCAPE a_expr
{
@@ -9908,8 +9907,8 @@ a_expr: c_expr { $$ = $1; }
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @2;
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2);
+ n->location = @2.begins;
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "!~", $1, (Node *) n, @2.begins);
}
/* NullTest clause
@@ -9951,7 +9950,7 @@ a_expr: c_expr { $$ = $1; }
}
| row OVERLAPS row
{
- $$ = (Node *)makeOverlaps($1, $3, @2, yyscanner);
+ $$ = (Node *)makeOverlaps($1, $3, @2.begins, yyscanner);
}
| a_expr IS TRUE_P %prec IS
{
@@ -9997,23 +9996,23 @@ a_expr: c_expr { $$ = $1; }
}
| a_expr IS DISTINCT FROM a_expr %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2.begins);
}
| a_expr IS NOT DISTINCT FROM a_expr %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
(Node *) makeSimpleA_Expr(AEXPR_DISTINCT,
- "=", $1, $6, @2),
- @2);
+ "=", $1, $6, @2.begins),
+ @2.begins);
}
| a_expr IS OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2.begins);
}
| a_expr IS NOT OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2.begins);
}
/*
* Ideally we would not use hard-wired operators below but
@@ -10024,42 +10023,43 @@ a_expr: c_expr { $$ = $1; }
| a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
- @2);
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2.begins),
+ @2.begins);
}
| a_expr NOT BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
- @2);
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2.begins),
+ @2.begins);
}
| a_expr BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_OR, NIL,
(Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2),
- @2),
+
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $4, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $6, @2.begins),
+ @2.begins),
(Node *) makeA_Expr(AEXPR_AND, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2),
- @2),
- @2);
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $6, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $4, @2.begins),
+ @2.begins),
+ @2.begins);
}
| a_expr NOT BETWEEN SYMMETRIC b_expr AND b_expr %prec BETWEEN
{
$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
(Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2),
- @2),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $5, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $7, @2.begins),
+ @2.begins),
(Node *) makeA_Expr(AEXPR_OR, NIL,
- (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2),
- (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2),
- @2),
- @2);
+ (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $7, @2.begins),
+ (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $5, @2.begins),
+ @2.begins),
+ @2.begins);
}
| a_expr IN_P in_expr
{
@@ -10071,13 +10071,13 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
- n->location = @2;
+ n->location = @2.begins;
$$ = (Node *)n;
}
else
{
/* generate scalar IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "=", $1, $3, @2.begins);
}
}
| a_expr NOT IN_P in_expr
@@ -10091,14 +10091,14 @@ a_expr: c_expr { $$ = $1; }
n->subLinkType = ANY_SUBLINK;
n->testexpr = $1;
n->operName = list_make1(makeString("="));
- n->location = @3;
+ n->location = @3.begins;
/* Stick a NOT on top */
- $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2);
+ $$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL, (Node *) n, @2.begins);
}
else
{
/* generate scalar NOT IN expression */
- $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_IN, "<>", $1, $4, @2.begins);
}
}
| a_expr subquery_Op sub_type select_with_parens %prec Op
@@ -10108,15 +10108,15 @@ a_expr: c_expr { $$ = $1; }
n->testexpr = $1;
n->operName = $2;
n->subselect = $4;
- n->location = @2;
+ n->location = @2.begins;
$$ = (Node *)n;
}
| a_expr subquery_Op sub_type '(' a_expr ')' %prec Op
{
if ($3 == ANY_SUBLINK)
- $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2);
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ANY, $2, $1, $5, @2.begins);
else
- $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2);
+ $$ = (Node *) makeA_Expr(AEXPR_OP_ALL, $2, $1, $5, @2.begins);
}
| UNIQUE select_with_parens
{
@@ -10132,19 +10132,19 @@ a_expr: c_expr { $$ = $1; }
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("UNIQUE predicate is not yet implemented"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
| a_expr IS DOCUMENT_P %prec IS
{
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
- list_make1($1), @2);
+ list_make1($1), @2.begins);
}
| a_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
makeXmlExpr(IS_DOCUMENT, NULL, NIL,
- list_make1($1), @2),
- @2);
+ list_make1($1), @2.begins),
+ @2.begins);
}
;
@@ -10160,63 +10160,63 @@ a_expr: c_expr { $$ = $1; }
b_expr: c_expr
{ $$ = $1; }
| b_expr TYPECAST Typename
- { $$ = makeTypeCast($1, $3, @2); }
+ { $$ = makeTypeCast($1, $3, @2.begins, @2.length); }
| '+' b_expr %prec UMINUS
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1.begins); }
| '-' b_expr %prec UMINUS
- { $$ = doNegate($2, @1); }
+ { $$ = doNegate($2, @1.begins, @1.length); }
| b_expr '+' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2.begins); }
| b_expr '-' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2.begins); }
| b_expr '*' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2.begins); }
| b_expr '/' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2.begins); }
| b_expr '%' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2.begins); }
| b_expr '^' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2.begins); }
| b_expr '<' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2.begins); }
| b_expr '>' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2.begins); }
| b_expr '=' b_expr
- { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
+ { $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2.begins); }
| b_expr qual_Op b_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2.begins); }
| qual_Op b_expr %prec Op
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1.begins); }
| b_expr qual_Op %prec POSTFIXOP
- { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
+ { $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2.begins); }
| b_expr IS DISTINCT FROM b_expr %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2.begins);
}
| b_expr IS NOT DISTINCT FROM b_expr %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL,
- NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2), @2);
+ NULL, (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $6, @2.begins), @2.begins);
}
| b_expr IS OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2.begins);
}
| b_expr IS NOT OF '(' type_list ')' %prec IS
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2.begins);
}
| b_expr IS DOCUMENT_P %prec IS
{
$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
- list_make1($1), @2);
+ list_make1($1), @2.begins);
}
| b_expr IS NOT DOCUMENT_P %prec IS
{
$$ = (Node *) makeA_Expr(AEXPR_NOT, NIL, NULL,
makeXmlExpr(IS_DOCUMENT, NULL, NIL,
- list_make1($1), @2),
- @2);
+ list_make1($1), @2.begins),
+ @2.begins);
}
;
@@ -10234,7 +10234,7 @@ c_expr: columnref { $$ = $1; }
{
ParamRef *p = makeNode(ParamRef);
p->number = $1;
- p->location = @1;
+ p->location = @1.begins;
if ($2)
{
A_Indirection *n = makeNode(A_Indirection);
@@ -10268,7 +10268,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $1;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| EXISTS select_with_parens
@@ -10278,7 +10278,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| ARRAY select_with_parens
@@ -10288,7 +10288,7 @@ c_expr: columnref { $$ = $1; }
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| ARRAY array_expr
@@ -10296,7 +10296,7 @@ c_expr: columnref { $$ = $1; }
A_ArrayExpr *n = (A_ArrayExpr *) $2;
Assert(IsA(n, A_ArrayExpr));
/* point outermost A_ArrayExpr to the ARRAY keyword */
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| row
@@ -10304,7 +10304,7 @@ c_expr: columnref { $$ = $1; }
RowExpr *r = makeNode(RowExpr);
r->args = $1;
r->row_typeid = InvalidOid; /* not analyzed yet */
- r->location = @1;
+ r->location = @1.begins;
$$ = (Node *)r;
}
;
@@ -10327,7 +10327,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = $4;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' func_arg_list ')' over_clause
@@ -10340,7 +10340,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = $5;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' VARIADIC func_arg_expr ')' over_clause
@@ -10353,7 +10353,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = TRUE;
n->over = $6;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' func_arg_list ',' VARIADIC func_arg_expr ')' over_clause
@@ -10366,7 +10366,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = TRUE;
n->over = $8;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' func_arg_list sort_clause ')' over_clause
@@ -10379,7 +10379,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = $6;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' ALL func_arg_list opt_sort_clause ')' over_clause
@@ -10396,7 +10396,7 @@ func_expr: func_name '(' ')' over_clause
*/
n->func_variadic = FALSE;
n->over = $7;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' DISTINCT func_arg_list opt_sort_clause ')' over_clause
@@ -10409,7 +10409,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = TRUE;
n->func_variadic = FALSE;
n->over = $7;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| func_name '(' '*' ')' over_clause
@@ -10432,7 +10432,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = $5;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CURRENT_DATE
@@ -10453,8 +10453,8 @@ func_expr: func_name '(' ')' over_clause
* to rely on it.)
*/
Node *n;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("date"), -1);
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("date"), -1, -1);
}
| CURRENT_TIME
{
@@ -10463,8 +10463,8 @@ func_expr: func_name '(' ')' over_clause
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timetz"), -1);
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timetz"), -1, -1);
}
| CURRENT_TIME '(' Iconst ')'
{
@@ -10474,10 +10474,10 @@ func_expr: func_name '(' ')' over_clause
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
d = SystemTypeName("timetz");
- d->typmods = list_make1(makeIntConst($3, @3));
- $$ = makeTypeCast(n, d, -1);
+ d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$ = makeTypeCast(n, d, -1, -1);
}
| CURRENT_TIMESTAMP
{
@@ -10493,7 +10493,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CURRENT_TIMESTAMP '(' Iconst ')'
@@ -10504,10 +10504,10 @@ func_expr: func_name '(' ')' over_clause
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
d = SystemTypeName("timestamptz");
- d->typmods = list_make1(makeIntConst($3, @3));
- $$ = makeTypeCast(n, d, -1);
+ d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$ = makeTypeCast(n, d, -1, -1);
}
| LOCALTIME
{
@@ -10516,8 +10516,8 @@ func_expr: func_name '(' ')' over_clause
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
- $$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1);
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
+ $$ = makeTypeCast((Node *)n, SystemTypeName("time"), -1, -1);
}
| LOCALTIME '(' Iconst ')'
{
@@ -10527,10 +10527,10 @@ func_expr: func_name '(' ')' over_clause
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
d = SystemTypeName("time");
- d->typmods = list_make1(makeIntConst($3, @3));
- $$ = makeTypeCast((Node *)n, d, -1);
+ d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$ = makeTypeCast((Node *)n, d, -1, -1);
}
| LOCALTIMESTAMP
{
@@ -10539,8 +10539,8 @@ func_expr: func_name '(' ')' over_clause
* See comments for CURRENT_DATE.
*/
Node *n;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
- $$ = makeTypeCast(n, SystemTypeName("timestamp"), -1);
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
+ $$ = makeTypeCast(n, SystemTypeName("timestamp"), -1, -1);
}
| LOCALTIMESTAMP '(' Iconst ')'
{
@@ -10550,10 +10550,10 @@ func_expr: func_name '(' ')' over_clause
*/
Node *n;
TypeName *d;
- n = makeStringConstCast("now", @1, SystemTypeName("text"));
+ n = makeStringConstCast("now", @1.begins, @1.length, SystemTypeName("text"));
d = SystemTypeName("timestamp");
- d->typmods = list_make1(makeIntConst($3, @3));
- $$ = makeTypeCast(n, d, -1);
+ d->typmods = list_make1(makeIntConst($3, @3.begins, @3.length));
+ $$ = makeTypeCast(n, d, -1, -1);
}
| CURRENT_ROLE
{
@@ -10565,7 +10565,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CURRENT_USER
@@ -10578,7 +10578,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| SESSION_USER
@@ -10591,7 +10591,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| USER
@@ -10604,7 +10604,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CURRENT_CATALOG
@@ -10617,7 +10617,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CURRENT_SCHEMA
@@ -10630,11 +10630,11 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| CAST '(' a_expr AS Typename ')'
- { $$ = makeTypeCast($3, $5, @1); }
+ { $$ = makeTypeCast($3, $5, @1.begins, @1.length); }
| EXTRACT '(' extract_list ')'
{
FuncCall *n = makeNode(FuncCall);
@@ -10645,7 +10645,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| OVERLAY '(' overlay_list ')'
@@ -10663,7 +10663,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| POSITION '(' position_list ')'
@@ -10677,7 +10677,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| SUBSTRING '(' substr_list ')'
@@ -10693,7 +10693,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| TREAT '(' a_expr AS Typename ')'
@@ -10715,7 +10715,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| TRIM '(' BOTH trim_list ')'
@@ -10731,7 +10731,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| TRIM '(' LEADING trim_list ')'
@@ -10744,7 +10744,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| TRIM '(' TRAILING trim_list ')'
@@ -10757,7 +10757,7 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| TRIM '(' trim_list ')'
@@ -10770,18 +10770,18 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| NULLIF '(' a_expr ',' a_expr ')'
{
- $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1);
+ $$ = (Node *) makeSimpleA_Expr(AEXPR_NULLIF, "=", $3, $5, @1.begins);
}
| COALESCE '(' expr_list ')'
{
CoalesceExpr *c = makeNode(CoalesceExpr);
c->args = $3;
- c->location = @1;
+ c->location = @1.begins;
$$ = (Node *)c;
}
| GREATEST '(' expr_list ')'
@@ -10789,7 +10789,7 @@ func_expr: func_name '(' ')' over_clause
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_GREATEST;
- v->location = @1;
+ v->location = @1.begins;
$$ = (Node *)v;
}
| LEAST '(' expr_list ')'
@@ -10797,28 +10797,28 @@ func_expr: func_name '(' ')' over_clause
MinMaxExpr *v = makeNode(MinMaxExpr);
v->args = $3;
v->op = IS_LEAST;
- v->location = @1;
+ v->location = @1.begins;
$$ = (Node *)v;
}
| XMLCONCAT '(' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
+ $$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1.begins);
}
| XMLELEMENT '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1.begins);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1.begins);
}
| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1.begins);
}
| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
{
- $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
+ $$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1.begins);
}
| XMLEXISTS '(' c_expr xmlexists_argument ')'
{
@@ -10832,34 +10832,34 @@ func_expr: func_name '(' ')' over_clause
n->agg_distinct = FALSE;
n->func_variadic = FALSE;
n->over = NULL;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
| XMLFOREST '(' xml_attribute_list ')'
{
- $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
+ $$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1.begins);
}
| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
{
XmlExpr *x = (XmlExpr *)
makeXmlExpr(IS_XMLPARSE, NULL, NIL,
- list_make2($4, makeBoolAConst($5, -1)),
- @1);
+ list_make2($4, makeBoolAConst($5, -1, -1)),
+ @1.begins);
x->xmloption = $3;
$$ = (Node *)x;
}
| XMLPI '(' NAME_P ColLabel ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1);
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, NIL, @1.begins);
}
| XMLPI '(' NAME_P ColLabel ',' a_expr ')'
{
- $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1);
+ $$ = makeXmlExpr(IS_XMLPI, $4, NULL, list_make1($6), @1.begins);
}
| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
{
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
- list_make3($3, $5, $6), @1);
+ list_make3($3, $5, $6), @1.begins);
}
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
{
@@ -10867,7 +10867,7 @@ func_expr: func_name '(' ')' over_clause
n->xmloption = $3;
n->expr = $4;
n->typeName = $6;
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *)n;
}
;
@@ -10878,17 +10878,17 @@ func_expr: func_name '(' ')' over_clause
xml_root_version: VERSION_P a_expr
{ $$ = $2; }
| VERSION_P NO VALUE_P
- { $$ = makeNullAConst(-1); }
+ { $$ = makeNullAConst(-1, -1); }
;
opt_xml_root_standalone: ',' STANDALONE_P YES_P
- { $$ = makeIntConst(XML_STANDALONE_YES, -1); }
+ { $$ = makeIntConst(XML_STANDALONE_YES, -1, -1); }
| ',' STANDALONE_P NO
- { $$ = makeIntConst(XML_STANDALONE_NO, -1); }
+ { $$ = makeIntConst(XML_STANDALONE_NO, -1, -1); }
| ',' STANDALONE_P NO VALUE_P
- { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1); }
+ { $$ = makeIntConst(XML_STANDALONE_NO_VALUE, -1, -1); }
| /*EMPTY*/
- { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1); }
+ { $$ = makeIntConst(XML_STANDALONE_OMITTED, -1, -1); }
;
xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')' { $$ = $3; }
@@ -10904,7 +10904,7 @@ xml_attribute_el: a_expr AS ColLabel
$$->name = $3;
$$->indirection = NIL;
$$->val = (Node *) $1;
- $$->location = @1;
+ $$->location = @1.begins;
}
| a_expr
{
@@ -10912,7 +10912,7 @@ xml_attribute_el: a_expr AS ColLabel
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *) $1;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -10981,7 +10981,7 @@ over_clause: OVER window_specification
n->frameOptions = FRAMEOPTION_DEFAULTS;
n->startOffset = NULL;
n->endOffset = NULL;
- n->location = @2;
+ n->location = @2.begins;
$$ = n;
}
| /*EMPTY*/
@@ -11000,7 +11000,7 @@ window_specification: '(' opt_existing_window_name opt_partition_clause
n->frameOptions = $5->frameOptions;
n->startOffset = $5->startOffset;
n->endOffset = $5->endOffset;
- n->location = @1;
+ n->location = @1.begins;
$$ = n;
}
;
@@ -11040,13 +11040,13 @@ opt_frame_clause:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RANGE PRECEDING is only supported with UNBOUNDED"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
if (n->frameOptions & (FRAMEOPTION_START_VALUE_FOLLOWING |
FRAMEOPTION_END_VALUE_FOLLOWING))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("RANGE FOLLOWING is only supported with UNBOUNDED"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = n;
}
| ROWS frame_extent
@@ -11073,12 +11073,12 @@ frame_extent: frame_bound
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
if (n->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame starting from following row cannot end with current row"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
n->frameOptions |= FRAMEOPTION_END_CURRENT_ROW;
$$ = n;
}
@@ -11096,25 +11096,25 @@ frame_extent: frame_bound
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame start cannot be UNBOUNDED FOLLOWING"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
if (frameOptions & FRAMEOPTION_END_UNBOUNDED_PRECEDING)
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame end cannot be UNBOUNDED PRECEDING"),
- parser_errposition(@4)));
+ parser_errposition(@4.begins)));
if ((frameOptions & FRAMEOPTION_START_CURRENT_ROW) &&
(frameOptions & FRAMEOPTION_END_VALUE_PRECEDING))
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame starting from current row cannot have preceding rows"),
- parser_errposition(@4)));
+ parser_errposition(@4.begins)));
if ((frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING) &&
(frameOptions & (FRAMEOPTION_END_VALUE_PRECEDING |
FRAMEOPTION_END_CURRENT_ROW)))
ereport(ERROR,
(errcode(ERRCODE_WINDOWING_ERROR),
errmsg("frame starting from following row cannot have preceding rows"),
- parser_errposition(@4)));
+ parser_errposition(@4.begins)));
n1->frameOptions = frameOptions;
n1->endOffset = n2->startOffset;
$$ = n1;
@@ -11272,7 +11272,7 @@ func_arg_expr: a_expr
na->name = $1;
na->arg = (Expr *) $3;
na->argnumber = -1; /* until determined */
- na->location = @1;
+ na->location = @1.begins;
$$ = (Node *) na;
}
;
@@ -11283,15 +11283,15 @@ type_list: Typename { $$ = list_make1($1); }
array_expr: '[' expr_list ']'
{
- $$ = makeAArrayExpr($2, @1);
+ $$ = makeAArrayExpr($2, @1.begins);
}
| '[' array_expr_list ']'
{
- $$ = makeAArrayExpr($2, @1);
+ $$ = makeAArrayExpr($2, @1.begins);
}
| '[' ']'
{
- $$ = makeAArrayExpr(NIL, @1);
+ $$ = makeAArrayExpr(NIL, @1.begins);
}
;
@@ -11303,7 +11303,7 @@ array_expr_list: array_expr { $$ = list_make1($1); }
extract_list:
extract_arg FROM a_expr
{
- $$ = list_make2(makeStringConst($1, @1), $3);
+ $$ = list_make2(makeStringConst($1, @1.begins, @1.length), $3);
}
| /*EMPTY*/ { $$ = NIL; }
;
@@ -11388,9 +11388,9 @@ substr_list:
* which it is likely to do if the second argument
* is unknown or doesn't have an implicit cast to int4.
*/
- $$ = list_make3($1, makeIntConst(1, -1),
+ $$ = list_make3($1, makeIntConst(1, -1, -1),
makeTypeCast($2,
- SystemTypeName("int4"), -1));
+ SystemTypeName("int4"), -1, -1));
}
| expr_list
{
@@ -11436,7 +11436,7 @@ case_expr: CASE case_arg when_clause_list case_default END_P
c->arg = (Expr *) $2;
c->args = $3;
c->defresult = (Expr *) $4;
- c->location = @1;
+ c->location = @1.begins;
$$ = (Node *)c;
}
;
@@ -11453,7 +11453,7 @@ when_clause:
CaseWhen *w = makeNode(CaseWhen);
w->expr = (Expr *) $2;
w->result = (Expr *) $4;
- w->location = @1;
+ w->location = @1.begins;
$$ = (Node *)w;
}
;
@@ -11469,11 +11469,11 @@ case_arg: a_expr { $$ = $1; }
columnref: ColId
{
- $$ = makeColumnRef($1, NIL, @1, yyscanner);
+ $$ = makeColumnRef($1, NIL, @1.begins, yyscanner);
}
| ColId indirection
{
- $$ = makeColumnRef($1, $2, @1, yyscanner);
+ $$ = makeColumnRef($1, $2, @1.begins, yyscanner);
}
;
@@ -11528,7 +11528,7 @@ ctext_expr:
| DEFAULT
{
SetToDefault *n = makeNode(SetToDefault);
- n->location = @1;
+ n->location = @1.begins;
$$ = (Node *) n;
}
;
@@ -11564,7 +11564,7 @@ target_el: a_expr AS ColLabel
$$->name = $3;
$$->indirection = NIL;
$$->val = (Node *)$1;
- $$->location = @1;
+ $$->location = @1.begins;
}
/*
* We support omitting AS only for column labels that aren't
@@ -11580,7 +11580,7 @@ target_el: a_expr AS ColLabel
$$->name = $2;
$$->indirection = NIL;
$$->val = (Node *)$1;
- $$->location = @1;
+ $$->location = @1.begins;
}
| a_expr
{
@@ -11588,19 +11588,19 @@ target_el: a_expr AS ColLabel
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)$1;
- $$->location = @1;
+ $$->location = @1.begins;
}
| '*'
{
ColumnRef *n = makeNode(ColumnRef);
n->fields = list_make1(makeNode(A_Star));
- n->location = @1;
+ n->location = @1.begins;
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)n;
- $$->location = @1;
+ $$->location = @1.begins;
}
;
@@ -11626,12 +11626,12 @@ qualified_name_list:
qualified_name:
ColId
{
- $$ = makeRangeVar(NULL, $1, @1);
+ $$ = makeRangeVar(NULL, $1, @1.begins);
}
| ColId indirection
{
check_qualified_name($2, yyscanner);
- $$ = makeRangeVar(NULL, NULL, @1);
+ $$ = makeRangeVar(NULL, NULL, @1.begins);
switch (list_length($2))
{
case 1:
@@ -11649,7 +11649,7 @@ qualified_name:
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper qualified name (too many dotted names): %s",
NameListToString(lcons(makeString($1), $2))),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
break;
}
}
@@ -11699,19 +11699,19 @@ func_name: type_function_name
*/
AexprConst: Iconst
{
- $$ = makeIntConst($1, @1);
+ $$ = makeIntConst($1, @1.begins, @1.length);
}
| FCONST
{
- $$ = makeFloatConst($1, @1);
+ $$ = makeFloatConst($1, @1.begins, @1.length);
}
| Sconst
{
- $$ = makeStringConst($1, @1);
+ $$ = makeStringConst($1, @1.begins, @1.length);
}
| BCONST
{
- $$ = makeBitStringConst($1, @1);
+ $$ = makeBitStringConst($1, @1.begins, @1.length);
}
| XCONST
{
@@ -11720,14 +11720,14 @@ AexprConst: Iconst
* a <general literal> shall not be a
* <bit string literal> or a <hex string literal>.
*/
- $$ = makeBitStringConst($1, @1);
+ $$ = makeBitStringConst($1, @1.begins, @1.length);
}
| func_name Sconst
{
/* generic type 'literal' syntax */
TypeName *t = makeTypeNameFromNameList($1);
- t->location = @1;
- $$ = makeStringConstCast($2, @2, t);
+ t->location = @1.begins;
+ $$ = makeStringConstCast($2, @2.begins, @1.length, t);
}
| func_name '(' func_arg_list ')' Sconst
{
@@ -11751,18 +11751,18 @@ AexprConst: Iconst
parser_errposition(arg->location)));
}
t->typmods = $3;
- t->location = @1;
- $$ = makeStringConstCast($5, @5, t);
+ t->location = @1.begins;
+ $$ = makeStringConstCast($5, @5.begins, @5.length, t);
}
| ConstTypename Sconst
{
- $$ = makeStringConstCast($2, @2, $1);
+ $$ = makeStringConstCast($2, @2.begins, @2.length, $1);
}
| ConstInterval Sconst opt_interval
{
TypeName *t = $1;
t->typmods = $3;
- $$ = makeStringConstCast($2, @2, t);
+ $$ = makeStringConstCast($2, @2.begins, @2.length, t);
}
| ConstInterval '(' Iconst ')' Sconst opt_interval
{
@@ -11773,25 +11773,25 @@ AexprConst: Iconst
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("interval precision specified twice"),
- parser_errposition(@1)));
- t->typmods = lappend($6, makeIntConst($3, @3));
+ parser_errposition(@1.begins)));
+ t->typmods = lappend($6, makeIntConst($3, @3.begins, @3.length));
}
else
- t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
- makeIntConst($3, @3));
- $$ = makeStringConstCast($5, @5, t);
+ t->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1, -1),
+ makeIntConst($3, @3.begins, @3.length));
+ $$ = makeStringConstCast($5, @5.begins, @5.length, t);
}
| TRUE_P
{
- $$ = makeBoolAConst(TRUE, @1);
+ $$ = makeBoolAConst(TRUE, @1.begins, @1.length);
}
| FALSE_P
{
- $$ = makeBoolAConst(FALSE, @1);
+ $$ = makeBoolAConst(FALSE, @1.begins, @1.length);
}
| NULL_P
{
- $$ = makeNullAConst(@1);
+ $$ = makeNullAConst(@1.begins, @1.length);
}
;
@@ -12352,100 +12352,106 @@ makeColumnRef(char *colname, List *indirection,
}
static Node *
-makeTypeCast(Node *arg, TypeName *typename, int location)
+makeTypeCast(Node *arg, TypeName *typename, int location, int length)
{
TypeCast *n = makeNode(TypeCast);
n->arg = arg;
n->typeName = typename;
n->location = location;
+ n->tok_len = length;
return (Node *) n;
}
static Node *
-makeStringConst(char *str, int location)
+makeStringConst(char *str, int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = str;
n->location = location;
+ n->tok_len = length;
return (Node *)n;
}
static Node *
-makeStringConstCast(char *str, int location, TypeName *typename)
+makeStringConstCast(char *str, int location, int length, TypeName *typename)
{
- Node *s = makeStringConst(str, location);
+ Node *s = makeStringConst(str, location, length);
- return makeTypeCast(s, typename, -1);
+ return makeTypeCast(s, typename, -1, -1);
}
static Node *
-makeIntConst(int val, int location)
+makeIntConst(int val, int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Integer;
n->val.val.ival = val;
n->location = location;
+ n->tok_len = length;
return (Node *)n;
}
static Node *
-makeFloatConst(char *str, int location)
+makeFloatConst(char *str, int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Float;
n->val.val.str = str;
n->location = location;
+ n->tok_len = length;
return (Node *)n;
}
static Node *
-makeBitStringConst(char *str, int location)
+makeBitStringConst(char *str, int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_BitString;
n->val.val.str = str;
n->location = location;
+ n->tok_len = length;
return (Node *)n;
}
static Node *
-makeNullAConst(int location)
+makeNullAConst(int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Null;
n->location = location;
+ n->tok_len = length;
return (Node *)n;
}
static Node *
-makeAConst(Value *v, int location)
+makeAConst(Value *v, int location, int length)
{
Node *n;
switch (v->type)
{
case T_Float:
- n = makeFloatConst(v->val.str, location);
+ n = makeFloatConst(v->val.str, location, length);
break;
case T_Integer:
- n = makeIntConst(v->val.ival, location);
+ n = makeIntConst(v->val.ival, location, length);
break;
case T_String:
default:
- n = makeStringConst(v->val.str, location);
+ n = makeStringConst(v->val.str, location, length);
break;
}
@@ -12456,15 +12462,16 @@ makeAConst(Value *v, int location)
* Create an A_Const string node and put it inside a boolean cast.
*/
static Node *
-makeBoolAConst(bool state, int location)
+makeBoolAConst(bool state, int location, int length)
{
A_Const *n = makeNode(A_Const);
n->val.type = T_String;
n->val.val.str = (state ? "t" : "f");
n->location = location;
+ n->tok_len = length;
- return makeTypeCast((Node *)n, SystemTypeName("bool"), -1);
+ return makeTypeCast((Node *)n, SystemTypeName("bool"), -1, -1);
}
/* makeOverlaps()
@@ -12696,7 +12703,7 @@ SystemTypeName(char *name)
* until we know what the desired type is.
*/
static Node *
-doNegate(Node *n, int location)
+doNegate(Node *n, int location, int length)
{
if (IsA(n, A_Const))
{
@@ -12704,15 +12711,19 @@ doNegate(Node *n, int location)
/* report the constant's location as that of the '-' sign */
con->location = location;
+ /* TODO: A more elegant job of calculating length than this */
+ /*con->tok_len = length; */
if (con->val.type == T_Integer)
{
con->val.val.ival = -con->val.val.ival;
+ con->tok_len = (con->val.val.ival==0? 2: ((int) log10(fabs(con->val.val.ival)) + 2 ) );
return n;
}
if (con->val.type == T_Float)
{
doNegateFloat(&con->val);
+ con->tok_len = strlen(con->val.val.str);
return n;
}
}
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index e8177bc..6aaa4d2 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -1073,7 +1073,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (l_colvar->vartype != outcoltype)
l_node = coerce_type(pstate, (Node *) l_colvar, l_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
else if (l_colvar->vartypmod != outcoltypmod)
l_node = (Node *) makeRelabelType((Expr *) l_colvar,
outcoltype, outcoltypmod,
@@ -1085,7 +1085,7 @@ buildMergedJoinVar(ParseState *pstate, JoinType jointype,
if (r_colvar->vartype != outcoltype)
r_node = coerce_type(pstate, (Node *) r_colvar, r_colvar->vartype,
outcoltype, outcoltypmod,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
else if (r_colvar->vartypmod != outcoltypmod)
r_node = (Node *) makeRelabelType((Expr *) r_colvar,
outcoltype, outcoltypmod,
@@ -1965,7 +1965,7 @@ addTargetToSortList(ParseState *pstate, TargetEntry *tle,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
restype = TEXTOID;
}
@@ -2108,7 +2108,7 @@ addTargetToGroupList(ParseState *pstate, TargetEntry *tle,
restype, TEXTOID, -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
restype = TEXTOID;
}
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index a461ac9..cfc5106 100644
--- a/src/backend/parser/parse_coerce.c
+++ b/src/backend/parser/parse_coerce.c
@@ -76,7 +76,8 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
CoercionForm cformat,
- int location)
+ int location,
+ int tok_len)
{
Node *result;
@@ -85,7 +86,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
result = coerce_type(pstate, expr, exprtype,
targettype, targettypmod,
- ccontext, cformat, location);
+ ccontext, cformat, location, tok_len);
/*
* If the target is a fixed-length type, it may need a length coercion as
@@ -127,7 +128,7 @@ coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype,
Node *
coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat, int location)
+ CoercionContext ccontext, CoercionForm cformat, int location, int tok_len)
{
Node *result;
CoercionPathType pathtype;
@@ -255,11 +256,20 @@ coerce_type(ParseState *pstate, Node *node,
newcon->constisnull = con->constisnull;
/* Use the leftmost of the constant's and coercion's locations */
if (location < 0)
+ {
newcon->location = con->location;
+ newcon->tok_len = con->tok_len;
+ }
else if (con->location >= 0 && con->location < location)
+ {
newcon->location = con->location;
+ newcon->tok_len = con->tok_len;
+ }
else
+ {
newcon->location = location;
+ newcon->tok_len = tok_len;
+ }
/*
* Set up to point at the constant's text if the input routine throws
@@ -325,7 +335,7 @@ coerce_type(ParseState *pstate, Node *node,
newcoll->arg = (Expr *)
coerce_type(pstate, (Node *) coll->arg,
inputTypeId, targetTypeId, targetTypeMod,
- ccontext, cformat, location);
+ ccontext, cformat, location, tok_len);
newcoll->collOid = coll->collOid;
newcoll->location = coll->location;
return (Node *) newcoll;
@@ -946,7 +956,7 @@ coerce_record_to_complex(ParseState *pstate, Node *node,
tupdesc->attrs[i]->atttypmod,
ccontext,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (cexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
@@ -1006,7 +1016,7 @@ coerce_to_boolean(ParseState *pstate, Node *node,
BOOLOID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1053,7 +1063,7 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
targetTypeId, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (newnode == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -1253,7 +1263,7 @@ coerce_to_common_type(ParseState *pstate, Node *node,
return node; /* no work */
if (can_coerce_type(1, &inputTypeId, &targetTypeId, COERCION_IMPLICIT))
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1,
- COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1);
+ COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, -1, -1);
else
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 79328c9..22e67f2 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -125,7 +125,7 @@ transformExpr(ParseState *pstate, Node *expr)
A_Const *con = (A_Const *) expr;
Value *val = &con->val;
- result = (Node *) make_const(pstate, val, con->location);
+ result = (Node *) make_const(pstate, val, con->location, con->tok_len);
break;
}
@@ -1347,6 +1347,7 @@ transformCaseExpr(ParseState *pstate, CaseExpr *c)
n->val.type = T_Null;
n->location = -1;
+ n->tok_len = -1;
defresult = (Node *) n;
}
newc->defresult = (Expr *) transformExpr(pstate, defresult);
@@ -1663,7 +1664,7 @@ transformArrayExpr(ParseState *pstate, A_ArrayExpr *a,
typmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST,
- -1);
+ -1, -1);
if (newe == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
@@ -1942,7 +1943,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
TEXTOID, targetType, targetTypmod,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
@@ -2085,7 +2086,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
Oid inputType = exprType(expr);
Oid targetType;
int32 targetTypmod;
- int location;
+ int location, tok_len;
typenameTypeIdAndMod(pstate, tc->typeName, &targetType, &targetTypmod);
@@ -2098,6 +2099,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
* name (this can happen in TypeName 'string' syntax, for instance).
*/
location = tc->location;
+ tok_len = tc->tok_len;
if (location < 0)
location = tc->typeName->location;
@@ -2105,7 +2107,7 @@ transformTypeCast(ParseState *pstate, TypeCast *tc)
targetType, targetTypmod,
COERCION_EXPLICIT,
COERCE_EXPLICIT_CAST,
- location);
+ location, tok_len);
if (result == NULL)
ereport(ERROR,
(errcode(ERRCODE_CANNOT_COERCE),
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 75f1e20..b7f9b8d 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -222,7 +222,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
*/
return coerce_type(pstate, linitial(fargs),
actual_arg_types[0], rettype, -1,
- COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location);
+ COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location, -1);
}
else if (fdresult == FUNCDETAIL_NORMAL)
{
@@ -1275,7 +1275,7 @@ make_fn_arguments(ParseState *pstate,
declared_arg_types[i], -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
na->arg = (Expr *) node;
}
else
@@ -1286,7 +1286,7 @@ make_fn_arguments(ParseState *pstate,
declared_arg_types[i], -1,
COERCION_IMPLICIT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
lfirst(current_fargs) = node;
}
}
diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c
index 7b5c040..2d0e610 100644
--- a/src/backend/parser/parse_node.c
+++ b/src/backend/parser/parse_node.c
@@ -335,7 +335,7 @@ transformArraySubscripts(ParseState *pstate,
INT4OID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -362,7 +362,7 @@ transformArraySubscripts(ParseState *pstate,
INT4OID, -1,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (subexpr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -386,7 +386,7 @@ transformArraySubscripts(ParseState *pstate,
typeneeded, arrayTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (newFrom == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -434,7 +434,7 @@ transformArraySubscripts(ParseState *pstate,
* too many examples that fail if we try.
*/
Const *
-make_const(ParseState *pstate, Value *value, int location)
+make_const(ParseState *pstate, Value *value, int location, int tok_len)
{
Const *con;
Datum val;
@@ -533,6 +533,7 @@ make_const(ParseState *pstate, Value *value, int location)
true,
false);
con->location = location;
+ con->tok_len = tok_len;
return con;
default:
@@ -548,6 +549,7 @@ make_const(ParseState *pstate, Value *value, int location)
false,
typebyval);
con->location = location;
+ con->tok_len = tok_len;
return con;
}
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 2f2e87f..651f72a 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -478,7 +478,7 @@ transformAssignedExpr(ParseState *pstate,
attrtype, attrtypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
@@ -722,7 +722,7 @@ transformAssignmentIndirection(ParseState *pstate,
targetTypeId, targetTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (result == NULL)
{
if (targetIsArray)
@@ -822,7 +822,7 @@ transformAssignmentSubscripts(ParseState *pstate,
targetTypeId, targetTypMod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
/* probably shouldn't fail, but check */
if (result == NULL)
ereport(ERROR,
diff --git a/src/backend/parser/scan.l b/src/backend/parser/scan.l
index 12db190..32744fd 100644
--- a/src/backend/parser/scan.l
+++ b/src/backend/parser/scan.l
@@ -73,12 +73,14 @@ bool standard_conforming_strings = true;
* this should be done in the first such rule, else yylloc will point
* into the middle of the token.
*/
-#define SET_YYLLOC() (*(yylloc) = yytext - yyextra->scanbuf)
+#define SET_YYLLOC_BEGINS() yylloc->length = 0; yylloc->begins = yytext - yyextra->scanbuf;
+#define SET_YYLLOC_LEN() yylloc->length += strlen(yytext);
+
/*
* Advance yylloc by the given number of bytes.
*/
-#define ADVANCE_YYLLOC(delta) ( *(yylloc) += (delta) )
+#define ADVANCE_YYLLOC(delta) ( yylloc->begins += (delta) )
#define startlit() ( yyextra->literallen = 0 )
static void addlit(char *ytext, int yleng, core_yyscan_t yyscanner);
@@ -94,7 +96,7 @@ static void addunicode(pg_wchar c, yyscan_t yyscanner);
#define yyerror(msg) scanner_yyerror(msg, yyscanner)
-#define lexer_errposition() scanner_errposition(*(yylloc), yyscanner)
+#define lexer_errposition() scanner_errposition(yylloc->begins, yyscanner)
static void check_string_escape_warning(unsigned char ychar, core_yyscan_t yyscanner);
static void check_escape_warning(core_yyscan_t yyscanner);
@@ -377,17 +379,19 @@ other .
{xcstart} {
/* Set location in case of syntax error in comment */
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yyextra->xcdepth = 0;
BEGIN(xc);
/* Put back any characters past slash-star; see above */
yyless(2);
+ SET_YYLLOC_LEN();
}
<xc>{xcstart} {
(yyextra->xcdepth)++;
/* Put back any characters past slash-star; see above */
yyless(2);
+ SET_YYLLOC_LEN();
}
<xc>{xcstop} {
@@ -395,6 +399,7 @@ other .
BEGIN(INITIAL);
else
(yyextra->xcdepth)--;
+ SET_YYLLOC_LEN();
}
<xc>{xcinside} {
@@ -418,21 +423,24 @@ other .
* In the meantime, place a leading "b" on the string
* to mark it for the input routine as a binary string.
*/
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
BEGIN(xb);
startlit();
addlitchar('b', yyscanner);
+ SET_YYLLOC_LEN();
}
<xb>{quotestop} |
<xb>{quotefail} {
yyless(1);
BEGIN(INITIAL);
yylval->str = litbufdup(yyscanner);
+ SET_YYLLOC_LEN();
return BCONST;
}
<xh>{xhinside} |
<xb>{xbinside} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xh>{quotecontinue} |
<xb>{quotecontinue} {
@@ -447,16 +455,18 @@ other .
* In the meantime, place a leading "x" on the string
* to mark it for the input routine as a hex string.
*/
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
BEGIN(xh);
startlit();
addlitchar('x', yyscanner);
+ SET_YYLLOC_LEN();
}
<xh>{quotestop} |
<xh>{quotefail} {
yyless(1);
BEGIN(INITIAL);
yylval->str = litbufdup(yyscanner);
+ SET_YYLLOC_LEN();
return XCONST;
}
<xh><<EOF>> { yyerror("unterminated hexadecimal string literal"); }
@@ -468,7 +478,8 @@ other .
*/
const ScanKeyword *keyword;
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
yyless(1); /* eat only 'n' this time */
keyword = ScanKeywordLookup("nchar",
@@ -490,22 +501,25 @@ other .
{xqstart} {
yyextra->warn_on_first_escape = true;
yyextra->saw_non_ascii = false;
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
if (standard_conforming_strings)
BEGIN(xq);
else
BEGIN(xe);
startlit();
+ yylloc->length = 0;
+ SET_YYLLOC_LEN();
}
{xestart} {
yyextra->warn_on_first_escape = false;
yyextra->saw_non_ascii = false;
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
BEGIN(xe);
startlit();
+ SET_YYLLOC_LEN();
}
{xusstart} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
if (!standard_conforming_strings)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -513,6 +527,7 @@ other .
errdetail("String constants with Unicode escapes cannot be used when standard_conforming_strings is off."),
lexer_errposition()));
BEGIN(xus);
+ SET_YYLLOC_LEN();
startlit();
}
<xq,xe>{quotestop} |
@@ -528,6 +543,7 @@ other .
yyextra->literallen,
false);
yylval->str = litbufdup(yyscanner);
+ SET_YYLLOC_LEN();
return SCONST;
}
<xus>{xusstop1} {
@@ -535,21 +551,26 @@ other .
yyless(1);
BEGIN(INITIAL);
yylval->str = litbuf_udeescape('\\', yyscanner);
+ SET_YYLLOC_LEN();
return SCONST;
}
<xus>{xusstop2} {
BEGIN(INITIAL);
yylval->str = litbuf_udeescape(yytext[yyleng-2], yyscanner);
+ SET_YYLLOC_LEN();
return SCONST;
}
<xq,xe,xus>{xqdouble} {
addlitchar('\'', yyscanner);
+ SET_YYLLOC_LEN();
}
<xq,xus>{xqinside} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xe>{xeinside} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xe>{xeunicode} {
pg_wchar c = strtoul(yytext+2, NULL, 16);
@@ -565,6 +586,7 @@ other .
yyerror("invalid Unicode surrogate pair");
else
addunicode(c, yyscanner);
+ SET_YYLLOC_LEN();
}
<xeu>{xeunicode} {
pg_wchar c = strtoul(yytext+2, NULL, 16);
@@ -577,6 +599,7 @@ other .
addunicode(c, yyscanner);
BEGIN(xe);
+ SET_YYLLOC_LEN();
}
<xeu>. { yyerror("invalid Unicode surrogate pair"); }
<xeu>\n { yyerror("invalid Unicode surrogate pair"); }
@@ -603,6 +626,7 @@ other .
check_string_escape_warning(yytext[1], yyscanner);
addlitchar(unescape_single_char(yytext[1], yyscanner),
yyscanner);
+ SET_YYLLOC_LEN();
}
<xe>{xeoctesc} {
unsigned char c = strtoul(yytext+1, NULL, 8);
@@ -611,6 +635,7 @@ other .
addlitchar(c, yyscanner);
if (c == '\0' || IS_HIGHBIT_SET(c))
yyextra->saw_non_ascii = true;
+ SET_YYLLOC_LEN();
}
<xe>{xehexesc} {
unsigned char c = strtoul(yytext+2, NULL, 16);
@@ -619,6 +644,7 @@ other .
addlitchar(c, yyscanner);
if (c == '\0' || IS_HIGHBIT_SET(c))
yyextra->saw_non_ascii = true;
+ SET_YYLLOC_LEN();
}
<xq,xe,xus>{quotecontinue} {
/* ignore */
@@ -626,19 +652,23 @@ other .
<xe>. {
/* This is only needed for \ just before EOF */
addlitchar(yytext[0], yyscanner);
+ SET_YYLLOC_LEN();
}
<xq,xe,xus><<EOF>> { yyerror("unterminated quoted string"); }
{dolqdelim} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yyextra->dolqstart = pstrdup(yytext);
BEGIN(xdolq);
startlit();
+ yylloc->length = 0;
+ SET_YYLLOC_LEN();
}
{dolqfailed} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
/* throw back all but the initial "$" */
yyless(1);
+ SET_YYLLOC_LEN();
/* and treat it as {other} */
return yytext[0];
}
@@ -649,6 +679,7 @@ other .
yyextra->dolqstart = NULL;
BEGIN(INITIAL);
yylval->str = litbufdup(yyscanner);
+ SET_YYLLOC_LEN();
return SCONST;
}
else
@@ -660,29 +691,35 @@ other .
*/
addlit(yytext, yyleng-1, yyscanner);
yyless(yyleng-1);
+ SET_YYLLOC_LEN();
}
}
<xdolq>{dolqinside} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xdolq>{dolqfailed} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xdolq>. {
/* This is only needed for $ inside the quoted text */
addlitchar(yytext[0], yyscanner);
+ SET_YYLLOC_LEN();
}
<xdolq><<EOF>> { yyerror("unterminated dollar-quoted string"); }
{xdstart} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
BEGIN(xd);
startlit();
+ SET_YYLLOC_LEN();
}
{xuistart} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
BEGIN(xui);
startlit();
+ SET_YYLLOC_LEN();
}
<xd>{xdstop} {
char *ident;
@@ -694,6 +731,7 @@ other .
if (yyextra->literallen >= NAMEDATALEN)
truncate_identifier(ident, yyextra->literallen, true);
yylval->str = ident;
+ SET_YYLLOC_LEN();
return IDENT;
}
<xui>{xuistop1} {
@@ -708,6 +746,7 @@ other .
yylval->str = ident;
/* throw back all but the quote */
yyless(1);
+ SET_YYLLOC_LEN();
return IDENT;
}
<xui>{xuistop2} {
@@ -720,45 +759,53 @@ other .
if (yyextra->literallen >= NAMEDATALEN)
truncate_identifier(ident, yyextra->literallen, true);
yylval->str = ident;
+ SET_YYLLOC_LEN();
return IDENT;
}
<xd,xui>{xddouble} {
addlitchar('"', yyscanner);
+ SET_YYLLOC_LEN();
}
<xd,xui>{xdinside} {
addlit(yytext, yyleng, yyscanner);
+ SET_YYLLOC_LEN();
}
<xd,xui><<EOF>> { yyerror("unterminated quoted identifier"); }
{xufailed} {
char *ident;
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
/* throw back all but the initial u/U */
yyless(1);
/* and treat it as {identifier} */
ident = downcase_truncate_identifier(yytext, yyleng, true);
yylval->str = ident;
+ SET_YYLLOC_LEN();
return IDENT;
}
{typecast} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return TYPECAST;
}
{dot_dot} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return DOT_DOT;
}
{colon_equals} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return COLON_EQUALS;
}
{self} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return yytext[0];
}
@@ -808,7 +855,7 @@ other .
nchars--; /* else remove the +/-, and check again */
}
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
if (nchars < yyleng)
{
@@ -839,33 +886,39 @@ other .
yylval->str = pstrdup("<>");
else
yylval->str = pstrdup(yytext);
+ SET_YYLLOC_LEN();
return Op;
}
{param} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yylval->ival = atol(yytext + 1);
+ SET_YYLLOC_LEN();
return PARAM;
}
{integer} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return process_integer_literal(yytext, yylval);
}
{decimal} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yylval->str = pstrdup(yytext);
+ SET_YYLLOC_LEN();
return FCONST;
}
{decimalfail} {
/* throw back the .., and treat as integer */
yyless(yyleng-2);
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return process_integer_literal(yytext, yylval);
}
{real} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yylval->str = pstrdup(yytext);
+ SET_YYLLOC_LEN();
return FCONST;
}
{realfail1} {
@@ -876,15 +929,17 @@ other .
* syntax error anyway, we don't bother to distinguish.
*/
yyless(yyleng-1);
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yylval->str = pstrdup(yytext);
+ SET_YYLLOC_LEN();
return FCONST;
}
{realfail2} {
/* throw back the [Ee][+-], and proceed as above */
yyless(yyleng-2);
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
yylval->str = pstrdup(yytext);
+ SET_YYLLOC_LEN();
return FCONST;
}
@@ -893,8 +948,9 @@ other .
const ScanKeyword *keyword;
char *ident;
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ yylloc->length = 0;
/* Is it a keyword? */
keyword = ScanKeywordLookup(yytext,
yyextra->keywords,
@@ -902,6 +958,7 @@ other .
if (keyword != NULL)
{
yylval->keyword = keyword->name;
+ SET_YYLLOC_LEN();
return keyword->value;
}
@@ -911,16 +968,19 @@ other .
*/
ident = downcase_truncate_identifier(yytext, yyleng, true);
yylval->str = ident;
+ SET_YYLLOC_LEN();
return IDENT;
}
{other} {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
return yytext[0];
}
<<EOF>> {
- SET_YYLLOC();
+ SET_YYLLOC_BEGINS();
+ SET_YYLLOC_LEN();
yyterminate();
}
@@ -982,7 +1042,7 @@ scanner_errposition(int location, core_yyscan_t yyscanner)
void
scanner_yyerror(const char *message, core_yyscan_t yyscanner)
{
- const char *loc = yyextra->scanbuf + *yylloc;
+ const char *loc = yyextra->scanbuf + yylloc->begins;
if (*loc == YY_END_OF_BUFFER_CHAR)
{
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 3b31108..2c9bc38 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -1023,7 +1023,7 @@ build_column_default(Relation rel, int attrno)
atttype, atttypmod,
COERCION_ASSIGNMENT,
COERCE_IMPLICIT_CAST,
- -1);
+ -1, -1);
if (expr == NULL)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index af6565e..ebbceaf 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -252,6 +252,7 @@ typedef struct A_Const
NodeTag type;
Value val; /* value (includes type info, see value.h) */
int location; /* token location, or -1 if unknown */
+ int tok_len; /* token length (in bytes) */
} A_Const;
/*
@@ -263,6 +264,7 @@ typedef struct TypeCast
Node *arg; /* the expression being casted */
TypeName *typeName; /* the target type */
int location; /* token location, or -1 if unknown */
+ int tok_len; /* token length (in bytes) */
} TypeCast;
/*
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index cedf022..c170060 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -170,6 +170,7 @@ typedef struct Const
* in the Datum. If false, then the Datum
* contains a pointer to the information. */
int location; /* token location, or -1 if unknown */
+ int tok_len; /* token length (in bytes) */
} Const;
/* ----------------
diff --git a/src/include/parser/parse_coerce.h b/src/include/parser/parse_coerce.h
index ceaff2f..85f3fdd 100644
--- a/src/include/parser/parse_coerce.h
+++ b/src/include/parser/parse_coerce.h
@@ -40,12 +40,13 @@ extern Node *coerce_to_target_type(ParseState *pstate,
Oid targettype, int32 targettypmod,
CoercionContext ccontext,
CoercionForm cformat,
- int location);
+ int location,
+ int tok_len);
extern bool can_coerce_type(int nargs, Oid *input_typeids, Oid *target_typeids,
CoercionContext ccontext);
extern Node *coerce_type(ParseState *pstate, Node *node,
Oid inputTypeId, Oid targetTypeId, int32 targetTypeMod,
- CoercionContext ccontext, CoercionForm cformat, int location);
+ CoercionContext ccontext, CoercionForm cformat, int location, int tok_len);
extern Node *coerce_to_domain(Node *arg, Oid baseTypeId, int32 baseTypeMod,
Oid typeId,
CoercionForm cformat, int location,
diff --git a/src/include/parser/parse_node.h b/src/include/parser/parse_node.h
index 0ca7914..fde2a93 100644
--- a/src/include/parser/parse_node.h
+++ b/src/include/parser/parse_node.h
@@ -148,6 +148,6 @@ extern ArrayRef *transformArraySubscripts(ParseState *pstate,
int32 arrayTypMod,
List *indirection,
Node *assignFrom);
-extern Const *make_const(ParseState *pstate, Value *value, int location);
+extern Const *make_const(ParseState *pstate, Value *value, int location, int tok_len);
#endif /* PARSE_NODE_H */
diff --git a/src/include/parser/scanner.h b/src/include/parser/scanner.h
index 2a88e97..e12ccf4 100644
--- a/src/include/parser/scanner.h
+++ b/src/include/parser/scanner.h
@@ -36,12 +36,16 @@ typedef union core_YYSTYPE
/*
* We track token locations in terms of byte offsets from the start of the
* source string, not the column number/line number representation that
- * bison uses by default. Also, to minimize overhead we track only one
- * location (usually the first token location) for each construct, not
- * the beginning and ending locations as bison does by default. It's
- * therefore sufficient to make YYLTYPE an int.
+ * bison uses by default. We track the beginning of the token, as well
+ * as its total length.
*/
-#define YYLTYPE int
+typedef struct my_yyltype
+{
+ int begins;
+ int length;
+} my_yyltype;
+
+#define YYLTYPE my_yyltype
/*
* Another important component of the scanner's API is the token code numbers.
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 8c4c2f7..ce932c4 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -367,14 +367,14 @@ pl_block : decl_sect K_BEGIN proc_sect exception_sect K_END opt_label
new = palloc0(sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1.label;
new->n_initvars = $1.n_initvars;
new->initvarnos = $1.initvarnos;
new->body = $3;
new->exceptions = $4;
- check_labels($1.label, $6, @6);
+ check_labels($1.label, $6, @6.begins);
plpgsql_ns_pop();
$$ = (PLpgSQL_stmt *)new;
@@ -436,7 +436,7 @@ decl_stmt : decl_statement
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("block label must be placed before DECLARE, not after"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
;
@@ -457,7 +457,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("collations are not supported by type %s",
format_type_be($3->typoid)),
- parser_errposition(@4)));
+ parser_errposition(@4.begins)));
$3->collation = $4;
}
@@ -471,7 +471,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row or record variable cannot be CONSTANT"),
- parser_errposition(@2)));
+ parser_errposition(@2.begins)));
}
if ($5)
{
@@ -481,7 +481,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("row or record variable cannot be NOT NULL"),
- parser_errposition(@4)));
+ parser_errposition(@4.begins)));
}
if ($6 != NULL)
@@ -492,7 +492,7 @@ decl_statement : decl_varname decl_const decl_datatype decl_collate decl_notnull
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("default value for row or record variable is not supported"),
- parser_errposition(@5)));
+ parser_errposition(@5.begins)));
}
}
| decl_varname K_ALIAS K_FOR decl_aliasitem ';'
@@ -584,7 +584,7 @@ decl_cursor_args :
new = palloc0(sizeof(PLpgSQL_row));
new->dtype = PLPGSQL_DTYPE_ROW;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->rowtupdesc = NULL;
new->nfields = list_length($2);
new->fieldnames = palloc(new->nfields * sizeof(char *));
@@ -638,7 +638,7 @@ decl_aliasitem : T_WORD
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("variable \"%s\" does not exist",
$1.ident),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = nsi;
}
| T_CWORD
@@ -664,7 +664,7 @@ decl_aliasitem : T_WORD
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("variable \"%s\" does not exist",
NameListToString($1.idents)),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = nsi;
}
;
@@ -672,7 +672,7 @@ decl_aliasitem : T_WORD
decl_varname : T_WORD
{
$$.name = $1.ident;
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1.begins);
/*
* Check to make sure name isn't already declared
* in the current block.
@@ -685,7 +685,7 @@ decl_varname : T_WORD
| unreserved_keyword
{
$$.name = pstrdup($1);
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1.begins);
/*
* Check to make sure name isn't already declared
* in the current block.
@@ -819,7 +819,7 @@ stmt_perform : K_PERFORM expr_until_semi
new = palloc0(sizeof(PLpgSQL_stmt_perform));
new->cmd_type = PLPGSQL_STMT_PERFORM;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->expr = $2;
$$ = (PLpgSQL_stmt *)new;
@@ -832,7 +832,7 @@ stmt_assign : assign_var assign_operator expr_until_semi
new = palloc0(sizeof(PLpgSQL_stmt_assign));
new->cmd_type = PLPGSQL_STMT_ASSIGN;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->varno = $1;
new->expr = $3;
@@ -847,7 +847,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
new = palloc0(sizeof(PLpgSQL_stmt_getdiag));
new->cmd_type = PLPGSQL_STMT_GETDIAG;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->is_stacked = $2;
new->diag_items = $4;
@@ -868,7 +868,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("diagnostics item %s is not allowed in GET STACKED DIAGNOSTICS",
plpgsql_getdiag_kindname(ditem->kind)),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
break;
/* these fields are disallowed in current case */
case PLPGSQL_GETDIAG_ERROR_CONTEXT:
@@ -881,7 +881,7 @@ stmt_getdiag : K_GET getdiag_area_opt K_DIAGNOSTICS getdiag_list ';'
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("diagnostics item %s is not allowed in GET CURRENT DIAGNOSTICS",
plpgsql_getdiag_kindname(ditem->kind)),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
break;
default:
elog(ERROR, "unrecognized diagnostic item kind: %d",
@@ -962,32 +962,32 @@ getdiag_item :
getdiag_target : T_DATUM
{
- check_assignable($1.datum, @1);
+ check_assignable($1.datum, @1.begins);
if ($1.datum->dtype == PLPGSQL_DTYPE_ROW ||
$1.datum->dtype == PLPGSQL_DTYPE_REC)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("\"%s\" is not a scalar variable",
NameOfDatum(&($1))),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = $1.datum->dno;
}
| T_WORD
{
/* just to give a better message than "syntax error" */
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1.begins);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1.begins);
}
;
assign_var : T_DATUM
{
- check_assignable($1.datum, @1);
+ check_assignable($1.datum, @1.begins);
$$ = $1.datum->dno;
}
| assign_var '[' expr_until_rightbracket
@@ -1013,7 +1013,7 @@ stmt_if : K_IF expr_until_then proc_sect stmt_elsifs stmt_else K_END K_IF ';'
new = palloc0(sizeof(PLpgSQL_stmt_if));
new->cmd_type = PLPGSQL_STMT_IF;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->cond = $2;
new->then_body = $3;
new->elsif_list = $4;
@@ -1032,7 +1032,7 @@ stmt_elsifs :
PLpgSQL_if_elsif *new;
new = palloc0(sizeof(PLpgSQL_if_elsif));
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->cond = $3;
new->stmts = $4;
@@ -1052,7 +1052,7 @@ stmt_else :
stmt_case : K_CASE opt_expr_until_when case_when_list opt_case_else K_END K_CASE ';'
{
- $$ = make_case(@1, $2, $3, $4);
+ $$ = make_case(@1.begins, $2, $3, $4);
}
;
@@ -1085,7 +1085,7 @@ case_when : K_WHEN expr_until_then proc_sect
{
PLpgSQL_case_when *new = palloc(sizeof(PLpgSQL_case_when));
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->expr = $2;
new->stmts = $3;
$$ = new;
@@ -1117,7 +1117,7 @@ stmt_loop : opt_block_label K_LOOP loop_body
new = palloc0(sizeof(PLpgSQL_stmt_loop));
new->cmd_type = PLPGSQL_STMT_LOOP;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1;
new->body = $3.stmts;
@@ -1134,7 +1134,7 @@ stmt_while : opt_block_label K_WHILE expr_until_loop loop_body
new = palloc0(sizeof(PLpgSQL_stmt_while));
new->cmd_type = PLPGSQL_STMT_WHILE;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1;
new->cond = $3;
new->body = $4.stmts;
@@ -1154,7 +1154,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body
PLpgSQL_stmt_fori *new;
new = (PLpgSQL_stmt_fori *) $3;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1;
new->body = $4.stmts;
$$ = (PLpgSQL_stmt *) new;
@@ -1168,7 +1168,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body
$3->cmd_type == PLPGSQL_STMT_DYNFORS);
/* forq is the common supertype of all three */
new = (PLpgSQL_stmt_forq *) $3;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1;
new->body = $4.stmts;
$$ = (PLpgSQL_stmt *) new;
@@ -1183,7 +1183,7 @@ stmt_for : opt_block_label K_FOR for_control loop_body
for_control : for_variable K_IN
{
int tok = yylex();
- int tokloc = yylloc;
+ int tokloc = yylloc.begins;
if (tok == K_EXECUTE)
{
@@ -1201,18 +1201,18 @@ for_control : for_variable K_IN
if ($1.rec)
{
new->rec = $1.rec;
- check_assignable((PLpgSQL_datum *) new->rec, @1);
+ check_assignable((PLpgSQL_datum *) new->rec, @1.begins);
}
else if ($1.row)
{
new->row = $1.row;
- check_assignable((PLpgSQL_datum *) new->row, @1);
+ check_assignable((PLpgSQL_datum *) new->row, @1.begins);
}
else if ($1.scalar)
{
/* convert single scalar to list */
new->row = make_scalar_list1($1.name, $1.scalar,
- $1.lineno, @1);
+ $1.lineno, @1.begins);
/* no need for check_assignable */
}
else
@@ -1220,7 +1220,7 @@ for_control : for_variable K_IN
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
new->query = expr;
@@ -1254,7 +1254,7 @@ for_control : for_variable K_IN
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cursor FOR loop must have only one target variable"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
/* can't use an unbound cursor this way */
if (cursor->cursor_explicit_expr == NULL)
@@ -1344,7 +1344,7 @@ for_control : for_variable K_IN
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("integer FOR loop must have only one target variable"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
/* create loop's private variable */
fvar = (PLpgSQL_var *)
@@ -1394,18 +1394,18 @@ for_control : for_variable K_IN
if ($1.rec)
{
new->rec = $1.rec;
- check_assignable((PLpgSQL_datum *) new->rec, @1);
+ check_assignable((PLpgSQL_datum *) new->rec, @1.begins);
}
else if ($1.row)
{
new->row = $1.row;
- check_assignable((PLpgSQL_datum *) new->row, @1);
+ check_assignable((PLpgSQL_datum *) new->row, @1.begins);
}
else if ($1.scalar)
{
/* convert single scalar to list */
new->row = make_scalar_list1($1.name, $1.scalar,
- $1.lineno, @1);
+ $1.lineno, @1.begins);
/* no need for check_assignable */
}
else
@@ -1413,7 +1413,7 @@ for_control : for_variable K_IN
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("loop variable of loop over rows must be a record or row variable or list of scalar variables"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
}
new->query = expr1;
@@ -1444,7 +1444,7 @@ for_control : for_variable K_IN
for_variable : T_DATUM
{
$$.name = NameOfDatum(&($1));
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1.begins);
if ($1.datum->dtype == PLPGSQL_DTYPE_ROW)
{
$$.scalar = NULL;
@@ -1470,7 +1470,7 @@ for_variable : T_DATUM
if (tok == ',')
$$.row = read_into_scalar_list($$.name,
$$.scalar,
- @1);
+ @1.begins);
}
}
| T_WORD
@@ -1478,7 +1478,7 @@ for_variable : T_DATUM
int tok;
$$.name = $1.ident;
- $$.lineno = plpgsql_location_to_lineno(@1);
+ $$.lineno = plpgsql_location_to_lineno(@1.begins);
$$.scalar = NULL;
$$.rec = NULL;
$$.row = NULL;
@@ -1486,12 +1486,12 @@ for_variable : T_DATUM
tok = yylex();
plpgsql_push_back_token(tok);
if (tok == ',')
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1.begins);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1.begins);
}
;
@@ -1501,7 +1501,7 @@ stmt_foreach_a : opt_block_label K_FOREACH for_variable foreach_slice K_IN K_ARR
new = palloc0(sizeof(PLpgSQL_stmt_foreach_a));
new->cmd_type = PLPGSQL_STMT_FOREACH_A;
- new->lineno = plpgsql_location_to_lineno(@2);
+ new->lineno = plpgsql_location_to_lineno(@2.begins);
new->label = $1;
new->slice = $4;
new->expr = $7;
@@ -1510,24 +1510,24 @@ stmt_foreach_a : opt_block_label K_FOREACH for_variable foreach_slice K_IN K_ARR
if ($3.rec)
{
new->varno = $3.rec->dno;
- check_assignable((PLpgSQL_datum *) $3.rec, @3);
+ check_assignable((PLpgSQL_datum *) $3.rec, @3.begins);
}
else if ($3.row)
{
new->varno = $3.row->dno;
- check_assignable((PLpgSQL_datum *) $3.row, @3);
+ check_assignable((PLpgSQL_datum *) $3.row, @3.begins);
}
else if ($3.scalar)
{
new->varno = $3.scalar->dno;
- check_assignable($3.scalar, @3);
+ check_assignable($3.scalar, @3.begins);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("loop variable of FOREACH must be a known variable or list of variables"),
- parser_errposition(@3)));
+ parser_errposition(@3.begins)));
}
check_labels($1, $8.end_label, $8.end_label_location);
@@ -1554,7 +1554,7 @@ stmt_exit : exit_type opt_label opt_exitcond
new = palloc0(sizeof(PLpgSQL_stmt_exit));
new->cmd_type = PLPGSQL_STMT_EXIT;
new->is_exit = $1;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->label = $2;
new->cond = $3;
@@ -1583,17 +1583,17 @@ stmt_return : K_RETURN
if (tok_is_keyword(tok, &yylval,
K_NEXT, "next"))
{
- $$ = make_return_next_stmt(@1);
+ $$ = make_return_next_stmt(@1.begins);
}
else if (tok_is_keyword(tok, &yylval,
K_QUERY, "query"))
{
- $$ = make_return_query_stmt(@1);
+ $$ = make_return_query_stmt(@1.begins);
}
else
{
plpgsql_push_back_token(tok);
- $$ = make_return_stmt(@1);
+ $$ = make_return_stmt(@1.begins);
}
}
;
@@ -1606,7 +1606,7 @@ stmt_raise : K_RAISE
new = palloc(sizeof(PLpgSQL_stmt_raise));
new->cmd_type = PLPGSQL_STMT_RAISE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->elog_level = ERROR; /* default */
new->condname = NULL;
new->message = NULL;
@@ -1741,7 +1741,7 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
{
$$.stmts = $1;
$$.end_label = $4;
- $$.end_label_location = @4;
+ $$.end_label_location = @4.begins;
}
;
@@ -1757,7 +1757,7 @@ loop_body : proc_sect K_END K_LOOP opt_label ';'
*/
stmt_execsql : K_INSERT
{
- $$ = make_execsql_stmt(K_INSERT, @1);
+ $$ = make_execsql_stmt(K_INSERT, @1.begins);
}
| T_WORD
{
@@ -1766,8 +1766,8 @@ stmt_execsql : K_INSERT
tok = yylex();
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
- word_is_not_variable(&($1), @1);
- $$ = make_execsql_stmt(T_WORD, @1);
+ word_is_not_variable(&($1), @1.begins);
+ $$ = make_execsql_stmt(T_WORD, @1.begins);
}
| T_CWORD
{
@@ -1776,8 +1776,8 @@ stmt_execsql : K_INSERT
tok = yylex();
plpgsql_push_back_token(tok);
if (tok == '=' || tok == COLON_EQUALS || tok == '[')
- cword_is_not_variable(&($1), @1);
- $$ = make_execsql_stmt(T_CWORD, @1);
+ cword_is_not_variable(&($1), @1.begins);
+ $$ = make_execsql_stmt(T_CWORD, @1.begins);
}
;
@@ -1795,7 +1795,7 @@ stmt_dynexecute : K_EXECUTE
new = palloc(sizeof(PLpgSQL_stmt_dynexecute));
new->cmd_type = PLPGSQL_STMT_DYNEXECUTE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->query = expr;
new->into = false;
new->strict = false;
@@ -1852,7 +1852,7 @@ stmt_open : K_OPEN cursor_variable
new = palloc0(sizeof(PLpgSQL_stmt_open));
new->cmd_type = PLPGSQL_STMT_OPEN;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->curvar = $2->dno;
new->cursor_options = CURSOR_OPT_FAST_PLAN;
@@ -1942,9 +1942,9 @@ stmt_fetch : K_FETCH opt_fetch_direction cursor_variable K_INTO
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("FETCH statement cannot return multiple rows"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
- fetch->lineno = plpgsql_location_to_lineno(@1);
+ fetch->lineno = plpgsql_location_to_lineno(@1.begins);
fetch->rec = rec;
fetch->row = row;
fetch->curvar = $3->dno;
@@ -1958,7 +1958,7 @@ stmt_move : K_MOVE opt_fetch_direction cursor_variable ';'
{
PLpgSQL_stmt_fetch *fetch = $2;
- fetch->lineno = plpgsql_location_to_lineno(@1);
+ fetch->lineno = plpgsql_location_to_lineno(@1.begins);
fetch->curvar = $3->dno;
fetch->is_move = true;
@@ -1978,7 +1978,7 @@ stmt_close : K_CLOSE cursor_variable ';'
new = palloc(sizeof(PLpgSQL_stmt_close));
new->cmd_type = PLPGSQL_STMT_CLOSE;
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->curvar = $2->dno;
$$ = (PLpgSQL_stmt *)new;
@@ -1998,25 +1998,25 @@ cursor_variable : T_DATUM
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cursor variable must be a simple variable"),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
if (((PLpgSQL_var *) $1.datum)->datatype->typoid != REFCURSOROID)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("variable \"%s\" must be of type cursor or refcursor",
((PLpgSQL_var *) $1.datum)->refname),
- parser_errposition(@1)));
+ parser_errposition(@1.begins)));
$$ = (PLpgSQL_var *) $1.datum;
}
| T_WORD
{
/* just to give a better message than "syntax error" */
- word_is_not_variable(&($1), @1);
+ word_is_not_variable(&($1), @1.begins);
}
| T_CWORD
{
/* just to give a better message than "syntax error" */
- cword_is_not_variable(&($1), @1);
+ cword_is_not_variable(&($1), @1.begins);
}
;
@@ -2031,7 +2031,7 @@ exception_sect :
* scope of the names extends to the end of the
* current block.
*/
- int lineno = plpgsql_location_to_lineno(@1);
+ int lineno = plpgsql_location_to_lineno(@1.begins);
PLpgSQL_exception_block *new = palloc(sizeof(PLpgSQL_exception_block));
PLpgSQL_variable *var;
@@ -2077,7 +2077,7 @@ proc_exception : K_WHEN proc_conditions K_THEN proc_sect
PLpgSQL_exception *new;
new = palloc0(sizeof(PLpgSQL_exception));
- new->lineno = plpgsql_location_to_lineno(@1);
+ new->lineno = plpgsql_location_to_lineno(@1.begins);
new->conditions = $2;
new->action = $4;
@@ -2310,9 +2310,9 @@ static void
current_token_is_not_variable(int tok)
{
if (tok == T_WORD)
- word_is_not_variable(&(yylval.word), yylloc);
+ word_is_not_variable(&(yylval.word), yylloc.begins);
else if (tok == T_CWORD)
- cword_is_not_variable(&(yylval.cword), yylloc);
+ cword_is_not_variable(&(yylval.cword), yylloc.begins);
else
yyerror("syntax error");
}
@@ -2385,7 +2385,7 @@ read_sql_construct(int until,
{
tok = yylex();
if (startlocation < 0) /* remember loc of first token */
- startlocation = yylloc;
+ startlocation = yylloc.begins;
if (tok == until && parenlevel == 0)
break;
if (tok == until2 && parenlevel == 0)
@@ -2414,13 +2414,13 @@ read_sql_construct(int until,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("missing \"%s\" at end of SQL expression",
expected),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("missing \"%s\" at end of SQL statement",
expected),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
}
}
@@ -2432,7 +2432,7 @@ read_sql_construct(int until,
*endtoken = tok;
/* give helpful complaint about empty input */
- if (startlocation >= yylloc)
+ if (startlocation >= yylloc.begins)
{
if (isexpression)
yyerror("missing expression");
@@ -2440,7 +2440,7 @@ read_sql_construct(int until,
yyerror("missing SQL statement");
}
- plpgsql_append_source_text(&ds, startlocation, yylloc);
+ plpgsql_append_source_text(&ds, startlocation, yylloc.begins);
/* trim any trailing whitespace, for neatness */
while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
@@ -2476,7 +2476,7 @@ read_datatype(int tok)
if (tok == YYEMPTY)
tok = yylex();
- startlocation = yylloc;
+ startlocation = yylloc.begins;
/*
* If we have a simple or composite identifier, check for %TYPE
@@ -2557,7 +2557,7 @@ read_datatype(int tok)
/* set up ds to contain complete typename text */
initStringInfo(&ds);
- plpgsql_append_source_text(&ds, startlocation, yylloc);
+ plpgsql_append_source_text(&ds, startlocation, yylloc.begins);
type_name = ds.data;
if (type_name[0] == '\0')
@@ -2608,7 +2608,7 @@ make_execsql_stmt(int firsttoken, int location)
prev_tok = tok;
tok = yylex();
if (have_into && into_end_loc < 0)
- into_end_loc = yylloc; /* token after the INTO part */
+ into_end_loc = yylloc.begins; /* token after the INTO part */
if (tok == ';')
break;
if (tok == 0)
@@ -2619,7 +2619,7 @@ make_execsql_stmt(int firsttoken, int location)
if (have_into)
yyerror("INTO specified more than once");
have_into = true;
- into_start_loc = yylloc;
+ into_start_loc = yylloc.begins;
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL;
read_into_target(&rec, &row, &have_strict);
plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_EXPR;
@@ -2637,10 +2637,10 @@ make_execsql_stmt(int firsttoken, int location)
*/
plpgsql_append_source_text(&ds, location, into_start_loc);
appendStringInfoSpaces(&ds, into_end_loc - into_start_loc);
- plpgsql_append_source_text(&ds, into_end_loc, yylloc);
+ plpgsql_append_source_text(&ds, into_end_loc, yylloc.begins);
}
else
- plpgsql_append_source_text(&ds, location, yylloc);
+ plpgsql_append_source_text(&ds, location, yylloc.begins);
/* trim any trailing whitespace, for neatness */
while (ds.len > 0 && scanner_isspace(ds.data[ds.len - 1]))
@@ -2847,7 +2847,7 @@ make_return_stmt(int location)
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN cannot have a parameter in function returning set"),
errhint("Use RETURN NEXT or RETURN QUERY."),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
}
else if (plpgsql_curr_compile->out_param_varno >= 0)
{
@@ -2855,7 +2855,7 @@ make_return_stmt(int location)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN cannot have a parameter in function with OUT parameters"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
new->retvarno = plpgsql_curr_compile->out_param_varno;
}
else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
@@ -2864,7 +2864,7 @@ make_return_stmt(int location)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN cannot have a parameter in function returning void"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
}
else if (plpgsql_curr_compile->fn_retistuple)
{
@@ -2882,14 +2882,14 @@ make_return_stmt(int location)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN must specify a record or row variable in function returning row"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
break;
default:
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN must specify a record or row variable in function returning row"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
break;
}
if (yylex() != ';')
@@ -2931,7 +2931,7 @@ make_return_next_stmt(int location)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN NEXT cannot have a parameter in function with OUT parameters"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
new->retvarno = plpgsql_curr_compile->out_param_varno;
}
else if (plpgsql_curr_compile->fn_retistuple)
@@ -2946,14 +2946,14 @@ make_return_next_stmt(int location)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
break;
default:
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("RETURN NEXT must specify a record or row variable in function returning row"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
break;
}
if (yylex() != ';')
@@ -3087,32 +3087,32 @@ read_into_target(PLpgSQL_rec **rec, PLpgSQL_row **row, bool *strict)
case T_DATUM:
if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW)
{
- check_assignable(yylval.wdatum.datum, yylloc);
+ check_assignable(yylval.wdatum.datum, yylloc.begins);
*row = (PLpgSQL_row *) yylval.wdatum.datum;
if ((tok = yylex()) == ',')
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("record or row variable cannot be part of multiple-item INTO list"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
plpgsql_push_back_token(tok);
}
else if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
{
- check_assignable(yylval.wdatum.datum, yylloc);
+ check_assignable(yylval.wdatum.datum, yylloc.begins);
*rec = (PLpgSQL_rec *) yylval.wdatum.datum;
if ((tok = yylex()) == ',')
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("record or row variable cannot be part of multiple-item INTO list"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
plpgsql_push_back_token(tok);
}
else
{
*row = read_into_scalar_list(NameOfDatum(&(yylval.wdatum)),
- yylval.wdatum.datum, yylloc);
+ yylval.wdatum.datum, yylloc.begins);
}
break;
@@ -3151,20 +3151,20 @@ read_into_scalar_list(char *initial_name,
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("too many INTO variables specified"),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
tok = yylex();
switch (tok)
{
case T_DATUM:
- check_assignable(yylval.wdatum.datum, yylloc);
+ check_assignable(yylval.wdatum.datum, yylloc.begins);
if (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("\"%s\" is not a scalar variable",
NameOfDatum(&(yylval.wdatum))),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
fieldnames[nfields] = NameOfDatum(&(yylval.wdatum));
varnos[nfields++] = yylval.wdatum.datum->dno;
break;
@@ -3394,7 +3394,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, const char *expected)
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cursor \"%s\" has no arguments",
cursor->refname),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
if (tok != until)
yyerror("syntax error");
@@ -3408,7 +3408,7 @@ read_cursor_args(PLpgSQL_var *cursor, int until, const char *expected)
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("cursor \"%s\" has arguments",
cursor->refname),
- parser_errposition(yylloc)));
+ parser_errposition(yylloc.begins)));
/*
* Read expressions until the matching ')'.
diff --git a/src/pl/plpgsql/src/pl_scanner.c b/src/pl/plpgsql/src/pl_scanner.c
index 76e8436..7f18560 100644
--- a/src/pl/plpgsql/src/pl_scanner.c
+++ b/src/pl/plpgsql/src/pl_scanner.c
@@ -283,7 +283,7 @@ plpgsql_yylex(void)
push_back_token(tok3, &aux3);
push_back_token(tok2, &aux2);
if (plpgsql_parse_word(aux1.lval.str,
- core_yy.scanbuf + aux1.lloc,
+ core_yy.scanbuf + aux1.lloc.begins,
&aux1.lval.wdatum,
&aux1.lval.word))
tok1 = T_DATUM;
@@ -304,7 +304,7 @@ plpgsql_yylex(void)
/* not A.B, so just process A */
push_back_token(tok2, &aux2);
if (plpgsql_parse_word(aux1.lval.str,
- core_yy.scanbuf + aux1.lloc,
+ core_yy.scanbuf + aux1.lloc.begins,
&aux1.lval.wdatum,
&aux1.lval.word))
tok1 = T_DATUM;
@@ -356,7 +356,7 @@ internal_yylex(TokenAuxData *auxdata)
yyscanner);
/* remember the length of yytext before it gets changed */
- yytext = core_yy.scanbuf + auxdata->lloc;
+ yytext = core_yy.scanbuf + auxdata->lloc.begins;
auxdata->leng = strlen(yytext);
/* Check for << >> and #, which the core considers operators */
@@ -464,7 +464,7 @@ plpgsql_scanner_errposition(int location)
void
plpgsql_yyerror(const char *message)
{
- char *yytext = core_yy.scanbuf + plpgsql_yylloc;
+ char *yytext = core_yy.scanbuf + plpgsql_yylloc.begins;
if (*yytext == '\0')
{
@@ -472,7 +472,7 @@ plpgsql_yyerror(const char *message)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: %s is typically the translation of "syntax error" */
errmsg("%s at end of input", _(message)),
- plpgsql_scanner_errposition(plpgsql_yylloc)));
+ plpgsql_scanner_errposition(plpgsql_yylloc.begins)));
}
else
{
@@ -488,7 +488,7 @@ plpgsql_yyerror(const char *message)
(errcode(ERRCODE_SYNTAX_ERROR),
/* translator: first %s is typically the translation of "syntax error" */
errmsg("%s at or near \"%s\"", _(message), yytext),
- plpgsql_scanner_errposition(plpgsql_yylloc)));
+ plpgsql_scanner_errposition(plpgsql_yylloc.begins)));
}
}