postgres.c
来自「PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统」· C语言 代码 · 共 2,390 行 · 第 1/5 页
C
2,390 行
(!IsTransactionExitStmtList(pstmt->query_list) || numParams != 0)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " "commands ignored until end of transaction block"))); /* * Create the portal. Allow silent replacement of an existing portal only * if the unnamed portal is specified. */ if (portal_name[0] == '\0') portal = CreatePortal(portal_name, true, true); else portal = CreatePortal(portal_name, false, false); /* We need to output the parameter values someday */ if (log_statement == LOGSTMT_ALL) ereport(LOG, (errmsg("statement: <BIND> %s", portal_name))); /* * Fetch parameters, if any, and store in the portal's memory context. */ if (numParams > 0) { ListCell *l; MemoryContext oldContext; oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); params = (ParamListInfo) palloc0((numParams + 1) * sizeof(ParamListInfoData)); i = 0; foreach(l, pstmt->argtype_list) { Oid ptype = lfirst_oid(l); int32 plength; bool isNull; plength = pq_getmsgint(input_message, 4); isNull = (plength == -1); if (!isNull) { const char *pvalue = pq_getmsgbytes(input_message, plength); int16 pformat; StringInfoData pbuf; char csave; if (numPFormats > 1) pformat = pformats[i]; else if (numPFormats > 0) pformat = pformats[0]; else pformat = 0; /* default = text */ /* * Rather than copying data around, we just set up a phony * StringInfo pointing to the correct portion of the message * buffer. We assume we can scribble on the message buffer so * as to maintain the convention that StringInfos have a * trailing null. This is grotty but is a big win when * dealing with very large parameter strings. */ pbuf.data = (char *) pvalue; pbuf.maxlen = plength + 1; pbuf.len = plength; pbuf.cursor = 0; csave = pbuf.data[plength]; pbuf.data[plength] = '\0'; if (pformat == 0) { Oid typinput; Oid typioparam; char *pstring; getTypeInputInfo(ptype, &typinput, &typioparam); /* * We have to do encoding conversion before calling the * typinput routine. */ pstring = pg_client_to_server(pbuf.data, plength); params[i].value = OidFunctionCall3(typinput, CStringGetDatum(pstring), ObjectIdGetDatum(typioparam), Int32GetDatum(-1)); /* Free result of encoding conversion, if any */ if (pstring != pbuf.data) pfree(pstring); } else if (pformat == 1) { Oid typreceive; Oid typioparam; /* * Call the parameter type's binary input converter */ getTypeBinaryInputInfo(ptype, &typreceive, &typioparam); params[i].value = OidFunctionCall3(typreceive, PointerGetDatum(&pbuf), ObjectIdGetDatum(typioparam), Int32GetDatum(-1)); /* Trouble if it didn't eat the whole buffer */ if (pbuf.cursor != pbuf.len) ereport(ERROR, (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION), errmsg("incorrect binary data format in bind parameter %d", i + 1))); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("unsupported format code: %d", pformat))); } /* Restore message buffer contents */ pbuf.data[plength] = csave; } params[i].kind = PARAM_NUM; params[i].id = i + 1; params[i].ptype = ptype; params[i].isnull = isNull; i++; } params[i].kind = PARAM_INVALID; MemoryContextSwitchTo(oldContext); } else params = NULL; /* Get the result format codes */ numRFormats = pq_getmsgint(input_message, 2); if (numRFormats > 0) { rformats = (int16 *) palloc(numRFormats * sizeof(int16)); for (i = 0; i < numRFormats; i++) rformats[i] = pq_getmsgint(input_message, 2); } pq_getmsgend(input_message); /* * If we didn't plan the query before, do it now. This allows the planner * to make use of the concrete parameter values we now have. * * This happens only for unnamed statements, and so switching into the * statement context for planning is correct (see notes in * exec_parse_message). */ if (pstmt->plan_list == NIL && pstmt->query_list != NIL) { MemoryContext oldContext = MemoryContextSwitchTo(pstmt->context); pstmt->plan_list = pg_plan_queries(pstmt->query_list, params, true); MemoryContextSwitchTo(oldContext); } /* * Define portal and start execution. */ PortalDefineQuery(portal, pstmt->query_string, pstmt->commandTag, pstmt->query_list, pstmt->plan_list, pstmt->context); PortalStart(portal, params, InvalidSnapshot); /* * Apply the result format requests to the portal. */ PortalSetResultFormat(portal, numRFormats, rformats); /* * Send BindComplete. */ if (whereToSendOutput == DestRemote) pq_putemptymessage('2');}/* * exec_execute_message * * Process an "Execute" message for a portal */static voidexec_execute_message(const char *portal_name, long max_rows){ CommandDest dest; DestReceiver *receiver; Portal portal; bool completed; char completionTag[COMPLETION_TAG_BUFSIZE]; struct timeval start_t, stop_t; bool save_log_duration = log_duration; int save_log_min_duration_statement = log_min_duration_statement; bool save_log_statement_stats = log_statement_stats; bool execute_is_fetch = false; /* Adjust destination to tell printtup.c what to do */ dest = whereToSendOutput; if (dest == DestRemote) dest = DestRemoteExecute; portal = GetPortalByName(portal_name); if (!PortalIsValid(portal)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_CURSOR), errmsg("portal \"%s\" does not exist", portal_name))); /* * If we re-issue an Execute protocol request against an existing portal, * then we are only fetching more rows rather than completely re-executing * the query from the start. atStart is never reset for a v3 portal, so we * are safe to use this check. */ if (!portal->atStart) execute_is_fetch = true; /* * If the original query was a null string, just return * EmptyQueryResponse. */ if (portal->commandTag == NULL) { Assert(portal->parseTrees == NIL); NullCommand(dest); return; } /* Should we display the portal names here? */ if (execute_is_fetch) { debug_query_string = "fetch message"; pgstat_report_activity("<FETCH>"); } else if (portal->sourceText) { debug_query_string = portal->sourceText; pgstat_report_activity(portal->sourceText); } else { debug_query_string = "execute message"; pgstat_report_activity("<EXECUTE>"); } set_ps_display(portal->commandTag); /* * We use save_log_* so "SET log_duration = true" and "SET * log_min_duration_statement = true" don't report incorrect time because * gettimeofday() wasn't called. Similarly, log_statement_stats has to be * captured once. */ if (save_log_duration || save_log_min_duration_statement != -1) gettimeofday(&start_t, NULL); if (save_log_statement_stats) ResetUsage(); if (log_statement == LOGSTMT_ALL) /* We have the portal, so output the source query. */ ereport(LOG, (errmsg("statement: %sEXECUTE %s [PREPARE: %s]", (execute_is_fetch) ? "FETCH from " : "", (*portal_name != '\0') ? portal_name : "<unnamed>", portal->sourceText ? portal->sourceText : ""))); BeginCommand(portal->commandTag, dest); /* * Create dest receiver in MessageContext (we don't want it in transaction * context, because that may get deleted if portal contains VACUUM). */ receiver = CreateDestReceiver(dest, portal); /* * Ensure we are in a transaction command (this should normally be the * case already due to prior BIND). */ start_xact_command(); /* * If we are in aborted transaction state, the only portals we can * actually run are those containing COMMIT or ROLLBACK commands. */ if (IsAbortedTransactionBlockState() && !IsTransactionExitStmtList(portal->parseTrees)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " "commands ignored until end of transaction block"))); /* Check for cancel signal before we start execution */ CHECK_FOR_INTERRUPTS(); /* * Okay to run the portal. */ if (max_rows <= 0) max_rows = FETCH_ALL; completed = PortalRun(portal, max_rows, receiver, receiver, completionTag); (*receiver->rDestroy) (receiver); if (completed) { if (IsTransactionStmtList(portal->parseTrees)) { /* * 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 { /* * We need a CommandCounterIncrement after every query, except * those that start or end a transaction block. */ CommandCounterIncrement(); } /* Send appropriate CommandComplete to client */ EndCommand(completionTag, dest); } else { /* Portal run not complete, so send PortalSuspended */ if (whereToSendOutput == DestRemote) pq_putemptymessage('s'); } /* * 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 (log_statement == LOGSTMT_ALL && 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: %sEXECUTE %s [PREPARE: %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, (execute_is_fetch) ? "FETCH from " : "", (*portal_name != '\0') ? portal_name : "<unnamed>", portal->sourceText ? portal->sourceText : ""))); } if (save_log_statement_stats) ShowUsage("QUERY STATISTICS"); debug_query_string = NULL;}/* * exec_describe_statement_message * * Process a "Describe" message for a prepared statement */static voidexec_describe_statement_message(const char *stmt_name){ PreparedStatement *pstmt; TupleDesc tupdesc; ListCell *l; StringInfoData buf; /* * Start up a transaction command. (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); /* 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 we are in aborted transaction state, we can't safely create a result * tupledesc, because that needs catalog accesses. Hence, refuse to * Describe statements that return data. (We shouldn't just refuse all * Describes, since that might break the ability of some clients to issue * COMMIT or ROLLBACK commands, if they use code that blindly Describes * whatever it does.) We can Describe parameters without doing anything * dangerous, so we don't restrict that. */ if (IsAbortedTransactionBlockState() && PreparedStatementReturnsTuples(pstmt)) ereport(ERROR, (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION), errmsg("current transaction is aborted, " "commands ignored until end of transaction block"))); if (whereToSendOutput != DestRemote) return; /* can't actually do anything... */ /* * First describe the parameters... */ pq_beginmessage(&buf, 't'); /* parameter description message type */ pq_sendint(&buf, list_length(pstmt->argtype_list), 2); foreach(l, pstmt->argtype_list) { Oid ptype = lfirst_oid(l); pq_sendint(&buf, (int) ptype, 4); } pq_endmessage(&buf); /* * Next send RowDescription or NoData to describe the result... */ tupdesc = FetchPreparedStatementResultDesc(pstmt);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?