| 1329 | } |
| 1330 | |
| 1331 | static uint64 |
| 1332 | fetch_rows(CursorData *c, bool exact) |
| 1333 | { |
| 1334 | uint64 can_read_rows; |
| 1335 | |
| 1336 | if (!c->executed) |
| 1337 | ereport(ERROR, |
| 1338 | (errcode(ERRCODE_INVALID_CURSOR_STATE), |
| 1339 | errmsg("cursor is not executed"))); |
| 1340 | |
| 1341 | if (!c->portal) |
| 1342 | ereport(ERROR, |
| 1343 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), |
| 1344 | errmsg("cursor has not portal"))); |
| 1345 | |
| 1346 | if (c->nread == c->processed) |
| 1347 | { |
| 1348 | MemoryContext oldcxt; |
| 1349 | uint64 i; |
| 1350 | int batch_rows; |
| 1351 | |
| 1352 | if (!exact) |
| 1353 | { |
| 1354 | if (c->array_columns) |
| 1355 | batch_rows = (1000 / c->batch_rows) * c->batch_rows; |
| 1356 | else |
| 1357 | batch_rows = 1000; |
| 1358 | } |
| 1359 | else |
| 1360 | batch_rows = 2; |
| 1361 | |
| 1362 | /* create or reset context for tuples */ |
| 1363 | if (!c->tuples_cxt) |
| 1364 | c->tuples_cxt = AllocSetContextCreate(c->cursor_xact_cxt, |
| 1365 | "dbms_sql tuples context", |
| 1366 | ALLOCSET_DEFAULT_SIZES); |
| 1367 | else |
| 1368 | MemoryContextReset(c->tuples_cxt); |
| 1369 | |
| 1370 | if (SPI_connect() != SPI_OK_CONNECT) |
| 1371 | elog(ERROR, "SPI_connact failed"); |
| 1372 | |
| 1373 | /* try to fetch data from cursor */ |
| 1374 | SPI_cursor_fetch(c->portal, true, batch_rows); |
| 1375 | |
| 1376 | if (SPI_tuptable == NULL) |
| 1377 | elog(ERROR, "cannot fetch data"); |
| 1378 | |
| 1379 | if (exact && SPI_processed > 1) |
| 1380 | ereport(ERROR, |
| 1381 | (errcode(ERRCODE_TOO_MANY_ROWS), |
| 1382 | errmsg("too many rows"), |
| 1383 | errdetail("In exact mode only one row is expected"))); |
| 1384 | |
| 1385 | if (exact && SPI_processed == 0) |
| 1386 | ereport(ERROR, |
| 1387 | (errcode(ERRCODE_NO_DATA_FOUND), |
| 1388 | errmsg("no data found"), |
no test coverage detected