* commands. At one time acted as an interface between the Lisp and C
* systems.
*
- * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
/* local function declarations */
static void ProcessUtilitySlow(ParseState *pstate,
- Node *parsetree,
+ PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
* the query must be *in truth* read-only, because the caller wishes
* not to do CommandCounterIncrement for it.
*
- * Note: currently no need to support Query nodes here
+ * Note: currently no need to support raw or analyzed queries here
*/
bool
-CommandIsReadOnly(Node *parsetree)
+CommandIsReadOnly(PlannedStmt *pstmt)
{
- if (IsA(parsetree, PlannedStmt))
+ Assert(IsA(pstmt, PlannedStmt));
+ switch (pstmt->commandType)
{
- PlannedStmt *stmt = (PlannedStmt *) parsetree;
-
- switch (stmt->commandType)
- {
- case CMD_SELECT:
- if (stmt->rowMarks != NIL)
- return false; /* SELECT FOR [KEY] UPDATE/SHARE */
- else if (stmt->hasModifyingCTE)
- return false; /* data-modifying CTE */
- else
- return true;
- case CMD_UPDATE:
- case CMD_INSERT:
- case CMD_DELETE:
- return false;
- default:
- elog(WARNING, "unrecognized commandType: %d",
- (int) stmt->commandType);
- break;
- }
+ case CMD_SELECT:
+ if (pstmt->rowMarks != NIL)
+ return false; /* SELECT FOR [KEY] UPDATE/SHARE */
+ else if (pstmt->hasModifyingCTE)
+ return false; /* data-modifying CTE */
+ else
+ return true;
+ case CMD_UPDATE:
+ case CMD_INSERT:
+ case CMD_DELETE:
+ return false;
+ case CMD_UTILITY:
+ /* For now, treat all utility commands as read/write */
+ return false;
+ default:
+ elog(WARNING, "unrecognized commandType: %d",
+ (int) pstmt->commandType);
+ break;
}
- /* For now, treat all utility commands as read/write */
return false;
}
* ProcessUtility
* general utility function invoker
*
- * parsetree: the parse tree for the utility statement
+ * pstmt: PlannedStmt wrapper for the utility statement
* queryString: original source text of command
* context: identifies source of statement (toplevel client command,
* non-toplevel client command, subcommand of a larger utility command)
* completionTag may be NULL if caller doesn't want a status string.
*/
void
-ProcessUtility(Node *parsetree,
+ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
DestReceiver *dest,
char *completionTag)
{
+ Assert(IsA(pstmt, PlannedStmt));
+ Assert(pstmt->commandType == CMD_UTILITY);
Assert(queryString != NULL); /* required as of 8.4 */
/*
* call standard_ProcessUtility().
*/
if (ProcessUtility_hook)
- (*ProcessUtility_hook) (parsetree, queryString,
+ (*ProcessUtility_hook) (pstmt, queryString,
context, params,
dest, completionTag);
else
- standard_ProcessUtility(parsetree, queryString,
+ standard_ProcessUtility(pstmt, queryString,
context, params,
dest, completionTag);
}
* which requires being in a valid transaction.
*/
void
-standard_ProcessUtility(Node *parsetree,
+standard_ProcessUtility(PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
DestReceiver *dest,
char *completionTag)
{
+ Node *parsetree = pstmt->utilityStmt;
bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
ParseState *pstate;
/*
* Portal (cursor) manipulation
- *
- * Note: DECLARE CURSOR is processed mostly as a SELECT, and
- * therefore what we will get here is a PlannedStmt not a bare
- * DeclareCursorStmt.
*/
- case T_PlannedStmt:
- {
- PlannedStmt *stmt = (PlannedStmt *) parsetree;
-
- if (stmt->utilityStmt == NULL ||
- !IsA(stmt->utilityStmt, DeclareCursorStmt))
- elog(ERROR, "non-DECLARE CURSOR PlannedStmt passed to ProcessUtility");
- PerformCursorOpen(stmt, params, queryString, isTopLevel);
- }
+ case T_DeclareCursorStmt:
+ PerformCursorOpen((DeclareCursorStmt *) parsetree, params,
+ queryString, isTopLevel);
break;
case T_ClosePortalStmt:
{
uint64 processed;
- DoCopy(pstate, (CopyStmt *) parsetree, &processed);
+ DoCopy(pstate, (CopyStmt *) parsetree,
+ pstmt->stmt_location, pstmt->stmt_len,
+ &processed);
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
"COPY " UINT64_FORMAT, processed);
case T_PrepareStmt:
CheckRestrictedOperation("PREPARE");
- PrepareQuery((PrepareStmt *) parsetree, queryString);
+ PrepareQuery((PrepareStmt *) parsetree, queryString,
+ pstmt->stmt_location, pstmt->stmt_len);
break;
case T_ExecuteStmt:
GrantStmt *stmt = (GrantStmt *) parsetree;
if (EventTriggerSupportsGrantObjectType(stmt->objtype))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
- ExecuteGrantStmt((GrantStmt *) parsetree);
+ ExecuteGrantStmt(stmt);
}
break;
DropStmt *stmt = (DropStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->removeType))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
RenameStmt *stmt = (RenameStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->renameType))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
AlterObjectDependsStmt *stmt = (AlterObjectDependsStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
AlterObjectSchemaStmt *stmt = (AlterObjectSchemaStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
AlterOwnerStmt *stmt = (AlterOwnerStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objectType))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
CommentStmt *stmt = (CommentStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
- CommentObject((CommentStmt *) parsetree);
+ CommentObject(stmt);
break;
}
SecLabelStmt *stmt = (SecLabelStmt *) parsetree;
if (EventTriggerSupportsObjectType(stmt->objtype))
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
else
default:
/* All other statement types have event trigger support */
- ProcessUtilitySlow(pstate, parsetree, queryString,
+ ProcessUtilitySlow(pstate, pstmt, queryString,
context, params,
dest, completionTag);
break;
*/
static void
ProcessUtilitySlow(ParseState *pstate,
- Node *parsetree,
+ PlannedStmt *pstmt,
const char *queryString,
ProcessUtilityContext context,
ParamListInfo params,
DestReceiver *dest,
char *completionTag)
{
+ Node *parsetree = pstmt->utilityStmt;
bool isTopLevel = (context == PROCESS_UTILITY_TOPLEVEL);
bool isCompleteQuery = (context <= PROCESS_UTILITY_QUERY);
bool needCleanup;
*/
case T_CreateSchemaStmt:
CreateSchemaCommand((CreateSchemaStmt *) parsetree,
- queryString);
+ queryString,
+ pstmt->stmt_location,
+ pstmt->stmt_len);
/*
* EventTriggerCollectSimpleCommand called by
* call will stash the objects so created into our
* event trigger context.
*/
- ProcessUtility(stmt,
+ PlannedStmt *wrapper;
+
+ wrapper = makeNode(PlannedStmt);
+ wrapper->commandType = CMD_UTILITY;
+ wrapper->canSetTag = false;
+ wrapper->utilityStmt = stmt;
+ wrapper->stmt_location = pstmt->stmt_location;
+ wrapper->stmt_len = pstmt->stmt_len;
+
+ ProcessUtility(wrapper,
queryString,
PROCESS_UTILITY_SUBCOMMAND,
params,
* queued commands is consistent with the way
* they are executed here.
*/
+ PlannedStmt *wrapper;
+
EventTriggerAlterTableEnd();
- ProcessUtility(stmt,
+ wrapper = makeNode(PlannedStmt);
+ wrapper->commandType = CMD_UTILITY;
+ wrapper->canSetTag = false;
+ wrapper->utilityStmt = stmt;
+ wrapper->stmt_location = pstmt->stmt_location;
+ wrapper->stmt_len = pstmt->stmt_len;
+ ProcessUtility(wrapper,
queryString,
PROCESS_UTILITY_SUBCOMMAND,
params,
case T_ViewStmt: /* CREATE VIEW */
EventTriggerAlterTableStart(parsetree);
- address = DefineView((ViewStmt *) parsetree, queryString);
+ address = DefineView((ViewStmt *) parsetree, queryString,
+ pstmt->stmt_location, pstmt->stmt_len);
EventTriggerCollectSimpleCommand(address, secondaryObject,
parsetree);
/* stashed internally */
break;
case T_AlterTSConfigurationStmt:
- address = AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+ AlterTSConfiguration((AlterTSConfigurationStmt *) parsetree);
+
+ /*
+ * Commands are stashed in MakeConfigurationMapping and
+ * DropConfigurationMapping, which are called from
+ * AlterTSConfiguration
+ */
+ commandCollected = true;
break;
case T_AlterTableMoveAllStmt:
switch (parsetree->commandType)
{
case CMD_SELECT:
- /* returns tuples ... unless it's DECLARE CURSOR */
- if (parsetree->utilityStmt == NULL)
- return true;
- break;
+ /* returns tuples */
+ return true;
case CMD_INSERT:
case CMD_UPDATE:
case CMD_DELETE:
switch (nodeTag(parsetree))
{
+ case T_DeclareCursorStmt:
+ qry = (Query *) ((DeclareCursorStmt *) parsetree)->query;
+ Assert(IsA(qry, Query));
+ if (qry->commandType == CMD_UTILITY)
+ return UtilityContainsQuery(qry->utilityStmt);
+ return qry;
+
case T_ExplainStmt:
qry = (Query *) ((ExplainStmt *) parsetree)->query;
Assert(IsA(qry, Query));
/*
* CreateCommandTag
* utility to get a string representation of the command operation,
- * given either a raw (un-analyzed) parsetree or a planned query.
+ * given either a raw (un-analyzed) parsetree, an analyzed Query,
+ * or a PlannedStmt.
*
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
switch (nodeTag(parsetree))
{
+ /* recurse if we're given a RawStmt */
+ case T_RawStmt:
+ tag = CreateCommandTag(((RawStmt *) parsetree)->stmt);
+ break;
+
/* raw plannable queries */
case T_InsertStmt:
tag = "INSERT";
* will be useful for complaints about read-only
* statements
*/
- if (stmt->utilityStmt != NULL)
- {
- Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
- tag = "DECLARE CURSOR";
- }
- else if (stmt->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((PlanRowMark *) linitial(stmt->rowMarks))->strength)
case CMD_DELETE:
tag = "DELETE";
break;
+ case CMD_UTILITY:
+ tag = CreateCommandTag(stmt->utilityStmt);
+ break;
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);
* will be useful for complaints about read-only
* statements
*/
- if (stmt->utilityStmt != NULL)
- {
- Assert(IsA(stmt->utilityStmt, DeclareCursorStmt));
- tag = "DECLARE CURSOR";
- }
- else if (stmt->rowMarks != NIL)
+ if (stmt->rowMarks != NIL)
{
/* not 100% but probably close enough */
switch (((RowMarkClause *) linitial(stmt->rowMarks))->strength)
/*
* GetCommandLogLevel
* utility to get the minimum log_statement level for a command,
- * given either a raw (un-analyzed) parsetree or a planned query.
+ * given either a raw (un-analyzed) parsetree, an analyzed Query,
+ * or a PlannedStmt.
*
* This must handle all command types, but since the vast majority
* of 'em are utility commands, it seems sensible to keep it here.
switch (nodeTag(parsetree))
{
+ /* recurse if we're given a RawStmt */
+ case T_RawStmt:
+ lev = GetCommandLogLevel(((RawStmt *) parsetree)->stmt);
+ break;
+
/* raw plannable queries */
case T_InsertStmt:
case T_DeleteStmt:
/* Look through an EXECUTE to the referenced stmt */
ps = FetchPreparedStatement(stmt->name, false);
if (ps && ps->plansource->raw_parse_tree)
- lev = GetCommandLogLevel(ps->plansource->raw_parse_tree);
+ lev = GetCommandLogLevel(ps->plansource->raw_parse_tree->stmt);
else
lev = LOGSTMT_ALL;
}
lev = LOGSTMT_MOD;
break;
+ case CMD_UTILITY:
+ lev = GetCommandLogLevel(stmt->utilityStmt);
+ break;
+
default:
elog(WARNING, "unrecognized commandType: %d",
(int) stmt->commandType);