/* * ProcessUtility hook */ static void pg_record_ProcessUtility(Node *parsetree, const char *queryString, ParamListInfo params, bool isTopLevel, DestReceiver *dest, char *completionTag) { if ((nesting_level == 0) && collect) { instr_time start; instr_time duration; float seconds; INSTR_TIME_SET_CURRENT(start); nesting_level++; PG_TRY(); { if (prev_ProcessUtility) prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); nesting_level--; } PG_CATCH(); { nesting_level--; PG_RE_THROW(); } PG_END_TRY(); INSTR_TIME_SET_CURRENT(duration); INSTR_TIME_SUBTRACT(duration, start); seconds = INSTR_TIME_GET_DOUBLE(duration); buffer_add_query(seconds, queryString); } else { if (prev_ProcessUtility) prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); } }
queryhist_ProcessUtility(Node *parsetree, const char *queryString, ParamListInfo params, bool isTopLevel, DestReceiver *dest, char *completionTag) #endif { if (default_histogram_utility && (nesting_level == 0) && query_histogram_enabled()) { /* collecting histogram is enabled, we're in top level (nesting_level=0) */ instr_time start; instr_time duration; float seconds; INSTR_TIME_SET_CURRENT(start); nesting_level++; PG_TRY(); { if (prev_ProcessUtility) #if (PG_VERSION_NUM >= 90300) prev_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); #else prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); #endif else #if (PG_VERSION_NUM >= 90300) standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); #else standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); #endif nesting_level--; }
static void dbrestrict_utility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { /* Do our custom process on drop database */ switch (nodeTag(parsetree)) { case T_DropdbStmt: { DropdbStmt *stmt = (DropdbStmt *) parsetree; char *username = GetUserNameFromId(GetUserId(), false); /* * Check that only the authorized superuser foo can * drop the database undroppable_foodb. */ if (strcmp(stmt->dbname, hook_dbname) == 0 && strcmp(username, hook_username) != 0) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("Only super-superuser \"%s\" can drop database \"%s\"", hook_username, hook_dbname))); break; } default: break; } /* * Fallback to normal process, be it the previous hook loaded * or the in-core code path if the previous hook does not exist. */ if (prev_utility_hook) (*prev_utility_hook) (parsetree, queryString, context, params, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); }
static void MMProcessUtility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { bool skipCommand; switch (nodeTag(parsetree)) { case T_TransactionStmt: case T_PlannedStmt: case T_ClosePortalStmt: case T_FetchStmt: case T_DoStmt: case T_CopyStmt: case T_PrepareStmt: case T_ExecuteStmt: case T_NotifyStmt: case T_ListenStmt: case T_UnlistenStmt: case T_LoadStmt: case T_VariableSetStmt: case T_VariableShowStmt: skipCommand = true; break; default: skipCommand = false; break; } if (skipCommand || IsTransactionBlock()) { if (PreviousProcessUtilityHook != NULL) { PreviousProcessUtilityHook(parsetree, queryString, context, params, dest, completionTag); } else { standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); } if (!skipCommand) { MMIsDistributedTrans = false; } } else { MMBroadcastUtilityStmt(queryString, false); } }
/* * CStoreProcessUtility is the hook for handling utility commands. This function * intercepts "COPY cstore_table FROM" statements, and redirectes execution to * CopyIntoCStoreTable function. For all other utility statements, the function * calls the previous utility hook or the standard utility command. */ static void CStoreProcessUtility(Node *parseTree, const char *queryString, ProcessUtilityContext context, ParamListInfo paramListInfo, DestReceiver *destReceiver, char *completionTag) { bool copyIntoCStoreTable = false; /* check if the statement is a "COPY cstore_table FROM ..." statement */ if (nodeTag(parseTree) == T_CopyStmt) { CopyStmt *copyStatement = (CopyStmt *) parseTree; if (copyStatement->is_from && CStoreTable(copyStatement->relation)) { copyIntoCStoreTable = true; } } if (copyIntoCStoreTable) { uint64 processed = CopyIntoCStoreTable((CopyStmt *) parseTree, queryString); if (completionTag != NULL) { snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "COPY " UINT64_FORMAT, processed); } } else if (PreviousProcessUtilityHook != NULL) { PreviousProcessUtilityHook(parseTree, queryString, context, paramListInfo, destReceiver, completionTag); } else { standard_ProcessUtility(parseTree, queryString, context, paramListInfo, destReceiver, completionTag); } }
/* * ProcessUtility hook */ static void pgss_ProcessUtility(Node *parsetree, const char *queryString, ParamListInfo params, bool isTopLevel, DestReceiver *dest, char *completionTag) { if (pgss_track_utility && pgss_enabled()) { instr_time start; instr_time duration; uint64 rows = 0; BufferUsage bufusage; bufusage = pgBufferUsage; INSTR_TIME_SET_CURRENT(start); nested_level++; PG_TRY(); { if (prev_ProcessUtility) prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); nested_level--; } PG_CATCH(); { nested_level--; PG_RE_THROW(); } PG_END_TRY(); INSTR_TIME_SET_CURRENT(duration); INSTR_TIME_SUBTRACT(duration, start); /* parse command tag to retrieve the number of affected rows. */ if (completionTag && sscanf(completionTag, "COPY " UINT64_FORMAT, &rows) != 1) rows = 0; /* calc differences of buffer counters. */ bufusage.shared_blks_hit = pgBufferUsage.shared_blks_hit - bufusage.shared_blks_hit; bufusage.shared_blks_read = pgBufferUsage.shared_blks_read - bufusage.shared_blks_read; bufusage.shared_blks_written = pgBufferUsage.shared_blks_written - bufusage.shared_blks_written; bufusage.local_blks_hit = pgBufferUsage.local_blks_hit - bufusage.local_blks_hit; bufusage.local_blks_read = pgBufferUsage.local_blks_read - bufusage.local_blks_read; bufusage.local_blks_written = pgBufferUsage.local_blks_written - bufusage.local_blks_written; bufusage.temp_blks_read = pgBufferUsage.temp_blks_read - bufusage.temp_blks_read; bufusage.temp_blks_written = pgBufferUsage.temp_blks_written - bufusage.temp_blks_written; pgss_store(queryString, INSTR_TIME_GET_DOUBLE(duration), rows, &bufusage); } else { if (prev_ProcessUtility) prev_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, params, isTopLevel, dest, completionTag); } }
static void trunc2del(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag) { /* * Do custom processing for TRUNCATE. Note that this is not aimed at * doing much for TRUNCATE CASCADE and triggers that should fire here. * This becomes even more a mess should a DELETE trigger be defined * on this relation. */ switch (nodeTag(parsetree)) { case T_TruncateStmt: { TruncateStmt *stmt = (TruncateStmt *) parsetree; RangeVar *rv = (RangeVar *) linitial(stmt->relations); int ret; StringInfoData buf; Relation rel; /* * Check existence of relation queried, this is important in case * of an unexistent relation to not let the user know of this * run switch. As we are faking a TRUNCATE, it is as well important * to take a exclusive lock on the relation operated on. */ rel = heap_openrv(rv, AccessExclusiveLock); SPI_connect(); initStringInfo(&buf); appendStringInfo(&buf, "DELETE FROM "); if (rv->schemaname) appendStringInfo(&buf,"%s.", quote_identifier(rv->schemaname)); appendStringInfo(&buf, "%s;", quote_identifier(rv->relname)); ret = SPI_execute(buf.data, false, 0); if (ret != SPI_OK_DELETE) elog(ERROR, "Error while executing TRUNCATE (really?)"); SPI_finish(); /* keep lock until the end of transaction */ heap_close(rel, NoLock); return; } default: break; } /* * Fallback to normal process, be it the previous hook loaded * or the in-core code path if the previous hook does not exist. */ if (prev_utility_hook) (*prev_utility_hook) (parsetree, queryString, context, params, dest, completionTag); else standard_ProcessUtility(parsetree, queryString, context, params, dest, completionTag); }