aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlvaro Herrera <alvherre@alvh.no-ip.org>2015-03-18 14:48:02 -0300
committerAlvaro Herrera <alvherre@alvh.no-ip.org>2015-03-18 14:48:02 -0300
commitb8d226b4f9691c7afb986dbaaf3f6ff7b203d1b5 (patch)
tree22edcc6d4eb91685d02d0bdb8421523ecd85cb99 /src
parent0d831389749a3baaced7b984205b9894a82444b9 (diff)
downloadpostgresql-b8d226b4f9691c7afb986dbaaf3f6ff7b203d1b5.tar.gz
postgresql-b8d226b4f9691c7afb986dbaaf3f6ff7b203d1b5.zip
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
Diffstat (limited to 'src')
-rw-r--r--src/backend/parser/parse_func.c7
-rw-r--r--src/backend/parser/parse_oper.c24
-rw-r--r--src/backend/parser/parse_type.c5
-rw-r--r--src/backend/parser/parse_utilcmd.c13
-rw-r--r--src/test/regress/expected/create_table.out4
5 files changed, 43 insertions, 10 deletions
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 53bbaecac39..1385776f6bd 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -93,6 +93,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
Oid vatype;
FuncDetailCode fdresult;
char aggkind = 0;
+ ParseCallbackState pcbstate;
/*
* 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
* with default arguments.
*/
+
+ setup_parser_errposition_callback(&pcbstate, pstate, location);
+
fdresult = func_get_detail(funcname, fargs, argnames, nargs,
actual_arg_types,
!func_variadic, true,
&funcid, &rettype, &retset,
&nvargs, &vatype,
&declared_arg_types, &argdefaults);
+
+ cancel_parser_errposition_callback(&pcbstate);
+
if (fdresult == FUNCDETAIL_COERCION)
{
/*
diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c
index 10de97b7729..553260c835b 100644
--- a/src/backend/parser/parse_oper.c
+++ b/src/backend/parser/parse_oper.c
@@ -75,8 +75,9 @@ static const char *op_signature_string(List *op, char oprkind,
static void op_error(ParseState *pstate, List *op, char oprkind,
Oid arg1, Oid arg2,
FuncDetailCode fdresult, int location);
-static bool make_oper_cache_key(OprCacheKey *key, List *opname,
- Oid ltypeId, Oid rtypeId);
+static bool make_oper_cache_key(ParseState *pstate, OprCacheKey *key,
+ List *opname, Oid ltypeId, Oid rtypeId,
+ int location);
static Oid find_oper_cache_entry(OprCacheKey *key);
static void make_oper_cache_entry(OprCacheKey *key, Oid opr_oid);
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.
*/
- 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)
{
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.
*/
- 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)
{
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.
*/
- 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)
{
operOid = find_oper_cache_entry(&key);
@@ -1006,9 +1010,13 @@ static HTAB *OprCacheHash = NULL;
*
* Returns TRUE if successful, FALSE if the search_path overflowed
* (hence no caching is possible).
+ *
+ * pstate/location are used only to report the error position; pass NULL/-1
+ * if not available.
*/
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 *opername;
@@ -1026,8 +1034,12 @@ make_oper_cache_key(OprCacheKey *key, List *opname, Oid ltypeId, Oid rtypeId)
if (schemaname)
{
+ ParseCallbackState pcbstate;
+
/* search only in exact schema given */
+ setup_parser_errposition_callback(&pcbstate, pstate, location);
key->search_path[0] = LookupExplicitNamespace(schemaname, false);
+ cancel_parser_errposition_callback(&pcbstate);
}
else
{
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index ca5fbed34f4..1ba6ca76f42 100644
--- a/src/backend/parser/parse_type.c
+++ b/src/backend/parser/parse_type.c
@@ -156,6 +156,9 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
{
/* Look in specific schema only */
Oid namespaceId;
+ ParseCallbackState pcbstate;
+
+ setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
if (OidIsValid(namespaceId))
@@ -164,6 +167,8 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
ObjectIdGetDatum(namespaceId));
else
typoid = InvalidOid;
+
+ cancel_parser_errposition_callback(&pcbstate);
}
else
{
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 1e6da9cc40e..1bbed9582c9 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -149,6 +149,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
ListCell *elements;
Oid namespaceid;
Oid existing_relid;
+ ParseCallbackState pcbstate;
/*
* 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);
+ /* Set up pstate */
+ pstate = make_parsestate(NULL);
+ pstate->p_sourcetext = queryString;
+
/*
* Look up the creation namespace. This also checks permissions on the
* target namespace, locks it against concurrent drops, checks for a
* preexisting relation in that namespace with the same name, and updates
* stmt->relation->relpersistence if the selected namespace is temporary.
*/
+ setup_parser_errposition_callback(&pcbstate, pstate,
+ stmt->relation->location);
namespaceid =
RangeVarGetAndCheckCreationNamespace(stmt->relation, NoLock,
&existing_relid);
+ cancel_parser_errposition_callback(&pcbstate);
/*
* 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->schemaname = get_namespace_name(namespaceid);
- /* Set up pstate and CreateStmtContext */
- pstate = make_parsestate(NULL);
- pstate->p_sourcetext = queryString;
-
+ /* Set up CreateStmtContext */
cxt.pstate = pstate;
if (IsA(stmt, CreateForeignTableStmt))
{
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index 35451d5af26..34b5fc113d0 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -212,11 +212,15 @@ INSERT INTO unlogged1 VALUES (42);
CREATE UNLOGGED TABLE public.unlogged2 (a int primary key); -- also OK
CREATE UNLOGGED TABLE pg_temp.unlogged3 (a int primary key); -- not OK
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 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 public.temp_to_perm (a int primary key); -- not OK
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;
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';
CREATE TABLE as_select1 AS SELECT * FROM pg_class WHERE relkind = 'r';