aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/spi.c208
-rw-r--r--src/include/executor/spi.h11
2 files changed, 179 insertions, 40 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 3cd2e574100..42187fe43ad 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.191 2008/03/26 18:48:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.192 2008/04/01 03:09:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -35,13 +35,17 @@ static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */
static int _SPI_connected = -1;
static int _SPI_curid = -1;
-static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan);
+static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan,
+ ParamListInfo boundParams);
-static int _SPI_execute_plan(SPIPlanPtr plan,
- Datum *Values, const char *Nulls,
+static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, bool fire_triggers, long tcount);
+static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ int pflags);
+
static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
static void _SPI_error_callback(void *arg);
@@ -313,9 +317,9 @@ SPI_execute(const char *src, bool read_only, long tcount)
plan.magic = _SPI_PLAN_MAGIC;
plan.cursor_options = 0;
- _SPI_prepare_plan(src, &plan);
+ _SPI_prepare_plan(src, &plan, NULL);
- res = _SPI_execute_plan(&plan, NULL, NULL,
+ res = _SPI_execute_plan(&plan, NULL,
InvalidSnapshot, InvalidSnapshot,
read_only, true, tcount);
@@ -348,7 +352,9 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
return res;
res = _SPI_execute_plan(plan,
- Values, Nulls,
+ _SPI_convert_params(plan->nargs, plan->argtypes,
+ Values, Nulls,
+ 0),
InvalidSnapshot, InvalidSnapshot,
read_only, true, tcount);
@@ -394,7 +400,9 @@ SPI_execute_snapshot(SPIPlanPtr plan,
return res;
res = _SPI_execute_plan(plan,
- Values, Nulls,
+ _SPI_convert_params(plan->nargs, plan->argtypes,
+ Values, Nulls,
+ 0),
snapshot, crosscheck_snapshot,
read_only, fire_triggers, tcount);
@@ -402,6 +410,57 @@ SPI_execute_snapshot(SPIPlanPtr plan,
return res;
}
+/*
+ * SPI_execute_with_args -- plan and execute a query with supplied arguments
+ *
+ * This is functionally comparable to SPI_prepare followed by
+ * SPI_execute_plan, except that since we know the plan will be used only
+ * once, we can tell the planner to rely on the parameter values as constants.
+ * This eliminates potential performance disadvantages compared to
+ * inserting the parameter values directly into the query text.
+ */
+int
+SPI_execute_with_args(const char *src,
+ int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ bool read_only, long tcount)
+{
+ int res;
+ _SPI_plan plan;
+ ParamListInfo paramLI;
+
+ if (src == NULL || nargs < 0 || tcount < 0)
+ return SPI_ERROR_ARGUMENT;
+
+ if (nargs > 0 && (argtypes == NULL || Values == NULL))
+ return SPI_ERROR_PARAM;
+
+ res = _SPI_begin_call(true);
+ if (res < 0)
+ return res;
+
+ memset(&plan, 0, sizeof(_SPI_plan));
+ plan.magic = _SPI_PLAN_MAGIC;
+ plan.cursor_options = 0;
+ plan.nargs = nargs;
+ plan.argtypes = argtypes;
+
+ paramLI = _SPI_convert_params(nargs, argtypes,
+ Values, Nulls,
+ PARAM_FLAG_CONST);
+
+ _SPI_prepare_plan(src, &plan, paramLI);
+
+ /* We don't need to copy the plan since it will be thrown away anyway */
+
+ res = _SPI_execute_plan(&plan, paramLI,
+ InvalidSnapshot, InvalidSnapshot,
+ read_only, true, tcount);
+
+ _SPI_end_call(true);
+ return res;
+}
+
SPIPlanPtr
SPI_prepare(const char *src, int nargs, Oid *argtypes)
{
@@ -431,7 +490,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
plan.nargs = nargs;
plan.argtypes = argtypes;
- _SPI_prepare_plan(src, &plan);
+ _SPI_prepare_plan(src, &plan, NULL);
/* copy plan to procedure context */
result = _SPI_copy_plan(&plan, _SPI_current->procCxt);
@@ -1055,6 +1114,64 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
/*
+ * SPI_cursor_open_with_args()
+ *
+ * Parse and plan a query and open it as a portal. Like SPI_execute_with_args,
+ * we can tell the planner to rely on the parameter values as constants,
+ * because the plan will only be used once.
+ */
+Portal
+SPI_cursor_open_with_args(const char *name,
+ const char *src,
+ int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ bool read_only, int cursorOptions)
+{
+ Portal result;
+ _SPI_plan plan;
+ ParamListInfo paramLI;
+
+ if (src == NULL || nargs < 0)
+ elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
+
+ if (nargs > 0 && (argtypes == NULL || Values == NULL))
+ elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
+
+ SPI_result = _SPI_begin_call(true);
+ if (SPI_result < 0)
+ elog(ERROR, "SPI_cursor_open_with_args called while not connected");
+
+ memset(&plan, 0, sizeof(_SPI_plan));
+ plan.magic = _SPI_PLAN_MAGIC;
+ plan.cursor_options = cursorOptions;
+ plan.nargs = nargs;
+ plan.argtypes = argtypes;
+
+ paramLI = _SPI_convert_params(nargs, argtypes,
+ Values, Nulls,
+ PARAM_FLAG_CONST);
+
+ _SPI_prepare_plan(src, &plan, paramLI);
+
+ /* We needn't copy the plan; SPI_cursor_open will do so */
+
+ /* Adjust stack so that SPI_cursor_open doesn't complain */
+ _SPI_curid--;
+
+ /* SPI_cursor_open expects to be called in procedure memory context */
+ _SPI_procmem();
+
+ result = SPI_cursor_open(name, &plan, Values, Nulls, read_only);
+
+ /* And clean up */
+ _SPI_curid++;
+ _SPI_end_call(true);
+
+ return result;
+}
+
+
+/*
* SPI_cursor_find()
*
* Find the portal of an existing open cursor
@@ -1376,14 +1493,17 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
* Parse and plan a querystring.
*
* At entry, plan->argtypes, plan->nargs, and plan->cursor_options must be
- * valid.
+ * valid. If boundParams isn't NULL then it represents parameter values
+ * that are made available to the planner (as either estimates or hard values
+ * depending on their PARAM_FLAG_CONST marking). The boundParams had better
+ * match the param types embedded in the plan!
*
* Results are stored into *plan (specifically, plan->plancache_list).
* Note however that the result trees are all in CurrentMemoryContext
* and need to be copied somewhere to survive.
*/
static void
-_SPI_prepare_plan(const char *src, SPIPlanPtr plan)
+_SPI_prepare_plan(const char *src, SPIPlanPtr plan, ParamListInfo boundParams)
{
List *raw_parsetree_list;
List *plancache_list;
@@ -1422,7 +1542,8 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
/* Need a copyObject here to keep parser from modifying raw tree */
stmt_list = pg_analyze_and_rewrite(copyObject(parsetree),
src, argtypes, nargs);
- stmt_list = pg_plan_queries(stmt_list, cursor_options, NULL, false);
+ stmt_list = pg_plan_queries(stmt_list, cursor_options,
+ boundParams, false);
plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
cplan = (CachedPlan *) palloc0(sizeof(CachedPlan));
@@ -1465,7 +1586,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
* tcount: execution tuple-count limit, or 0 for none
*/
static int
-_SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
+_SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
Snapshot snapshot, Snapshot crosscheck_snapshot,
bool read_only, bool fire_triggers, long tcount)
{
@@ -1480,34 +1601,9 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
saveActiveSnapshot = ActiveSnapshot;
PG_TRY();
{
- ListCell *lc1;
ErrorContextCallback spierrcontext;
- int nargs = plan->nargs;
- ParamListInfo paramLI;
CachedPlan *cplan = NULL;
-
- /* Convert parameters to form wanted by executor */
- if (nargs > 0)
- {
- int k;
-
- /* sizeof(ParamListInfoData) includes the first array element */
- paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
- (nargs - 1) *sizeof(ParamExternData));
- paramLI->numParams = nargs;
-
- for (k = 0; k < nargs; k++)
- {
- ParamExternData *prm = &paramLI->params[k];
-
- prm->value = Values[k];
- prm->isnull = (Nulls && Nulls[k] == 'n');
- prm->pflags = 0;
- prm->ptype = plan->argtypes[k];
- }
- }
- else
- paramLI = NULL;
+ ListCell *lc1;
/*
* Setup error traceback support for ereport()
@@ -1723,6 +1819,40 @@ fail:
return my_res;
}
+/*
+ * Convert query parameters to form wanted by planner and executor
+ */
+static ParamListInfo
+_SPI_convert_params(int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ int pflags)
+{
+ ParamListInfo paramLI;
+
+ if (nargs > 0)
+ {
+ int i;
+
+ /* sizeof(ParamListInfoData) includes the first array element */
+ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
+ (nargs - 1) *sizeof(ParamExternData));
+ paramLI->numParams = nargs;
+
+ for (i = 0; i < nargs; i++)
+ {
+ ParamExternData *prm = &paramLI->params[i];
+
+ prm->value = Values[i];
+ prm->isnull = (Nulls && Nulls[i] == 'n');
+ prm->pflags = pflags;
+ prm->ptype = argtypes[i];
+ }
+ }
+ else
+ paramLI = NULL;
+ return paramLI;
+}
+
static int
_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
{
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index e64fc39cba5..9d3f65b8cf0 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.65 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.66 2008/04/01 03:09:30 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -105,6 +105,10 @@ extern int SPI_execute_snapshot(SPIPlanPtr plan,
Snapshot snapshot,
Snapshot crosscheck_snapshot,
bool read_only, bool fire_triggers, long tcount);
+extern int SPI_execute_with_args(const char *src,
+ int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ bool read_only, long tcount);
extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes);
extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
int cursorOptions);
@@ -136,6 +140,11 @@ extern void SPI_freetuptable(SPITupleTable *tuptable);
extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan,
Datum *Values, const char *Nulls, bool read_only);
+extern Portal SPI_cursor_open_with_args(const char *name,
+ const char *src,
+ int nargs, Oid *argtypes,
+ Datum *Values, const char *Nulls,
+ bool read_only, int cursorOptions);
extern Portal SPI_cursor_find(const char *name);
extern void SPI_cursor_fetch(Portal portal, bool forward, long count);
extern void SPI_cursor_move(Portal portal, bool forward, long count);