1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-02 09:02:37 +03:00

Add a bunch of new error location reports to parse-analysis error messages.

There are still some weak spots around JOIN USING and relation alias lists,
but most errors reported within backend/parser/ now have locations.
This commit is contained in:
Tom Lane
2008-09-01 20:42:46 +00:00
parent 9ac4299163
commit b153c09209
103 changed files with 1877 additions and 485 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.78 2008/08/28 23:09:46 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.79 2008/09/01 20:42:44 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,10 +30,16 @@ typedef struct
typedef struct
{
int varno;
int varattno;
int var_location;
int sublevels_up;
} contain_var_reference_context;
} locate_var_of_level_context;
typedef struct
{
int var_location;
int relid;
int sublevels_up;
} locate_var_of_relation_context;
typedef struct
{
@ -56,11 +62,12 @@ typedef struct
static bool pull_varnos_walker(Node *node,
pull_varnos_context *context);
static bool pull_varattnos_walker(Node *node, Bitmapset **varattnos);
static bool contain_var_reference_walker(Node *node,
contain_var_reference_context *context);
static bool contain_var_clause_walker(Node *node, void *context);
static bool contain_vars_of_level_walker(Node *node, int *sublevels_up);
static bool contain_vars_above_level_walker(Node *node, int *sublevels_up);
static bool locate_var_of_level_walker(Node *node,
locate_var_of_level_context *context);
static bool locate_var_of_relation_walker(Node *node,
locate_var_of_relation_context *context);
static bool find_minimum_var_level_walker(Node *node,
find_minimum_var_level_context *context);
static bool pull_var_clause_walker(Node *node,
@ -136,6 +143,7 @@ pull_varnos_walker(Node *node, pull_varnos_context *context)
(void *) context);
}
/*
* pull_varattnos
* Find all the distinct attribute numbers present in an expression tree,
@ -178,69 +186,6 @@ pull_varattnos_walker(Node *node, Bitmapset **varattnos)
}
/*
* contain_var_reference
*
* Detect whether a parsetree contains any references to a specified
* attribute of a specified rtable entry.
*
* NOTE: this is used on not-yet-planned expressions. It may therefore find
* bare SubLinks, and if so it needs to recurse into them to look for uplevel
* references to the desired rtable entry! But when we find a completed
* SubPlan, we only need to look at the parameters passed to the subplan.
*/
bool
contain_var_reference(Node *node, int varno, int varattno, int levelsup)
{
contain_var_reference_context context;
context.varno = varno;
context.varattno = varattno;
context.sublevels_up = levelsup;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
contain_var_reference_walker,
(void *) &context,
0);
}
static bool
contain_var_reference_walker(Node *node,
contain_var_reference_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->varno &&
var->varattno == context->varattno &&
var->varlevelsup == context->sublevels_up)
return true;
return false;
}
if (IsA(node, Query))
{
/* Recurse into RTE subquery or not-yet-planned sublink subquery */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_var_reference_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node, contain_var_reference_walker,
(void *) context);
}
/*
* contain_var_clause
* Recursively scan a clause to discover whether it contains any Var nodes
@ -273,6 +218,7 @@ contain_var_clause_walker(Node *node, void *context)
return expression_tree_walker(node, contain_var_clause_walker, context);
}
/*
* contain_vars_of_level
* Recursively scan a clause to discover whether it contains any Var nodes
@ -328,53 +274,146 @@ contain_vars_of_level_walker(Node *node, int *sublevels_up)
(void *) sublevels_up);
}
/*
* contain_vars_above_level
* Recursively scan a clause to discover whether it contains any Var nodes
* above the specified query level. (For example, pass zero to detect
* all nonlocal Vars.)
* locate_var_of_level
* Find the parse location of any Var of the specified query level.
*
* Returns true if any such Var found.
* Returns -1 if no such Var is in the querytree, or if they all have
* unknown parse location. (The former case is probably caller error,
* but we don't bother to distinguish it from the latter case.)
*
* Will recurse into sublinks. Also, may be invoked directly on a Query.
*
* Note: it might seem appropriate to merge this functionality into
* contain_vars_of_level, but that would complicate that function's API.
* Currently, the only uses of this function are for error reporting,
* and so shaving cycles probably isn't very important.
*/
bool
contain_vars_above_level(Node *node, int levelsup)
int
locate_var_of_level(Node *node, int levelsup)
{
int sublevels_up = levelsup;
locate_var_of_level_context context;
return query_or_expression_tree_walker(node,
contain_vars_above_level_walker,
(void *) &sublevels_up,
context.var_location = -1; /* in case we find nothing */
context.sublevels_up = levelsup;
(void) query_or_expression_tree_walker(node,
locate_var_of_level_walker,
(void *) &context,
0);
return context.var_location;
}
static bool
contain_vars_above_level_walker(Node *node, int *sublevels_up)
locate_var_of_level_walker(Node *node,
locate_var_of_level_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
if (((Var *) node)->varlevelsup > *sublevels_up)
Var *var = (Var *) node;
if (var->varlevelsup == context->sublevels_up &&
var->location >= 0)
{
context->var_location = var->location;
return true; /* abort tree traversal and return true */
}
return false;
}
if (IsA(node, CurrentOfExpr))
{
/* since CurrentOfExpr doesn't carry location, nothing we can do */
return false;
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
(*sublevels_up)++;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
contain_vars_above_level_walker,
(void *) sublevels_up,
locate_var_of_level_walker,
(void *) context,
0);
(*sublevels_up)--;
context->sublevels_up--;
return result;
}
return expression_tree_walker(node,
contain_vars_above_level_walker,
(void *) sublevels_up);
locate_var_of_level_walker,
(void *) context);
}
/*
* locate_var_of_relation
* Find the parse location of any Var of the specified relation.
*
* Returns -1 if no such Var is in the querytree, or if they all have
* unknown parse location.
*
* Will recurse into sublinks. Also, may be invoked directly on a Query.
*/
int
locate_var_of_relation(Node *node, int relid, int levelsup)
{
locate_var_of_relation_context context;
context.var_location = -1; /* in case we find nothing */
context.relid = relid;
context.sublevels_up = levelsup;
(void) query_or_expression_tree_walker(node,
locate_var_of_relation_walker,
(void *) &context,
0);
return context.var_location;
}
static bool
locate_var_of_relation_walker(Node *node,
locate_var_of_relation_context *context)
{
if (node == NULL)
return false;
if (IsA(node, Var))
{
Var *var = (Var *) node;
if (var->varno == context->relid &&
var->varlevelsup == context->sublevels_up &&
var->location >= 0)
{
context->var_location = var->location;
return true; /* abort tree traversal and return true */
}
return false;
}
if (IsA(node, CurrentOfExpr))
{
/* since CurrentOfExpr doesn't carry location, nothing we can do */
return false;
}
if (IsA(node, Query))
{
/* Recurse into subselects */
bool result;
context->sublevels_up++;
result = query_tree_walker((Query *) node,
locate_var_of_relation_walker,
(void *) context,
0);
context->sublevels_up--;
return result;
}
return expression_tree_walker(node,
locate_var_of_relation_walker,
(void *) context);
}