Setup cursor position for schema-qualified elements
This makes any errors thrown while looking up such schemas report the position of the error. Author: Ryan Kelly Reviewed by: Jeevan Chalke, Tom Lane
This commit is contained in:
parent
0d83138974
commit
b8d226b4f9
src
backend/parser
test/regress/expected
@ -93,6 +93,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
Oid vatype;
|
Oid vatype;
|
||||||
FuncDetailCode fdresult;
|
FuncDetailCode fdresult;
|
||||||
char aggkind = 0;
|
char aggkind = 0;
|
||||||
|
ParseCallbackState pcbstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's an aggregate filter, transform it using transformWhereClause
|
* If there's an aggregate filter, transform it using transformWhereClause
|
||||||
@ -235,12 +236,18 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
|
|||||||
* type. We'll fix up the variadic case below. We may also have to deal
|
* type. We'll fix up the variadic case below. We may also have to deal
|
||||||
* with default arguments.
|
* with default arguments.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||||
|
|
||||||
fdresult = func_get_detail(funcname, fargs, argnames, nargs,
|
fdresult = func_get_detail(funcname, fargs, argnames, nargs,
|
||||||
actual_arg_types,
|
actual_arg_types,
|
||||||
!func_variadic, true,
|
!func_variadic, true,
|
||||||
&funcid, &rettype, &retset,
|
&funcid, &rettype, &retset,
|
||||||
&nvargs, &vatype,
|
&nvargs, &vatype,
|
||||||
&declared_arg_types, &argdefaults);
|
&declared_arg_types, &argdefaults);
|
||||||
|
|
||||||
|
cancel_parser_errposition_callback(&pcbstate);
|
||||||
|
|
||||||
if (fdresult == FUNCDETAIL_COERCION)
|
if (fdresult == FUNCDETAIL_COERCION)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
|
@ -75,8 +75,9 @@ static const char *op_signature_string(List *op, char oprkind,
|
|||||||
static void op_error(ParseState *pstate, List *op, char oprkind,
|
static void op_error(ParseState *pstate, List *op, char oprkind,
|
||||||
Oid arg1, Oid arg2,
|
Oid arg1, Oid arg2,
|
||||||
FuncDetailCode fdresult, int location);
|
FuncDetailCode fdresult, int location);
|
||||||
static bool make_oper_cache_key(OprCacheKey *key, List *opname,
|
static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
|
||||||
Oid ltypeId, Oid rtypeId);
|
List *opname, Oid ltypeId, Oid rtypeId,
|
||||||
|
int location);
|
||||||
static Oid find_oper_cache_entry(OprCacheKey *key);
|
static Oid find_oper_cache_entry(OprCacheKey *key);
|
||||||
static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
|
static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
|
||||||
static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
|
static void InvalidateOprCacheCallBack(Datum arg, int cacheid, uint32 hashvalue);
|
||||||
@ -383,7 +384,8 @@ oper(ParseState *pstate, List *opname, Oid ltypeId, Oid rtypeId,
|
|||||||
/*
|
/*
|
||||||
* Try to find the mapping in the lookaside cache.
|
* Try to find the mapping in the lookaside cache.
|
||||||
*/
|
*/
|
||||||
key_ok = make_oper_cache_key(&key, opname, ltypeId, rtypeId);
|
key_ok = make_oper_cache_key(pstate, &key, opname, ltypeId, rtypeId, location);
|
||||||
|
|
||||||
if (key_ok)
|
if (key_ok)
|
||||||
{
|
{
|
||||||
operOid = find_oper_cache_entry(&key);
|
operOid = find_oper_cache_entry(&key);
|
||||||
@ -529,7 +531,8 @@ right_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
|
|||||||
/*
|
/*
|
||||||
* Try to find the mapping in the lookaside cache.
|
* Try to find the mapping in the lookaside cache.
|
||||||
*/
|
*/
|
||||||
key_ok = make_oper_cache_key(&key, op, arg, InvalidOid);
|
key_ok = make_oper_cache_key(pstate, &key, op, arg, InvalidOid, location);
|
||||||
|
|
||||||
if (key_ok)
|
if (key_ok)
|
||||||
{
|
{
|
||||||
operOid = find_oper_cache_entry(&key);
|
operOid = find_oper_cache_entry(&key);
|
||||||
@ -607,7 +610,8 @@ left_oper(ParseState *pstate, List *op, Oid arg, bool noError, int location)
|
|||||||
/*
|
/*
|
||||||
* Try to find the mapping in the lookaside cache.
|
* Try to find the mapping in the lookaside cache.
|
||||||
*/
|
*/
|
||||||
key_ok = make_oper_cache_key(&key, op, InvalidOid, arg);
|
key_ok = make_oper_cache_key(pstate, &key, op, InvalidOid, arg, location);
|
||||||
|
|
||||||
if (key_ok)
|
if (key_ok)
|
||||||
{
|
{
|
||||||
operOid = find_oper_cache_entry(&key);
|
operOid = find_oper_cache_entry(&key);
|
||||||
@ -1006,9 +1010,13 @@ static HTAB *OprCacheHash = NULL;
|
|||||||
*
|
*
|
||||||
* Returns TRUE if successful, FALSE if the search_path overflowed
|
* Returns TRUE if successful, FALSE if the search_path overflowed
|
||||||
* (hence no caching is possible).
|
* (hence no caching is possible).
|
||||||
|
*
|
||||||
|
* pstate/location are used only to report the error position; pass NULL/-1
|
||||||
|
* if not available.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
make_oper_cache_key(OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId)
|
make_oper_cache_key(ParseState *pstate, OprCacheKey *key, List *opname,
|
||||||
|
Oid ltypeId, Oid rtypeId, int location)
|
||||||
{
|
{
|
||||||
char *schemaname;
|
char *schemaname;
|
||||||
char *opername;
|
char *opername;
|
||||||
@ -1026,8 +1034,12 @@ make_oper_cache_key(OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId)
|
|||||||
|
|
||||||
if (schemaname)
|
if (schemaname)
|
||||||
{
|
{
|
||||||
|
ParseCallbackState pcbstate;
|
||||||
|
|
||||||
/* search only in exact schema given */
|
/* search only in exact schema given */
|
||||||
|
setup_parser_errposition_callback(&pcbstate, pstate, location);
|
||||||
key->search_path[0] = LookupExplicitNamespace(schemaname, false);
|
key->search_path[0] = LookupExplicitNamespace(schemaname, false);
|
||||||
|
cancel_parser_errposition_callback(&pcbstate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -156,6 +156,9 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
|||||||
{
|
{
|
||||||
/* Look in specific schema only */
|
/* Look in specific schema only */
|
||||||
Oid namespaceId;
|
Oid namespaceId;
|
||||||
|
ParseCallbackState pcbstate;
|
||||||
|
|
||||||
|
setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
|
||||||
|
|
||||||
namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
|
namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
|
||||||
if (OidIsValid(namespaceId))
|
if (OidIsValid(namespaceId))
|
||||||
@ -164,6 +167,8 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
|||||||
ObjectIdGetDatum(namespaceId));
|
ObjectIdGetDatum(namespaceId));
|
||||||
else
|
else
|
||||||
typoid = InvalidOid;
|
typoid = InvalidOid;
|
||||||
|
|
||||||
|
cancel_parser_errposition_callback(&pcbstate);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -149,6 +149,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
|||||||
ListCell *elements;
|
ListCell *elements;
|
||||||
Oid namespaceid;
|
Oid namespaceid;
|
||||||
Oid existing_relid;
|
Oid existing_relid;
|
||||||
|
ParseCallbackState pcbstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
|
* We must not scribble on the passed-in CreateStmt, so copy it. (This is
|
||||||
@ -156,15 +157,22 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
|||||||
*/
|
*/
|
||||||
stmt = (CreateStmt *) copyObject(stmt);
|
stmt = (CreateStmt *) copyObject(stmt);
|
||||||
|
|
||||||
|
/* Set up pstate */
|
||||||
|
pstate = make_parsestate(NULL);
|
||||||
|
pstate->p_sourcetext = queryString;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Look up the creation namespace. This also checks permissions on the
|
* Look up the creation namespace. This also checks permissions on the
|
||||||
* target namespace, locks it against concurrent drops, checks for a
|
* target namespace, locks it against concurrent drops, checks for a
|
||||||
* preexisting relation in that namespace with the same name, and updates
|
* preexisting relation in that namespace with the same name, and updates
|
||||||
* stmt->relation->relpersistence if the selected namespace is temporary.
|
* stmt->relation->relpersistence if the selected namespace is temporary.
|
||||||
*/
|
*/
|
||||||
|
setup_parser_errposition_callback(&pcbstate, pstate,
|
||||||
|
stmt->relation->location);
|
||||||
namespaceid =
|
namespaceid =
|
||||||
RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
|
RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
|
||||||
&existing_relid);
|
&existing_relid);
|
||||||
|
cancel_parser_errposition_callback(&pcbstate);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the relation already exists and the user specified "IF NOT EXISTS",
|
* If the relation already exists and the user specified "IF NOT EXISTS",
|
||||||
@ -190,10 +198,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
|
|||||||
&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
|
&& stmt->relation->relpersistence != RELPERSISTENCE_TEMP)
|
||||||
stmt->relation->schemaname = get_namespace_name(namespaceid);
|
stmt->relation->schemaname = get_namespace_name(namespaceid);
|
||||||
|
|
||||||
/* Set up pstate and CreateStmtContext */
|
/* Set up CreateStmtContext */
|
||||||
pstate = make_parsestate(NULL);
|
|
||||||
pstate->p_sourcetext = queryString;
|
|
||||||
|
|
||||||
cxt.pstate = pstate;
|
cxt.pstate = pstate;
|
||||||
if (IsA(stmt, CreateForeignTableStmt))
|
if (IsA(stmt, CreateForeignTableStmt))
|
||||||
{
|
{
|
||||||
|
@ -212,11 +212,15 @@ INSERT INTO unlogged1 VALUES (42);
|
|||||||
CREATE UNLOGGED TABLE public.unlogged2 (a int primary key); -- also OK
|
CREATE UNLOGGED TABLE public.unlogged2 (a int primary key); -- also OK
|
||||||
CREATE UNLOGGED TABLE pg_temp.unlogged3 (a int primary key); -- not OK
|
CREATE UNLOGGED TABLE pg_temp.unlogged3 (a int primary key); -- not OK
|
||||||
ERROR: only temporary relations may be created in temporary schemas
|
ERROR: only temporary relations may be created in temporary schemas
|
||||||
|
LINE 1: CREATE UNLOGGED TABLE pg_temp.unlogged3 (a int primary key);
|
||||||
|
^
|
||||||
CREATE TABLE pg_temp.implicitly_temp (a int primary key); -- OK
|
CREATE TABLE pg_temp.implicitly_temp (a int primary key); -- OK
|
||||||
CREATE TEMP TABLE explicitly_temp (a int primary key); -- also OK
|
CREATE TEMP TABLE explicitly_temp (a int primary key); -- also OK
|
||||||
CREATE TEMP TABLE pg_temp.doubly_temp (a int primary key); -- also OK
|
CREATE TEMP TABLE pg_temp.doubly_temp (a int primary key); -- also OK
|
||||||
CREATE TEMP TABLE public.temp_to_perm (a int primary key); -- not OK
|
CREATE TEMP TABLE public.temp_to_perm (a int primary key); -- not OK
|
||||||
ERROR: cannot create temporary relation in non-temporary schema
|
ERROR: cannot create temporary relation in non-temporary schema
|
||||||
|
LINE 1: CREATE TEMP TABLE public.temp_to_perm (a int primary key);
|
||||||
|
^
|
||||||
DROP TABLE unlogged1, public.unlogged2;
|
DROP TABLE unlogged1, public.unlogged2;
|
||||||
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
|
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
|
||||||
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
|
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
|
||||||
|
Loading…
x
Reference in New Issue
Block a user