postgres.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,390 行 · 第 1/5 页
C
2,390 行
PortalDefineQuery(portal, query_string, commandTag, querytree_list, plantree_list, MessageContext); /* * Start the portal. No parameters here. */ PortalStart(portal, NULL, InvalidSnapshot); /* * Select the appropriate output format: text unless we are doing a * FETCH from a binary cursor. (Pretty grotty to have to do this here * --- but it avoids grottiness in other places. Ah, the joys of * backward compatibility...) */ format = 0; /* TEXT is default */ if (IsA(parsetree, FetchStmt)) { FetchStmt *stmt = (FetchStmt *) parsetree; if (!stmt->ismove) { Portal fportal = GetPortalByName(stmt->portalname); if (PortalIsValid(fportal) && (fportal->cursorOptions & CURSOR_OPT_BINARY)) format = 1; /* BINARY */ } } PortalSetResultFormat(portal, 1, &format); /* * Now we can create the destination receiver object. */ receiver = CreateDestReceiver(dest, portal); /* * Switch back to transaction context for execution. */ MemoryContextSwitchTo(oldcontext); /* * Run the portal to completion, and then drop it (and the receiver). */ (void) PortalRun(portal, FETCH_ALL, receiver, receiver, completionTag); (*receiver->rDestroy) (receiver); PortalDrop(portal, false); if (IsA(parsetree, TransactionStmt)) { /* * If this was a transaction control statement, commit it. We will * start a new xact command for the next command (if any). */ finish_xact_command(); } else if (lnext(parsetree_item) == NULL) { /* * If this is the last parsetree of the query string, close down * transaction statement before reporting command-complete. This * is so that any end-of-transaction errors are reported before * the command-complete message is issued, to avoid confusing * clients who will expect either a command-complete message or an * error, not one and then the other. But for compatibility with * historical Postgres behavior, we do not force a transaction * boundary between queries appearing in a single query string. */ finish_xact_command(); } else { /* * We need a CommandCounterIncrement after every query, except * those that start or end a transaction block. */ CommandCounterIncrement(); } /* * Tell client that we're done with this query. Note we emit exactly * one EndCommand report for each raw parsetree, thus one for each SQL * command the client sent, regardless of rewriting. (But a command * aborted by error will not send an EndCommand report at all.) */ EndCommand(completionTag, dest); } /* end loop over parsetrees */ /* * Close down transaction statement, if one is open. */ finish_xact_command(); /* * If there were no parsetrees, return EmptyQueryResponse message. */ if (!parsetree_list) NullCommand(dest); QueryContext = NULL; /* * Combine processing here as we need to calculate the query duration in * both instances. */ if (save_log_duration || save_log_min_duration_statement != -1) { long usecs; gettimeofday(&stop_t, NULL); if (stop_t.tv_usec < start_t.tv_usec) { stop_t.tv_sec--; stop_t.tv_usec += 1000000; } usecs = (long) (stop_t.tv_sec - start_t.tv_sec) * 1000000 + (long) (stop_t.tv_usec - start_t.tv_usec); /* Only print duration if we previously printed the statement. */ if (was_logged && save_log_duration) ereport(LOG, (errmsg("duration: %ld.%03ld ms", (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 + (stop_t.tv_usec - start_t.tv_usec) / 1000), (long) (stop_t.tv_usec - start_t.tv_usec) % 1000))); /* * Output a duration_statement to the log if the query has exceeded * the min duration, or if we are to print all durations. */ if (save_log_min_duration_statement == 0 || (save_log_min_duration_statement > 0 && usecs >= save_log_min_duration_statement * 1000)) ereport(LOG, (errmsg("duration: %ld.%03ld ms statement: %s%s", (long) ((stop_t.tv_sec - start_t.tv_sec) * 1000 + (stop_t.tv_usec - start_t.tv_usec) / 1000), (long) (stop_t.tv_usec - start_t.tv_usec) % 1000, query_string, prepare_string ? prepare_string : ""))); } if (save_log_statement_stats) ShowUsage("QUERY STATISTICS"); if (prepare_string != NULL) pfree(prepare_string); debug_query_string = NULL;}/* * exec_parse_message * * Execute a "Parse" protocol message. */static voidexec_parse_message(const char *query_string, /* string to execute */ const char *stmt_name, /* name for prepared stmt */ Oid *paramTypes, /* parameter types */ int numParams) /* number of parameters */{ MemoryContext oldcontext; List *parsetree_list; const char *commandTag; List *querytree_list, *plantree_list, *param_list; bool is_named; bool save_log_statement_stats = log_statement_stats; /* * Report query to various monitoring facilities. */ debug_query_string = query_string; pgstat_report_activity(query_string); set_ps_display("PARSE"); if (save_log_statement_stats) ResetUsage(); if (log_statement == LOGSTMT_ALL) ereport(LOG, (errmsg("statement: PREPARE %s AS %s", (*stmt_name != '\0') ? stmt_name : "<unnamed>", query_string))); /* * Start up a transaction command so we can run parse analysis etc. (Note * that this will normally change current memory context.) Nothing happens * if we are already in one. */ start_xact_command(); /* * Switch to appropriate context for constructing parsetrees. * * We have two strategies depending on whether the prepared statement is * named or not. For a named prepared statement, we do parsing in * MessageContext and copy the finished trees into the prepared * statement's private context; then the reset of MessageContext releases * temporary space used by parsing and planning. For an unnamed prepared * statement, we assume the statement isn't going to hang around long, so * getting rid of temp space quickly is probably not worth the costs of * copying parse/plan trees. So in this case, we set up a special context * for the unnamed statement, and do all the parsing/planning therein. */ is_named = (stmt_name[0] != '\0'); if (is_named) { /* Named prepared statement --- parse in MessageContext */ oldcontext = MemoryContextSwitchTo(MessageContext); } else { /* Unnamed prepared statement --- release any prior unnamed stmt */ unnamed_stmt_pstmt = NULL; if (unnamed_stmt_context) { DropDependentPortals(unnamed_stmt_context); MemoryContextDelete(unnamed_stmt_context); } unnamed_stmt_context = NULL; /* create context for parsing/planning */ unnamed_stmt_context = AllocSetContextCreate(TopMemoryContext, "unnamed prepared statement", ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE, ALLOCSET_DEFAULT_MAXSIZE); oldcontext = MemoryContextSwitchTo(unnamed_stmt_context); } QueryContext = CurrentMemoryContext; /* * Do basic parsing of the query or queries (this should be safe even if * we are in aborted transaction state!) */ parsetree_list = pg_parse_query(query_string); /* * We only allow a single user statement in a prepared statement. This is * mainly to keep the protocol simple --- otherwise we'd need to worry * about multiple result tupdescs and things like that. */ if (list_length(parsetree_list) > 1) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("cannot insert multiple commands into a prepared statement"))); if (parsetree_list != NIL) { Node *parsetree = (Node *) linitial(parsetree_list); int i; /* * Get the command name for possible use in status display. */ commandTag = CreateCommandTag(parsetree); /* * If we are in an aborted transaction, reject all commands except * COMMIT/ROLLBACK. It is important that this test occur before we * try to do parse analysis, rewrite, or planning, since all those * phases try to do database accesses, which may fail in abort state. * (It might be safe to allow some additional utility commands in this * state, but not many...) */ if (IsAbortedTransactionBlockState() && !IsTransactionExitStmt(parsetree)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " "commands ignored until end of transaction block"))); /* * OK to analyze, rewrite, and plan this query. Note that the * originally specified parameter set is not required to be complete, * so we have to use parse_analyze_varparams(). */ if (log_parser_stats) ResetUsage(); querytree_list = parse_analyze_varparams(parsetree, ¶mTypes, &numParams); /* * Check all parameter types got determined, and convert array * representation to a list for storage. */ param_list = NIL; for (i = 0; i < numParams; i++) { Oid ptype = paramTypes[i]; if (ptype == InvalidOid || ptype == UNKNOWNOID) ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_DATATYPE), errmsg("could not determine data type of parameter $%d", i + 1))); param_list = lappend_oid(param_list, ptype); } if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); querytree_list = pg_rewrite_queries(querytree_list); /* * If this is the unnamed statement and it has parameters, defer query * planning until Bind. Otherwise do it now. */ if (!is_named && numParams > 0) plantree_list = NIL; else plantree_list = pg_plan_queries(querytree_list, NULL, true); } else { /* Empty input string. This is legal. */ commandTag = NULL; querytree_list = NIL; plantree_list = NIL; param_list = NIL; } /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); /* * Store the query as a prepared statement. See above comments. */ if (is_named) { StorePreparedStatement(stmt_name, query_string, commandTag, querytree_list, plantree_list, param_list); } else { PreparedStatement *pstmt; pstmt = (PreparedStatement *) palloc0(sizeof(PreparedStatement)); /* query_string needs to be copied into unnamed_stmt_context */ pstmt->query_string = pstrdup(query_string); /* the rest is there already */ pstmt->commandTag = commandTag; pstmt->query_list = querytree_list; pstmt->plan_list = plantree_list; pstmt->argtype_list = param_list; pstmt->context = unnamed_stmt_context; /* Now the unnamed statement is complete and valid */ unnamed_stmt_pstmt = pstmt; } MemoryContextSwitchTo(oldcontext); QueryContext = NULL; /* * We do NOT close the open transaction command here; that only happens * when the client sends Sync. Instead, do CommandCounterIncrement just * in case something happened during parse/plan. */ CommandCounterIncrement(); /* * Send ParseComplete. */ if (whereToSendOutput == DestRemote) pq_putemptymessage('1'); if (save_log_statement_stats) ShowUsage("PARSE MESSAGE STATISTICS"); debug_query_string = NULL;}/* * exec_bind_message * * Process a "Bind" message to create a portal from a prepared statement */static voidexec_bind_message(StringInfo input_message){ const char *portal_name; const char *stmt_name; int numPFormats; int16 *pformats = NULL; int numParams; int numRFormats; int16 *rformats = NULL; int i; PreparedStatement *pstmt; Portal portal; ParamListInfo params; pgstat_report_activity("<BIND>"); set_ps_display("BIND"); /* * Start up a transaction command so we can call functions etc. (Note that * this will normally change current memory context.) Nothing happens if * we are already in one. */ start_xact_command(); /* Switch back to message context */ MemoryContextSwitchTo(MessageContext); /* Get the fixed part of the message */ portal_name = pq_getmsgstring(input_message); stmt_name = pq_getmsgstring(input_message); /* Get the parameter format codes */ numPFormats = pq_getmsgint(input_message, 2); if (numPFormats > 0) { pformats = (int16 *) palloc(numPFormats * sizeof(int16)); for (i = 0; i < numPFormats; i++) pformats[i] = pq_getmsgint(input_message, 2); } /* Get the parameter value count */ numParams = pq_getmsgint(input_message, 2); if (numPFormats > 1 && numPFormats != numParams) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("bind message has %d parameter formats but %d parameters", numPFormats, numParams))); /* Find prepared statement */ if (stmt_name[0] != '\0') pstmt = FetchPreparedStatement(stmt_name, true); else { /* special-case the unnamed statement */ pstmt = unnamed_stmt_pstmt; if (!pstmt) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PSTATEMENT), errmsg("unnamed prepared statement does not exist"))); } if (numParams != list_length(pstmt->argtype_list)) ereport(ERROR, (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("bind message supplies %d parameters, but prepared statement \"%s\" requires %d", numParams, stmt_name, list_length(pstmt->argtype_list)))); /* * If we are in aborted transaction state, the only portals we can * actually run are those containing COMMIT or ROLLBACK commands. We * disallow binding anything else to avoid problems with infrastructure * that expects to run inside a valid transaction. We also disallow * binding any parameters, since we can't risk calling user-defined I/O * functions. */ if (IsAbortedTransactionBlockState() &&
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?