diff options
Diffstat (limited to 'src/backend/tcop/postgres.c')
-rw-r--r-- | src/backend/tcop/postgres.c | 344 |
1 files changed, 340 insertions, 4 deletions
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 43e912f5cf..34b63041d1 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -5,6 +5,7 @@ * * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California + * Portions Copyright (c) 2010 Nippon Telegraph and Telephone Corporation * * * IDENTIFICATION @@ -71,7 +72,16 @@ #include "utils/snapmgr.h" #include "mb/pg_wchar.h" - +#ifdef PGXC +#include "storage/procarray.h" +#include "pgxc/pgxc.h" +#include "access/gtm.h" +/* PGXC_COORD */ +#include "pgxc/planner.h" +#include "pgxc/datanode.h" +/* PGXC_DATANODE */ +#include "access/transam.h" +#endif extern int optind; extern char *optarg; @@ -185,6 +195,27 @@ static void SigHupHandler(SIGNAL_ARGS); static void log_disconnections(int code, Datum arg); +#ifdef PGXC /* PGXC_DATANODE */ +static void pgxc_transaction_stmt (Node *parsetree); +static List * pgxc_execute_direct (Node *parsetree, List *querytree_list, CommandDest dest, bool snapshot_set, bool *exec_on_coord); + +/* ---------------------------------------------------------------- + * PG-XC routines + * ---------------------------------------------------------------- + */ + +/* + * Called when the backend is ending. + */ +static void +DataNodeShutdown (int code, Datum arg) +{ + /* Close connection with GTM, if active */ + if (IsAutoVacuumWorkerProcess()) + CloseGTM(); +} +#endif + /* ---------------------------------------------------------------- * routines to obtain user input * ---------------------------------------------------------------- @@ -398,6 +429,11 @@ SocketBackend(StringInfo inBuf) (errcode(ERRCODE_PROTOCOL_VIOLATION), errmsg("invalid frontend message type %d", qtype))); break; +#ifdef PGXC /* PGXC_DATANODE */ + case 'g': + case 's': + break; +#endif default: @@ -780,7 +816,6 @@ exec_simple_query(const char *query_string) bool isTopLevel; char msec_str[32]; - /* * Report query to various monitoring facilities. */ @@ -863,6 +898,22 @@ exec_simple_query(const char *query_string) Portal portal; DestReceiver *receiver; int16 format; +#ifdef PGXC + Query_Plan *query_plan; + Query_Step *query_step; + bool exec_on_coord; + + + /* + * By default we do not want data nodes to contact GTM directly, + * it should get this information passed down to it. + */ + if (IS_PGXC_DATANODE) + SetForceXidFromGTM(false); + + exec_on_coord = true; + query_plan = NULL; +#endif /* * Get the command name for use in status display (it also becomes the @@ -917,15 +968,53 @@ exec_simple_query(const char *query_string) querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); - plantree_list = pg_plan_queries(querytree_list, 0, NULL); +#ifdef PGXC /* PGXC_COORD */ + if (IS_PGXC_COORDINATOR) + { + if (IsA(parsetree, TransactionStmt)) + pgxc_transaction_stmt(parsetree); + + else if (IsA(parsetree, ExecDirectStmt)) + querytree_list = pgxc_execute_direct(parsetree, querytree_list, dest, snapshot_set, &exec_on_coord); + + else + { + query_plan = GetQueryPlan(parsetree, query_string, querytree_list); + + exec_on_coord = query_plan->exec_loc_type & EXEC_ON_COORD; + } + + /* First execute on the coordinator, if involved (DDL), then data nodes */ + } + + if ((IS_PGXC_COORDINATOR && exec_on_coord) || IS_PGXC_DATANODE) +#endif + plantree_list = pg_plan_queries(querytree_list, 0, NULL); /* Done with the snapshot used for parsing/planning */ +#ifdef PGXC + /* In PG-XC, hold on to it a bit longer */ +#else if (snapshot_set) PopActiveSnapshot(); +#endif /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); +#ifdef PGXC + /* PGXC_DATANODE */ + /* Force getting Xid from GTM if not autovacuum, but a vacuum */ + if (IS_PGXC_DATANODE && IsA(parsetree, VacuumStmt) && IsPostmasterEnvironment) + SetForceXidFromGTM(true); + + /* PGXC_COORD */ + /* Force getting Xid from GTM if not autovacuum, but a vacuum */ + /* Skip the Portal stuff on coordinator if command only executes on data nodes */ + if ((IS_PGXC_COORDINATOR && exec_on_coord) || IS_PGXC_DATANODE) + { +#endif + /* * Create unnamed portal to run the query or queries in. If there * already is one, silently drop it. @@ -999,6 +1088,33 @@ exec_simple_query(const char *query_string) PortalDrop(portal, false); +#ifdef PGXC + } + + /* PGXC_COORD */ + /* If the coordinator ran ok, now run on the data nodes if planned */ + if (IS_PGXC_COORDINATOR) + { + if (query_plan && (query_plan->exec_loc_type & EXEC_ON_DATA_NODES)) + { + query_step = linitial(query_plan->query_step_list); + + DataNodeExec(query_step->sql_statement, + query_step->nodelist, + dest, + snapshot_set ? GetActiveSnapshot() : GetTransactionSnapshot(), + query_plan->force_autocommit, + query_step->simple_aggregates, + IsA(parsetree, SelectStmt)); + } + + FreeQueryPlan(query_plan); + } + + if (snapshot_set) + PopActiveSnapshot(); +#endif /* PGXC_COORD */ + if (IsA(parsetree, TransactionStmt)) { /* @@ -1029,6 +1145,11 @@ exec_simple_query(const char *query_string) */ CommandCounterIncrement(); } +#ifdef PGXC /* PGXC_COORD */ + /* In case of PGXC handling client already received a response */ + if ((IS_PGXC_COORDINATOR && exec_on_coord) || IS_PGXC_DATANODE) + { +#endif /* * Tell client that we're done with this query. Note we emit exactly @@ -1037,6 +1158,9 @@ exec_simple_query(const char *query_string) * aborted by error will not send an EndCommand report at all.) */ EndCommand(completionTag, dest); +#ifdef PGXC /* PGXC_COORD */ + } +#endif } /* end loop over parsetrees */ /* @@ -2868,6 +2992,14 @@ PostgresMain(int argc, char *argv[], const char *username) sigjmp_buf local_sigjmp_buf; volatile bool send_ready_for_query = true; +#ifdef PGXC /* PGXC_DATANODE */ + /* Snapshot info */ + int xmin; + int xmax; + int xcnt; + int *xip; +#endif + #define PendingConfigOption(name,val) \ (guc_names = lappend(guc_names, pstrdup(name)), \ guc_values = lappend(guc_values, pstrdup(val))) @@ -2948,7 +3080,11 @@ PostgresMain(int argc, char *argv[], const char *username) * postmaster/postmaster.c (the option sets should not conflict) and with * the common help() function in main/main.c. */ +#ifdef PGXC + while ((flag = getopt(argc, argv, "A:B:Cc:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:Xy:-:")) != -1) +#else while ((flag = getopt(argc, argv, "A:B:c:D:d:EeFf:h:ijk:lN:nOo:Pp:r:S:sTt:v:W:y:-:")) != -1) +#endif { switch (flag) { @@ -2960,6 +3096,12 @@ PostgresMain(int argc, char *argv[], const char *username) SetConfigOption("shared_buffers", optarg, ctx, gucsource); break; +#ifdef PGXC + case 'C': + isPGXCCoordinator = true; + break; +#endif + case 'D': if (secure) userDoption = optarg; @@ -3082,7 +3224,11 @@ PostgresMain(int argc, char *argv[], const char *username) SetConfigOption("post_auth_delay", optarg, ctx, gucsource); break; - +#ifdef PGXC + case 'X': + isPGXCDataNode = true; + break; +#endif case 'y': /* @@ -3140,6 +3286,24 @@ PostgresMain(int argc, char *argv[], const char *username) } } +#ifdef PGXC + /* + * Make sure we specified the mode if Coordinator or Data Node. + * Allow for the exception of initdb by checking config option + */ + if (!IS_PGXC_COORDINATOR && !IS_PGXC_DATANODE && IsUnderPostmaster) + { + ereport(FATAL, + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("PG-XC: must start as either a Coordinator (-C) or Data Node (-X)\n"))); + } + if (!IsPostmasterEnvironment) + { + /* Treat it as a data node for initdb to work properly */ + isPGXCDataNode = true; + } +#endif + /* * Process any additional GUC variable settings passed in startup packet. * These are handled exactly like command-line variables. @@ -3511,6 +3675,19 @@ PostgresMain(int argc, char *argv[], const char *username) if (!ignore_till_sync) send_ready_for_query = true; /* initially, or after error */ +#ifdef PGXC /* PGXC_COORD */ + if (IS_PGXC_COORDINATOR) + { + InitMultinodeExecutor(); + /* If we exit, first try and clean connections and send to pool */ + on_proc_exit (DataNodeCleanAndRelease, 0); + } + if (IS_PGXC_DATANODE) + { + /* If we exit, first try and clean connection to GTM */ + on_proc_exit (DataNodeShutdown, 0); + } +#endif /* * Non-error queries loop here. */ @@ -3560,6 +3737,15 @@ PostgresMain(int argc, char *argv[], const char *username) } ReadyForQuery(whereToSendOutput); +#ifdef PGXC + /* + * Helps us catch any problems where we did not send down a snapshot + * when it was expected. + */ + if (IS_PGXC_DATANODE) + UnsetGlobalSnapshotData(); +#endif + send_ready_for_query = false; } @@ -3832,6 +4018,42 @@ PostgresMain(int argc, char *argv[], const char *username) * is still sending data. */ break; +#ifdef PGXC /* PGXC_DATANODE */ + case 'g': /* gxid */ + { + /* Set the GXID we were passed down */ + TransactionId gxid = (TransactionId) pq_getmsgint(&input_message, 4); + elog(DEBUG1, "Received new gxid %u", gxid); + SetNextTransactionId(gxid); + pq_getmsgend(&input_message); + } + break; + + case 's': /* snapshot */ + /* Set the snapshot we were passed down */ + xmin = pq_getmsgint(&input_message, 4); + xmax = pq_getmsgint(&input_message, 4); + RecentGlobalXmin = pq_getmsgint(&input_message, 4); + xcnt = pq_getmsgint(&input_message, 4); + if (xcnt > 0) + { + int i; + xip = malloc(xcnt * 4); + if (xip == NULL) + { + ereport(ERROR, + (errcode(ERRCODE_OUT_OF_MEMORY), + errmsg("out of memory"))); + } + for (i = 0; i < xcnt; i++) + xip[i] = pq_getmsgint(&input_message, 4); + } + else + xip = NULL; + pq_getmsgend(&input_message); + SetGlobalSnapshotData(xmin, xmax, xcnt, xip); + break; +#endif /* PGXC */ default: ereport(FATAL, @@ -4023,3 +4245,117 @@ log_disconnections(int code, Datum arg) port->user_name, port->database_name, port->remote_host, port->remote_port[0] ? " port=" : "", port->remote_port))); } + + +#ifdef PGXC +/* + * Handle transaction statements in PG-XC + */ +void +pgxc_transaction_stmt (Node *parsetree) +{ + Assert(IS_PGXC_COORDINATOR); + + + /* Handle transaction statements specially */ + if (IsA(parsetree, TransactionStmt)) + { + TransactionStmt *stmt = (TransactionStmt *) parsetree; + + switch (stmt->kind) + { + case TRANS_STMT_BEGIN: + /* + * This does not yet send down a BEGIN, + * we do that "on demand" as data nodes are added + */ + DataNodeBegin(); + break; + + case TRANS_STMT_COMMIT: + DataNodeCommit(DestNone); + break; + + case TRANS_STMT_ROLLBACK: + DataNodeRollback(DestNone); + break; + + default: + /* Ignore others for prototype */ + break; + } + } +} + + +/* + * Handle EXECUTE DIRECT + */ +List * +pgxc_execute_direct (Node *parsetree, List *querytree_list, CommandDest dest, bool snapshot_set, bool *exec_on_coord) +{ + List *node_list = NIL; + List *parsetree_list; + ListCell *node_cell; + ExecDirectStmt *execdirect = (ExecDirectStmt *) parsetree; + bool on_coord = execdirect->coordinator; + + + Assert(IS_PGXC_COORDINATOR); + Assert(IsA(parsetree, ExecDirectStmt)); + + foreach (node_cell, execdirect->nodes) + { + int node_int = intVal(lfirst(node_cell)); + node_list = lappend_int(node_list, node_int); + } + if (node_list) + if (DataNodeExec(execdirect->query, + node_list, + dest, + snapshot_set ? GetActiveSnapshot() : GetTransactionSnapshot(), + FALSE, + FALSE, + FALSE) != 0) + on_coord = false; + + if (on_coord) + { + /* + * Parse inner statement, like at the begiining of the function + * We do not have to release wrapper trees, the message context + * will be deleted later + * Also, no need to switch context - current is already + * the MessageContext + */ + parsetree_list = pg_parse_query(execdirect->query); + + /* We do not want to log or display the inner command */ + + /* + * we do not support complex commands (expanded to multiple + * parse trees) within EXEC DIRECT + */ + if (list_length(parsetree_list) != 1) + { + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("Can not execute %s with EXECUTE DIRECT", + execdirect->query))); + } + + /* + * Get parse tree from the list + */ + parsetree = (Node *) lfirst(list_head(parsetree_list)); + + /* + * Build new query tree */ + querytree_list = pg_analyze_and_rewrite(parsetree, + execdirect->query, NULL, 0); + } + *exec_on_coord = on_coord; + + return querytree_list; +} +#endif /* PGXC */ |