StoreQueryResult Query::store() { executeImpl(); MYSQL_RES * res = mysql_store_result(conn->getDriver()); if (!res) checkError(conn->getDriver()); return StoreQueryResult(res, conn, this); }
/* * ExecuteTaskAndStoreResults executes the task on the remote node, retrieves * the results and stores them, if SELECT or RETURNING is used, in a tuple * store. * * If the task fails on one of the placements, the function retries it on * other placements (SELECT), reraises the remote error (constraint violation * in DML), marks the affected placement as invalid (DML on some placement * failed), or errors out (DML failed on all placements). */ static bool ExecuteTaskAndStoreResults(QueryDesc *queryDesc, Task *task, bool isModificationQuery, bool expectResults) { TupleDesc tupleDescriptor = queryDesc->tupDesc; EState *executorState = queryDesc->estate; MaterialState *routerState = (MaterialState *) queryDesc->planstate; bool resultsOK = false; List *taskPlacementList = task->taskPlacementList; ListCell *taskPlacementCell = NULL; List *failedPlacementList = NIL; ListCell *failedPlacementCell = NULL; int64 affectedTupleCount = -1; bool gotResults = false; /* * Try to run the query to completion on one placement. If the query fails * attempt the query on the next placement. */ foreach(taskPlacementCell, taskPlacementList) { ShardPlacement *taskPlacement = (ShardPlacement *) lfirst(taskPlacementCell); char *nodeName = taskPlacement->nodeName; int32 nodePort = taskPlacement->nodePort; bool queryOK = false; int64 currentAffectedTupleCount = 0; PGconn *connection = GetOrEstablishConnection(nodeName, nodePort); if (connection == NULL) { failedPlacementList = lappend(failedPlacementList, taskPlacement); continue; } queryOK = SendQueryInSingleRowMode(connection, task->queryString); if (!queryOK) { PurgeConnection(connection); failedPlacementList = lappend(failedPlacementList, taskPlacement); continue; } /* * If caller is interested, store query results the first time * through. The output of the query's execution on other shards is * discarded if we run there (because it's a modification query). */ if (!gotResults && expectResults) { queryOK = StoreQueryResult(routerState, connection, tupleDescriptor, ¤tAffectedTupleCount); } else { queryOK = ConsumeQueryResult(connection, ¤tAffectedTupleCount); } if (queryOK) { if ((affectedTupleCount == -1) || (affectedTupleCount == currentAffectedTupleCount)) { affectedTupleCount = currentAffectedTupleCount; } else { ereport(WARNING, (errmsg("modified "INT64_FORMAT " tuples, but expected " "to modify "INT64_FORMAT, currentAffectedTupleCount, affectedTupleCount), errdetail("modified placement on %s:%d", nodeName, nodePort))); } #if (PG_VERSION_NUM < 90600) /* before 9.6, PostgreSQL used a uint32 for this field, so check */ Assert(currentAffectedTupleCount <= 0xFFFFFFFF); #endif resultsOK = true; gotResults = true; /* * Modifications have to be executed on all placements, but for * read queries we can stop here. */ if (!isModificationQuery) { break; } } else { PurgeConnection(connection); failedPlacementList = lappend(failedPlacementList, taskPlacement); continue; } }