From 815d001dcc7a2cda50e3d55522bfaf30ad7fceee Mon Sep 17 00:00:00 2001 From: Amit Langote Date: Thu, 5 Mar 2026 17:42:19 +0900 Subject: [PATCH v7 2/5] Add RowBatch infrastructure for batched tuple processing Introduce RowBatch, a data carrier that allows table AMs to deliver multiple rows per call and the executor to process them as a group. RowBatch separates three concerns: - am_payload: opaque, AM-owned storage (e.g. HeapBatch with pinned page and tuple headers). The AM allocates this in its scan_begin_batch callback. - slots[]: TupleTableSlot array, created by RowBatchCreateSlots() with AM-appropriate slot ops. Populated from am_payload by ops->materialize_into_slots when the executor needs tuple data. - max_rows: executor-set upper bound that the AM respects when filling a batch. RowBatch does not own selection/filtering state. Which rows survive qual evaluation is the executor's concern, tracked separately in scan node state. This keeps RowBatch focused on the AM-to-executor data transfer boundary. RowBatchOps provides a vtable for AM-specific operations; currently only materialize_into_slots is defined. --- src/backend/executor/Makefile | 1 + src/backend/executor/execRowBatch.c | 54 ++++++++++++++++++ src/backend/executor/meson.build | 1 + src/include/executor/execRowBatch.h | 88 +++++++++++++++++++++++++++++ src/tools/pgindent/typedefs.list | 2 + 5 files changed, 146 insertions(+) create mode 100644 src/backend/executor/execRowBatch.c create mode 100644 src/include/executor/execRowBatch.h diff --git a/src/backend/executor/Makefile b/src/backend/executor/Makefile index 11118d0ce02..99a00e762f6 100644 --- a/src/backend/executor/Makefile +++ b/src/backend/executor/Makefile @@ -15,6 +15,7 @@ include $(top_builddir)/src/Makefile.global OBJS = \ execAmi.o \ execAsync.o \ + execRowBatch.o \ execCurrent.o \ execExpr.o \ execExprInterp.o \ diff --git a/src/backend/executor/execRowBatch.c b/src/backend/executor/execRowBatch.c new file mode 100644 index 00000000000..6a298813bd8 --- /dev/null +++ b/src/backend/executor/execRowBatch.c @@ -0,0 +1,54 @@ +/*------------------------------------------------------------------------- + * + * execRowBatch.c + * Helpers for RowBatch + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/backend/executor/execRowBatch.c + *------------------------------------------------------------------------- + */ + +#include "postgres.h" + +#include "executor/execRowBatch.h" + +/* + * RowBatchCreate + * Allocate and initialize a new RowBatch envelope. + */ +RowBatch * +RowBatchCreate(int max_rows) +{ + RowBatch *b; + + Assert(max_rows > 0); + + b = palloc(sizeof(RowBatch)); + b->am_payload = NULL; + b->ops = NULL; + b->max_rows = max_rows; + b->nrows = 0; + b->pos = 0; + b->materialized = false; + b->slot = NULL; + + return b; +} + +/* + * RowBatchReset + * Reset an existing RowBatch envelope to empty. + */ +void +RowBatchReset(RowBatch *b, bool drop_slots) +{ + Assert(b != NULL); + + b->nrows = 0; + b->pos = 0; + b->materialized = false; + /* b->slot belongs to the owning PlanState node */ +} diff --git a/src/backend/executor/meson.build b/src/backend/executor/meson.build index dc45be0b2ce..fd0bf80bacd 100644 --- a/src/backend/executor/meson.build +++ b/src/backend/executor/meson.build @@ -3,6 +3,7 @@ backend_sources += files( 'execAmi.c', 'execAsync.c', + 'execRowBatch.c', 'execCurrent.c', 'execExpr.c', 'execExprInterp.c', diff --git a/src/include/executor/execRowBatch.h b/src/include/executor/execRowBatch.h new file mode 100644 index 00000000000..021fdeecc73 --- /dev/null +++ b/src/include/executor/execRowBatch.h @@ -0,0 +1,88 @@ +/*------------------------------------------------------------------------- + * + * execRowBatch.h + * Executor batch envelope for passing row batch state upward + * + * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * IDENTIFICATION + * src/include/executor/execRowBatch.h + *------------------------------------------------------------------------- + */ +#ifndef EXECROWBATCH_H +#define EXECROWBATCH_H + +#include "executor/tuptable.h" + +typedef struct RowBatchOps RowBatchOps; + +/* + * RowBatch + * + * Data carrier from table AM to executor. The AM populates am_payload + * and nrows via scan_getnextbatch(). The executor calls ops->materialize_all + * to populate slots[] when it needs tuple data. + * + * Selection state (which rows survived qual eval) is owned by the executor, + * not the batch. + */ +typedef struct RowBatch +{ + void *am_payload; + const RowBatchOps *ops; + + int max_rows; /* executor-set upper bound */ + int nrows; /* rows TAM put in */ + int pos; /* iteration position */ + bool materialized; /* tuples in slots valid? */ + + TupleTableSlot *slot; /* row view */ +} RowBatch; + +/* + * RowBatchOps -- AM-specific operations on a RowBatch. + * + * Table AMs set b->ops during scan_begin_batch to provide + * callbacks that the executor uses to access batch contents. + * + * repoint_slot re-points the batch's single slot to the tuple at + * index idx within the current batch. The slot remains valid until + * the next call or until the batch is exhausted. + * + * Additional callbacks can be added here as new AMs or executor + * features require them. + */ +typedef struct RowBatchOps +{ + void (*repoint_slot) (RowBatch *b, int idx); +} RowBatchOps; + +/* Create/teardown */ +extern RowBatch *RowBatchCreate(int max_rows); +extern void RowBatchReset(RowBatch *b, bool drop_slots); + +/* Validation */ +static inline bool +RowBatchIsValid(RowBatch *b) +{ + return b != NULL && b->max_rows > 0; +} + +/* Iteration over materialized slots */ +static inline bool +RowBatchHasMore(RowBatch *b) +{ + return b->pos < b->nrows; +} + +static inline TupleTableSlot * +RowBatchGetNextSlot(RowBatch *b) +{ + if (b->pos >= b->nrows) + return NULL; + b->ops->repoint_slot(b, b->pos++); + return b->slot; +} + +#endif /* EXECROWBATCH_H */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 35acda59851..e5c172628b3 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -2694,6 +2694,8 @@ RoleSpec RoleSpecType RoleStmtType RollupData +RowBatch +RowBatchOps RowCompareExpr RowExpr RowIdentityVarInfo -- 2.47.3