mirror of
https://github.com/postgres/postgres.git
synced 2025-06-30 21:42:05 +03:00
Add location field to DefElem
Add a location field to the DefElem struct, used to parse many utility commands. Update various error messages to supply error position information. To propogate the error position information in a more systematic way, create a ParseState in standard_ProcessUtility() and pass that to interested functions implementing the utility commands. This seems better than passing the query string and then reassembling a parse state ad hoc, which violates the encapsulation of the ParseState type. Reviewed-by: Pavel Stehule <pavel.stehule@gmail.com>
This commit is contained in:
@ -279,12 +279,12 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0";
|
||||
|
||||
|
||||
/* non-export function prototypes */
|
||||
static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query,
|
||||
const char *queryString, const Oid queryRelId, List *attnamelist,
|
||||
static CopyState BeginCopy(ParseState *pstate, bool is_from, Relation rel, Node *raw_query,
|
||||
const Oid queryRelId, List *attnamelist,
|
||||
List *options);
|
||||
static void EndCopy(CopyState cstate);
|
||||
static void ClosePipeToProgram(CopyState cstate);
|
||||
static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString,
|
||||
static CopyState BeginCopyTo(ParseState *pstate, Relation rel, Node *query,
|
||||
const Oid queryRelId, const char *filename, bool is_program,
|
||||
List *attnamelist, List *options);
|
||||
static void EndCopyTo(CopyState cstate);
|
||||
@ -787,7 +787,7 @@ CopyLoadRawBuf(CopyState cstate)
|
||||
* the table or the specifically requested columns.
|
||||
*/
|
||||
Oid
|
||||
DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
|
||||
DoCopy(ParseState *pstate, const CopyStmt *stmt, uint64 *processed)
|
||||
{
|
||||
CopyState cstate;
|
||||
bool is_from = stmt->is_from;
|
||||
@ -936,7 +936,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
|
||||
PreventCommandIfReadOnly("COPY FROM");
|
||||
PreventCommandIfParallelMode("COPY FROM");
|
||||
|
||||
cstate = BeginCopyFrom(rel, stmt->filename, stmt->is_program,
|
||||
cstate = BeginCopyFrom(pstate, rel, stmt->filename, stmt->is_program,
|
||||
stmt->attlist, stmt->options);
|
||||
cstate->range_table = range_table;
|
||||
*processed = CopyFrom(cstate); /* copy from file to database */
|
||||
@ -944,7 +944,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
|
||||
}
|
||||
else
|
||||
{
|
||||
cstate = BeginCopyTo(rel, query, queryString, relid,
|
||||
cstate = BeginCopyTo(pstate, rel, query, relid,
|
||||
stmt->filename, stmt->is_program,
|
||||
stmt->attlist, stmt->options);
|
||||
*processed = DoCopyTo(cstate); /* copy from database to file */
|
||||
@ -980,7 +980,8 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed)
|
||||
* self-consistency of the options list.
|
||||
*/
|
||||
void
|
||||
ProcessCopyOptions(CopyState cstate,
|
||||
ProcessCopyOptions(ParseState *pstate,
|
||||
CopyState cstate,
|
||||
bool is_from,
|
||||
List *options)
|
||||
{
|
||||
@ -1005,7 +1006,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (format_specified)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
format_specified = true;
|
||||
if (strcmp(fmt, "text") == 0)
|
||||
/* default format */ ;
|
||||
@ -1016,14 +1018,16 @@ ProcessCopyOptions(CopyState cstate,
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("COPY format \"%s\" not recognized", fmt)));
|
||||
errmsg("COPY format \"%s\" not recognized", fmt),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else if (strcmp(defel->defname, "oids") == 0)
|
||||
{
|
||||
if (cstate->oids)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->oids = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "freeze") == 0)
|
||||
@ -1031,7 +1035,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->freeze)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->freeze = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "delimiter") == 0)
|
||||
@ -1039,7 +1044,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->delim)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->delim = defGetString(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "null") == 0)
|
||||
@ -1047,7 +1053,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->null_print)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->null_print = defGetString(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "header") == 0)
|
||||
@ -1055,7 +1062,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->header_line)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->header_line = defGetBoolean(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "quote") == 0)
|
||||
@ -1063,7 +1071,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->quote)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->quote = defGetString(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "escape") == 0)
|
||||
@ -1071,7 +1080,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->escape)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->escape = defGetString(defel);
|
||||
}
|
||||
else if (strcmp(defel->defname, "force_quote") == 0)
|
||||
@ -1079,7 +1089,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->force_quote || cstate->force_quote_all)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
if (defel->arg && IsA(defel->arg, A_Star))
|
||||
cstate->force_quote_all = true;
|
||||
else if (defel->arg && IsA(defel->arg, List))
|
||||
@ -1088,21 +1099,24 @@ ProcessCopyOptions(CopyState cstate,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument to option \"%s\" must be a list of column names",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else if (strcmp(defel->defname, "force_not_null") == 0)
|
||||
{
|
||||
if (cstate->force_notnull)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
if (defel->arg && IsA(defel->arg, List))
|
||||
cstate->force_notnull = (List *) defel->arg;
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument to option \"%s\" must be a list of column names",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else if (strcmp(defel->defname, "force_null") == 0)
|
||||
{
|
||||
@ -1116,7 +1130,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument to option \"%s\" must be a list of column names",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else if (strcmp(defel->defname, "convert_selectively") == 0)
|
||||
{
|
||||
@ -1128,7 +1143,8 @@ ProcessCopyOptions(CopyState cstate,
|
||||
if (cstate->convert_selectively)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->convert_selectively = true;
|
||||
if (defel->arg == NULL || IsA(defel->arg, List))
|
||||
cstate->convert_select = (List *) defel->arg;
|
||||
@ -1136,26 +1152,30 @@ ProcessCopyOptions(CopyState cstate,
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument to option \"%s\" must be a list of column names",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else if (strcmp(defel->defname, "encoding") == 0)
|
||||
{
|
||||
if (cstate->file_encoding >= 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
errmsg("conflicting or redundant options"),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
cstate->file_encoding = pg_char_to_encoding(defGetString(defel));
|
||||
if (cstate->file_encoding < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument to option \"%s\" must be a valid encoding name",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("option \"%s\" not recognized",
|
||||
defel->defname)));
|
||||
defel->defname),
|
||||
parser_errposition(pstate, defel->location)));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1318,10 +1338,10 @@ ProcessCopyOptions(CopyState cstate,
|
||||
* NULL values as <null_print>.
|
||||
*/
|
||||
static CopyState
|
||||
BeginCopy(bool is_from,
|
||||
BeginCopy(ParseState *pstate,
|
||||
bool is_from,
|
||||
Relation rel,
|
||||
Node *raw_query,
|
||||
const char *queryString,
|
||||
const Oid queryRelId,
|
||||
List *attnamelist,
|
||||
List *options)
|
||||
@ -1345,7 +1365,7 @@ BeginCopy(bool is_from,
|
||||
oldcontext = MemoryContextSwitchTo(cstate->copycontext);
|
||||
|
||||
/* Extract options from the statement node tree */
|
||||
ProcessCopyOptions(cstate, is_from, options);
|
||||
ProcessCopyOptions(pstate, cstate, is_from, options);
|
||||
|
||||
/* Process the source/target relation or query */
|
||||
if (rel)
|
||||
@ -1390,7 +1410,7 @@ BeginCopy(bool is_from,
|
||||
* DECLARE CURSOR and PREPARE.) XXX FIXME someday.
|
||||
*/
|
||||
rewritten = pg_analyze_and_rewrite((Node *) copyObject(raw_query),
|
||||
queryString, NULL, 0);
|
||||
pstate->p_sourcetext, NULL, 0);
|
||||
|
||||
/* check that we got back something we can work with */
|
||||
if (rewritten == NIL)
|
||||
@ -1490,7 +1510,7 @@ BeginCopy(bool is_from,
|
||||
((DR_copy *) dest)->cstate = cstate;
|
||||
|
||||
/* Create a QueryDesc requesting no output */
|
||||
cstate->queryDesc = CreateQueryDesc(plan, queryString,
|
||||
cstate->queryDesc = CreateQueryDesc(plan, pstate->p_sourcetext,
|
||||
GetActiveSnapshot(),
|
||||
InvalidSnapshot,
|
||||
dest, NULL, 0);
|
||||
@ -1678,9 +1698,9 @@ EndCopy(CopyState cstate)
|
||||
* Setup CopyState to read tuples from a table or a query for COPY TO.
|
||||
*/
|
||||
static CopyState
|
||||
BeginCopyTo(Relation rel,
|
||||
BeginCopyTo(ParseState *pstate,
|
||||
Relation rel,
|
||||
Node *query,
|
||||
const char *queryString,
|
||||
const Oid queryRelId,
|
||||
const char *filename,
|
||||
bool is_program,
|
||||
@ -1723,7 +1743,7 @@ BeginCopyTo(Relation rel,
|
||||
RelationGetRelationName(rel))));
|
||||
}
|
||||
|
||||
cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist,
|
||||
cstate = BeginCopy(pstate, false, rel, query, queryRelId, attnamelist,
|
||||
options);
|
||||
oldcontext = MemoryContextSwitchTo(cstate->copycontext);
|
||||
|
||||
@ -2645,7 +2665,8 @@ CopyFromInsertBatch(CopyState cstate, EState *estate, CommandId mycid,
|
||||
* Returns a CopyState, to be passed to NextCopyFrom and related functions.
|
||||
*/
|
||||
CopyState
|
||||
BeginCopyFrom(Relation rel,
|
||||
BeginCopyFrom(ParseState *pstate,
|
||||
Relation rel,
|
||||
const char *filename,
|
||||
bool is_program,
|
||||
List *attnamelist,
|
||||
@ -2666,7 +2687,7 @@ BeginCopyFrom(Relation rel,
|
||||
MemoryContext oldcontext;
|
||||
bool volatile_defexprs;
|
||||
|
||||
cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options);
|
||||
cstate = BeginCopy(pstate, true, rel, NULL, InvalidOid, attnamelist, options);
|
||||
oldcontext = MemoryContextSwitchTo(cstate->copycontext);
|
||||
|
||||
/* Initialize state variables */
|
||||
|
Reference in New Issue
Block a user