Commit b8d226b4 authored by Alvaro Herrera's avatar Alvaro Herrera

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
parent 0d831389
...@@ -93,6 +93,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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; ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment