faster-plpgsql-datum-setup-1.patch
text/x-diff
Filename: faster-plpgsql-datum-setup-1.patch
Type: text/x-diff
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/pl/plpgsql/src/pl_comp.c | 0 | 0 |
| src/pl/plpgsql/src/pl_exec.c | 0 | 0 |
| src/pl/plpgsql/src/pl_gram.y | 0 | 0 |
| src/pl/plpgsql/src/plpgsql.h | 0 | 0 |
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index 7d966e7..ca7d152 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** plpgsql_adddatum(PLpgSQL_datum *new)
*** 2181,2192 ****
--- 2181,2209 ----
static void
plpgsql_finish_datums(PLpgSQL_function *function)
{
+ Size copiable_size = 0;
int i;
function->ndatums = plpgsql_nDatums;
function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
for (i = 0; i < plpgsql_nDatums; i++)
+ {
function->datums[i] = plpgsql_Datums[i];
+
+ /* This must agree with copy_plpgsql_datums on what is copiable */
+ switch (function->datums[i]->dtype)
+ {
+ case PLPGSQL_DTYPE_VAR:
+ copiable_size += MAXALIGN(sizeof(PLpgSQL_var));
+ break;
+ case PLPGSQL_DTYPE_REC:
+ copiable_size += MAXALIGN(sizeof(PLpgSQL_rec));
+ break;
+ default:
+ break;
+ }
+ }
+ function->copiable_size = copiable_size;
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index a0a10f2..e0ed19f 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** static HTAB *shared_cast_hash = NULL;
*** 161,167 ****
static void coerce_function_result_tuple(PLpgSQL_execstate *estate,
TupleDesc tupdesc);
static void plpgsql_exec_error_callback(void *arg);
! static PLpgSQL_datum *copy_plpgsql_datum(PLpgSQL_datum *datum);
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
static void push_stmt_mcontext(PLpgSQL_execstate *estate);
static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
--- 161,168 ----
static void coerce_function_result_tuple(PLpgSQL_execstate *estate,
TupleDesc tupdesc);
static void plpgsql_exec_error_callback(void *arg);
! static void copy_plpgsql_datums(PLpgSQL_execstate *estate,
! PLpgSQL_function *func);
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
static void push_stmt_mcontext(PLpgSQL_execstate *estate);
static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
*************** plpgsql_exec_function(PLpgSQL_function *
*** 380,387 ****
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! for (i = 0; i < estate.ndatums; i++)
! estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
/*
* Store the actual call argument values into the appropriate variables
--- 381,387 ----
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! copy_plpgsql_datums(&estate, func);
/*
* Store the actual call argument values into the appropriate variables
*************** plpgsql_exec_trigger(PLpgSQL_function *f
*** 772,779 ****
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! for (i = 0; i < estate.ndatums; i++)
! estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
/*
* Put the OLD and NEW tuples into record variables
--- 772,778 ----
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! copy_plpgsql_datums(&estate, func);
/*
* Put the OLD and NEW tuples into record variables
*************** plpgsql_exec_event_trigger(PLpgSQL_funct
*** 1066,1072 ****
{
PLpgSQL_execstate estate;
ErrorContextCallback plerrcontext;
- int i;
int rc;
PLpgSQL_var *var;
--- 1065,1070 ----
*************** plpgsql_exec_event_trigger(PLpgSQL_funct
*** 1087,1094 ****
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! for (i = 0; i < estate.ndatums; i++)
! estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
/*
* Assign the special tg_ variables
--- 1085,1091 ----
* Make local execution copies of all the datums
*/
estate.err_text = gettext_noop("during initialization of execution state");
! copy_plpgsql_datums(&estate, func);
/*
* Assign the special tg_ variables
*************** plpgsql_exec_error_callback(void *arg)
*** 1203,1259 ****
* Support function for initializing local execution variables
* ----------
*/
! static PLpgSQL_datum *
! copy_plpgsql_datum(PLpgSQL_datum *datum)
{
! PLpgSQL_datum *result;
! switch (datum->dtype)
! {
! case PLPGSQL_DTYPE_VAR:
! {
! PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var));
! memcpy(new, datum, sizeof(PLpgSQL_var));
! /* should be preset to null/non-freeable */
! Assert(new->isnull);
! Assert(!new->freeval);
! result = (PLpgSQL_datum *) new;
! }
! break;
! case PLPGSQL_DTYPE_REC:
! {
! PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec));
! memcpy(new, datum, sizeof(PLpgSQL_rec));
! /* should be preset to empty */
! Assert(new->erh == NULL);
! result = (PLpgSQL_datum *) new;
! }
! break;
! case PLPGSQL_DTYPE_ROW:
! case PLPGSQL_DTYPE_RECFIELD:
! case PLPGSQL_DTYPE_ARRAYELEM:
! /*
! * These datum records are read-only at runtime, so no need to
! * copy them (well, RECFIELD and ARRAYELEM contain cached data,
! * but we'd just as soon centralize the caching anyway)
! */
! result = datum;
! break;
! default:
! elog(ERROR, "unrecognized dtype: %d", datum->dtype);
! result = NULL; /* keep compiler quiet */
! break;
}
! return result;
}
/*
--- 1200,1272 ----
* Support function for initializing local execution variables
* ----------
*/
! static void
! copy_plpgsql_datums(PLpgSQL_execstate *estate,
! PLpgSQL_function *func)
{
! int ndatums = estate->ndatums;
! PLpgSQL_datum **indatums;
! PLpgSQL_datum **outdatums;
! char *workspace;
! char *ws_next;
! int i;
! /* Allocate local datum-pointer array */
! estate->datums = (PLpgSQL_datum **)
! palloc(sizeof(PLpgSQL_datum *) * ndatums);
! /*
! * To reduce palloc overhead, we make a single palloc request for all the
! * space needed for locally-instantiated datums.
! */
! workspace = palloc(func->copiable_size);
! ws_next = workspace;
! /* Fill datum-pointer array, copying datums into workspace as needed */
! indatums = func->datums;
! outdatums = estate->datums;
! for (i = 0; i < ndatums; i++)
! {
! PLpgSQL_datum *indatum = indatums[i];
! PLpgSQL_datum *outdatum;
! /* This must agree with plpgsql_finish_datums on what is copiable */
! switch (indatum->dtype)
! {
! case PLPGSQL_DTYPE_VAR:
! outdatum = (PLpgSQL_datum *) ws_next;
! memcpy(outdatum, indatum, sizeof(PLpgSQL_var));
! ws_next += MAXALIGN(sizeof(PLpgSQL_var));
! break;
! case PLPGSQL_DTYPE_REC:
! outdatum = (PLpgSQL_datum *) ws_next;
! memcpy(outdatum, indatum, sizeof(PLpgSQL_rec));
! ws_next += MAXALIGN(sizeof(PLpgSQL_rec));
! break;
! case PLPGSQL_DTYPE_ROW:
! case PLPGSQL_DTYPE_RECFIELD:
! case PLPGSQL_DTYPE_ARRAYELEM:
! /*
! * These datum records are read-only at runtime, so no need to
! * copy them (well, RECFIELD and ARRAYELEM contain cached
! * data, but we'd just as soon centralize the caching anyway).
! */
! outdatum = indatum;
! break;
! default:
! elog(ERROR, "unrecognized dtype: %d", indatum->dtype);
! outdatum = NULL; /* keep compiler quiet */
! break;
! }
! outdatums[i] = outdatum;
}
! Assert(ws_next == workspace + func->copiable_size);
}
/*
*************** plpgsql_estate_setup(PLpgSQL_execstate *
*** 3560,3567 ****
estate->found_varno = func->found_varno;
estate->ndatums = func->ndatums;
! estate->datums = palloc(sizeof(PLpgSQL_datum *) * estate->ndatums);
! /* caller is expected to fill the datums array */
estate->datum_context = CurrentMemoryContext;
/* initialize our ParamListInfo with appropriate hook functions */
--- 3573,3580 ----
estate->found_varno = func->found_varno;
estate->ndatums = func->ndatums;
! estate->datums = NULL;
! /* the datums array will be filled by copy_plpgsql_datums() */
estate->datum_context = CurrentMemoryContext;
/* initialize our ParamListInfo with appropriate hook functions */
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 3bd2493..df4694b 100644
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
*************** decl_statement : decl_varname decl_const
*** 561,567 ****
curname_def = palloc0(sizeof(PLpgSQL_expr));
- curname_def->dtype = PLPGSQL_DTYPE_EXPR;
strcpy(buf, "SELECT ");
cp1 = new->refname;
cp2 = buf + strlen(buf);
--- 561,566 ----
*************** read_sql_construct(int until,
*** 2663,2669 ****
}
expr = palloc0(sizeof(PLpgSQL_expr));
- expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = pstrdup(ds.data);
expr->plan = NULL;
expr->paramnos = NULL;
--- 2662,2667 ----
*************** make_execsql_stmt(int firsttoken, int lo
*** 2910,2916 ****
ds.data[--ds.len] = '\0';
expr = palloc0(sizeof(PLpgSQL_expr));
- expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = pstrdup(ds.data);
expr->plan = NULL;
expr->paramnos = NULL;
--- 2908,2913 ----
*************** read_cursor_args(PLpgSQL_var *cursor, in
*** 3782,3788 ****
appendStringInfoChar(&ds, ';');
expr = palloc0(sizeof(PLpgSQL_expr));
- expr->dtype = PLPGSQL_DTYPE_EXPR;
expr->query = pstrdup(ds.data);
expr->plan = NULL;
expr->paramnos = NULL;
--- 3779,3784 ----
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 21dc41f..01c14e3 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef enum PLpgSQL_datum_type
*** 63,70 ****
PLPGSQL_DTYPE_ROW,
PLPGSQL_DTYPE_REC,
PLPGSQL_DTYPE_RECFIELD,
! PLPGSQL_DTYPE_ARRAYELEM,
! PLPGSQL_DTYPE_EXPR
} PLpgSQL_datum_type;
/*
--- 63,69 ----
PLPGSQL_DTYPE_ROW,
PLPGSQL_DTYPE_REC,
PLPGSQL_DTYPE_RECFIELD,
! PLPGSQL_DTYPE_ARRAYELEM
} PLpgSQL_datum_type;
/*
*************** typedef struct PLpgSQL_type
*** 187,224 ****
} PLpgSQL_type;
/*
- * Generic datum array item
- *
- * PLpgSQL_datum is the common supertype for PLpgSQL_expr, PLpgSQL_var,
- * PLpgSQL_row, PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem
- */
- typedef struct PLpgSQL_datum
- {
- PLpgSQL_datum_type dtype;
- int dno;
- } PLpgSQL_datum;
-
- /*
- * Scalar or composite variable
- *
- * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
- * fields
- */
- typedef struct PLpgSQL_variable
- {
- PLpgSQL_datum_type dtype;
- int dno;
- char *refname;
- int lineno;
- } PLpgSQL_variable;
-
- /*
* SQL Query to plan and execute
*/
typedef struct PLpgSQL_expr
{
- PLpgSQL_datum_type dtype;
- int dno;
char *query;
SPIPlanPtr plan;
Bitmapset *paramnos; /* all dnos referenced by this query */
--- 186,195 ----
*************** typedef struct PLpgSQL_expr
*** 248,253 ****
--- 219,250 ----
} PLpgSQL_expr;
/*
+ * Generic datum array item
+ *
+ * PLpgSQL_datum is the common supertype for PLpgSQL_var, PLpgSQL_row,
+ * PLpgSQL_rec, PLpgSQL_recfield, and PLpgSQL_arrayelem.
+ */
+ typedef struct PLpgSQL_datum
+ {
+ PLpgSQL_datum_type dtype;
+ int dno;
+ } PLpgSQL_datum;
+
+ /*
+ * Scalar or composite variable
+ *
+ * The variants PLpgSQL_var, PLpgSQL_row, and PLpgSQL_rec share these
+ * fields.
+ */
+ typedef struct PLpgSQL_variable
+ {
+ PLpgSQL_datum_type dtype;
+ int dno;
+ char *refname;
+ int lineno;
+ } PLpgSQL_variable;
+
+ /*
* Scalar variable
*/
typedef struct PLpgSQL_var
*************** typedef struct PLpgSQL_var
*** 256,266 ****
int dno;
char *refname;
int lineno;
PLpgSQL_type *datatype;
- int isconst;
- int notnull;
PLpgSQL_expr *default_val;
PLpgSQL_expr *cursor_explicit_expr;
int cursor_explicit_argrow;
int cursor_options;
--- 253,270 ----
int dno;
char *refname;
int lineno;
+ /* end of PLpgSQL_variable fields */
+ bool isconst;
+ bool notnull;
PLpgSQL_type *datatype;
PLpgSQL_expr *default_val;
+
+ /*
+ * Variables declared as CURSOR FOR <query> are mostly like ordinary
+ * scalar variables of type refcursor, but they have these additional
+ * properties:
+ */
PLpgSQL_expr *cursor_explicit_expr;
int cursor_explicit_argrow;
int cursor_options;
*************** typedef struct PLpgSQL_row
*** 284,289 ****
--- 288,294 ----
int dno;
char *refname;
int lineno;
+ /* end of PLpgSQL_variable fields */
/*
* rowtupdesc is only set up if we might need to convert the row into a
*************** typedef struct PLpgSQL_rec
*** 306,311 ****
--- 311,318 ----
int dno;
char *refname;
int lineno;
+ /* end of PLpgSQL_variable fields */
+
Oid rectypeid; /* declared type of variable */
/* RECFIELDs for this record are chained together for easy access */
int firstfield; /* dno of first RECFIELD, or -1 if none */
*************** typedef struct PLpgSQL_recfield
*** 320,325 ****
--- 327,334 ----
{
PLpgSQL_datum_type dtype;
int dno;
+ /* end of PLpgSQL_datum fields */
+
char *fieldname; /* name of field */
int recparentno; /* dno of parent record */
int nextfield; /* dno of next child, or -1 if none */
*************** typedef struct PLpgSQL_arrayelem
*** 335,340 ****
--- 344,351 ----
{
PLpgSQL_datum_type dtype;
int dno;
+ /* end of PLpgSQL_datum fields */
+
PLpgSQL_expr *subscript;
int arrayparentno; /* dno of parent array variable */
*************** typedef struct PLpgSQL_function
*** 864,869 ****
--- 875,881 ----
/* the datums representing the function's local variables */
int ndatums;
PLpgSQL_datum **datums;
+ Size copiable_size; /* space for locally instantiated datums */
/* function body parsetree */
PLpgSQL_stmt_block *action;
*************** typedef struct PLpgSQL_execstate
*** 900,907 ****
ResourceOwner tuple_store_owner;
ReturnSetInfo *rsi;
- /* the datums representing the function's local variables */
int found_varno;
int ndatums;
PLpgSQL_datum **datums;
/* context containing variable values (same as func's SPI_proc context) */
--- 912,925 ----
ResourceOwner tuple_store_owner;
ReturnSetInfo *rsi;
int found_varno;
+
+ /*
+ * The datums representing the function's local variables. Some of these
+ * are local storage in this execstate, but some just point to the shared
+ * copy belonging to the PLpgSQL_function, depending on whether or not we
+ * need any per-execution state for the datum's dtype.
+ */
int ndatums;
PLpgSQL_datum **datums;
/* context containing variable values (same as func's SPI_proc context) */