diff options
Diffstat (limited to 'src/backend/commands/prepare.c')
-rw-r--r-- | src/backend/commands/prepare.c | 186 |
1 files changed, 91 insertions, 95 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index ecd5074211..8a5382c737 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.68 2007/01/28 19:05:35 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.69 2007/02/20 17:32:14 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -114,9 +114,9 @@ PrepareQuery(PrepareStmt *stmt) StorePreparedStatement(stmt->name, debug_query_string, commandTag, - query_list, plan_list, stmt->argtype_oids, + true, true); } @@ -129,8 +129,7 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, { PreparedStatement *entry; char *query_string; - List *query_list, - *plan_list; + List *plan_list; MemoryContext qcontext; ParamListInfo paramLI = NULL; EState *estate = NULL; @@ -139,13 +138,18 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, /* Look it up in the hash table */ entry = FetchPreparedStatement(stmt->name, true); + /* + * Punt if not fully planned. (Currently, that only happens for the + * protocol-level unnamed statement, which can't be accessed from SQL; + * so there's no point in doing more than a quick check here.) + */ + if (!entry->fully_planned) + elog(ERROR, "EXECUTE does not support unplanned prepared statements"); + query_string = entry->query_string; - query_list = entry->query_list; - plan_list = entry->plan_list; + plan_list = entry->stmt_list; qcontext = entry->context; - Assert(list_length(query_list) == list_length(plan_list)); - /* Evaluate parameters, if any */ if (entry->argtype_list != NIL) { @@ -172,30 +176,26 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, if (stmt->into) { MemoryContext oldContext; - Query *query; + PlannedStmt *pstmt; - oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); + qcontext = PortalGetHeapMemory(portal); + oldContext = MemoryContextSwitchTo(qcontext); if (query_string) query_string = pstrdup(query_string); - query_list = copyObject(query_list); plan_list = copyObject(plan_list); - qcontext = PortalGetHeapMemory(portal); - if (list_length(query_list) != 1) + if (list_length(plan_list) != 1) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); - query = (Query *) linitial(query_list); - if (query->commandType != CMD_SELECT) + pstmt = (PlannedStmt *) linitial(plan_list); + if (!IsA(pstmt, PlannedStmt) || + pstmt->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); - query->into = copyObject(stmt->into); - query->intoOptions = copyObject(stmt->intoOptions); - query->intoOnCommit = stmt->into_on_commit; - if (stmt->into_tbl_space) - query->intoTableSpaceName = pstrdup(stmt->into_tbl_space); + pstmt->into = copyObject(stmt->into); MemoryContextSwitchTo(oldContext); } @@ -204,7 +204,6 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params, NULL, query_string, entry->commandTag, - query_list, plan_list, qcontext); @@ -305,9 +304,9 @@ void StorePreparedStatement(const char *stmt_name, const char *query_string, const char *commandTag, - List *query_list, - List *plan_list, + List *stmt_list, List *argtype_list, + bool fully_planned, bool from_sql) { PreparedStatement *entry; @@ -345,8 +344,7 @@ StorePreparedStatement(const char *stmt_name, * incomplete (ie corrupt) hashtable entry. */ qstring = query_string ? pstrdup(query_string) : NULL; - query_list = (List *) copyObject(query_list); - plan_list = (List *) copyObject(plan_list); + stmt_list = (List *) copyObject(stmt_list); argtype_list = list_copy(argtype_list); /* Now we can add entry to hash table */ @@ -363,12 +361,12 @@ StorePreparedStatement(const char *stmt_name, /* Fill in the hash table entry with copied data */ entry->query_string = qstring; entry->commandTag = commandTag; - entry->query_list = query_list; - entry->plan_list = plan_list; + entry->stmt_list = stmt_list; entry->argtype_list = argtype_list; + entry->fully_planned = fully_planned; + entry->from_sql = from_sql; entry->context = entrycxt; entry->prepare_time = GetCurrentStatementStartTimestamp(); - entry->from_sql = from_sql; MemoryContextSwitchTo(oldcxt); } @@ -426,21 +424,54 @@ FetchPreparedStatementParams(const char *stmt_name) TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt) { + Node *node; Query *query; + PlannedStmt *pstmt; - switch (ChoosePortalStrategy(stmt->query_list)) + switch (ChoosePortalStrategy(stmt->stmt_list)) { case PORTAL_ONE_SELECT: - query = (Query *) linitial(stmt->query_list); - return ExecCleanTypeFromTL(query->targetList, false); + node = (Node *) linitial(stmt->stmt_list); + if (IsA(node, Query)) + { + query = (Query *) node; + return ExecCleanTypeFromTL(query->targetList, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; + return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false); + } + /* other cases shouldn't happen, but return NULL */ + break; case PORTAL_ONE_RETURNING: - query = PortalListGetPrimaryQuery(stmt->query_list); - return ExecCleanTypeFromTL(query->returningList, false); + node = PortalListGetPrimaryStmt(stmt->stmt_list); + if (IsA(node, Query)) + { + query = (Query *) node; + Assert(query->returningList); + return ExecCleanTypeFromTL(query->returningList, false); + } + if (IsA(node, PlannedStmt)) + { + pstmt = (PlannedStmt *) node; + Assert(pstmt->returningLists); + return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false); + } + /* other cases shouldn't happen, but return NULL */ + break; case PORTAL_UTIL_SELECT: - query = (Query *) linitial(stmt->query_list); - return UtilityTupleDescriptor(query->utilityStmt); + node = (Node *) linitial(stmt->stmt_list); + if (IsA(node, Query)) + { + query = (Query *) node; + Assert(query->utilityStmt); + return UtilityTupleDescriptor(query->utilityStmt); + } + /* else it's a bare utility statement */ + return UtilityTupleDescriptor(node); case PORTAL_MULTI_QUERY: /* will not return tuples */ @@ -460,7 +491,7 @@ FetchPreparedStatementResultDesc(PreparedStatement *stmt) bool PreparedStatementReturnsTuples(PreparedStatement *stmt) { - switch (ChoosePortalStrategy(stmt->query_list)) + switch (ChoosePortalStrategy(stmt->stmt_list)) { case PORTAL_ONE_SELECT: case PORTAL_ONE_RETURNING: @@ -480,52 +511,15 @@ PreparedStatementReturnsTuples(PreparedStatement *stmt) * targetlist. * * Note: do not modify the result. - * - * XXX be careful to keep this in sync with FetchPortalTargetList, - * and with UtilityReturnsTuples. */ List * FetchPreparedStatementTargetList(PreparedStatement *stmt) { - PortalStrategy strategy = ChoosePortalStrategy(stmt->query_list); - - if (strategy == PORTAL_ONE_SELECT) - return ((Query *) linitial(stmt->query_list))->targetList; - if (strategy == PORTAL_ONE_RETURNING) - return (PortalListGetPrimaryQuery(stmt->query_list))->returningList; - if (strategy == PORTAL_UTIL_SELECT) - { - Node *utilityStmt; - - utilityStmt = ((Query *) linitial(stmt->query_list))->utilityStmt; - switch (nodeTag(utilityStmt)) - { - case T_FetchStmt: - { - FetchStmt *substmt = (FetchStmt *) utilityStmt; - Portal subportal; - - Assert(!substmt->ismove); - subportal = GetPortalByName(substmt->portalname); - Assert(PortalIsValid(subportal)); - return FetchPortalTargetList(subportal); - } - - case T_ExecuteStmt: - { - ExecuteStmt *substmt = (ExecuteStmt *) utilityStmt; - PreparedStatement *entry; - - Assert(!substmt->into); - entry = FetchPreparedStatement(substmt->name, true); - return FetchPreparedStatementTargetList(entry); - } - - default: - break; - } - } - return NIL; + /* no point in looking if it doesn't return tuples */ + if (ChoosePortalStrategy(stmt->stmt_list) == PORTAL_MULTI_QUERY) + return NIL; + /* get the primary statement and find out what it returns */ + return FetchStatementTargetList(PortalListGetPrimaryStmt(stmt->stmt_list)); } /* @@ -574,10 +568,8 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, { ExecuteStmt *execstmt = (ExecuteStmt *) stmt->query->utilityStmt; PreparedStatement *entry; - ListCell *q, - *p; - List *query_list, - *plan_list; + List *plan_list; + ListCell *p; ParamListInfo paramLI = NULL; EState *estate = NULL; @@ -587,10 +579,15 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, /* Look it up in the hash table */ entry = FetchPreparedStatement(execstmt->name, true); - query_list = entry->query_list; - plan_list = entry->plan_list; + /* + * Punt if not fully planned. (Currently, that only happens for the + * protocol-level unnamed statement, which can't be accessed from SQL; + * so there's no point in doing more than a quick check here.) + */ + if (!entry->fully_planned) + elog(ERROR, "EXPLAIN EXECUTE does not support unplanned prepared statements"); - Assert(list_length(query_list) == list_length(plan_list)); + plan_list = entry->stmt_list; /* Evaluate parameters, if any */ if (entry->argtype_list != NIL) @@ -606,17 +603,16 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, } /* Explain each query */ - forboth(q, query_list, p, plan_list) + foreach(p, plan_list) { - Query *query = (Query *) lfirst(q); - Plan *plan = (Plan *) lfirst(p); + PlannedStmt *pstmt = (PlannedStmt *) lfirst(p); bool is_last_query; is_last_query = (lnext(p) == NULL); - if (query->commandType == CMD_UTILITY) + if (!IsA(pstmt, PlannedStmt)) { - if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt)) + if (IsA(pstmt, NotifyStmt)) do_text_output_oneline(tstate, "NOTIFY"); else do_text_output_oneline(tstate, "UTILITY"); @@ -627,15 +623,15 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, if (execstmt->into) { - if (query->commandType != CMD_SELECT) + if (pstmt->commandType != CMD_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); - /* Copy the query so we can modify it */ - query = copyObject(query); + /* Copy the stmt so we can modify it */ + pstmt = copyObject(pstmt); - query->into = execstmt->into; + pstmt->into = execstmt->into; } /* @@ -648,7 +644,7 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params, ActiveSnapshot->curcid = GetCurrentCommandId(); /* Create a QueryDesc requesting no output */ - qdesc = CreateQueryDesc(query, plan, + qdesc = CreateQueryDesc(pstmt, ActiveSnapshot, InvalidSnapshot, None_Receiver, paramLI, stmt->analyze); |