* PortalRunSelect * Execute a portal's query in PORTAL_ONE_SELECT mode, and also * when fetching from a completed holdStore in PORTAL_ONE_RETURNING, * PORTAL_ONE_MOD_WITH, and PORTAL_UTIL_SELECT cases. * * This handles simple N-rows-forward-or-backward cases. For more complex * nonsequential access to a portal, see PortalRunFetch. * * count <= 0 is interpreted as a no-op: the destinati
| 1075 | * Returns number of rows processed (suitable for use in result tag) |
| 1076 | */ |
| 1077 | static uint64 |
| 1078 | PortalRunSelect(Portal portal, |
| 1079 | bool forward, |
| 1080 | int64 count, |
| 1081 | DestReceiver *dest) |
| 1082 | { |
| 1083 | QueryDesc *queryDesc; |
| 1084 | ScanDirection direction; |
| 1085 | uint64 nprocessed; |
| 1086 | |
| 1087 | /* |
| 1088 | * NB: queryDesc will be NULL if we are fetching from a held cursor or a |
| 1089 | * completed utility query; can't use it in that path. |
| 1090 | */ |
| 1091 | queryDesc = portal->queryDesc; |
| 1092 | |
| 1093 | /* Caller messed up if we have neither a ready query nor held data. */ |
| 1094 | Assert(queryDesc || portal->holdStore); |
| 1095 | |
| 1096 | /* |
| 1097 | * Force the queryDesc destination to the right thing. This supports |
| 1098 | * MOVE, for example, which will pass in dest = DestNone. This is okay to |
| 1099 | * change as long as we do it on every fetch. (The Executor must not |
| 1100 | * assume that dest never changes.) |
| 1101 | */ |
| 1102 | if (queryDesc) |
| 1103 | queryDesc->dest = dest; |
| 1104 | |
| 1105 | /* |
| 1106 | * Determine which direction to go in, and check to see if we're already |
| 1107 | * at the end of the available tuples in that direction. If so, set the |
| 1108 | * direction to NoMovement to avoid trying to fetch any tuples. (This |
| 1109 | * check exists because not all plan node types are robust about being |
| 1110 | * called again if they've already returned NULL once.) Then call the |
| 1111 | * executor (we must not skip this, because the destination needs to see a |
| 1112 | * setup and shutdown even if no tuples are available). Finally, update |
| 1113 | * the portal position state depending on the number of tuples that were |
| 1114 | * retrieved. |
| 1115 | */ |
| 1116 | if (forward) |
| 1117 | { |
| 1118 | if (portal->atEnd || count <= 0) |
| 1119 | { |
| 1120 | direction = NoMovementScanDirection; |
| 1121 | count = 0; /* don't pass negative count to executor */ |
| 1122 | } |
| 1123 | else |
| 1124 | direction = ForwardScanDirection; |
| 1125 | |
| 1126 | /* In the executor, zero count processes all rows */ |
| 1127 | if (count == FETCH_ALL) |
| 1128 | count = 0; |
| 1129 | |
| 1130 | if (portal->holdStore) |
| 1131 | nprocessed = RunFromStore(portal, direction, (uint64) count, dest); |
| 1132 | else |
| 1133 | { |
| 1134 | PushActiveSnapshot(queryDesc->snapshot); |
no test coverage detected