postgresql/src/backend/executor/nodeFunctionscan.c

426 lines
11 KiB
C
Raw Normal View History

/*-------------------------------------------------------------------------
*
* nodeFunctionscan.c
* Support routines for scanning RangeFunctions (functions in rangetable).
*
* Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
2010-09-20 22:08:53 +02:00
* src/backend/executor/nodeFunctionscan.c
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecFunctionScan scans a function.
* ExecFunctionNext retrieve next tuple in sequential order.
* ExecInitFunctionScan creates and initializes a functionscan node.
* ExecEndFunctionScan releases any storage allocated.
* ExecReScanFunctionScan rescans the function
*/
#include "postgres.h"
#include "executor/nodeFunctionscan.h"
#include "funcapi.h"
#include "nodes/nodeFuncs.h"
#include "catalog/pg_type.h"
static TupleTableSlot *FunctionNext(FunctionScanState *node);
/* ----------------------------------------------------------------
* Scan Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* FunctionNext
*
* This is a workhorse for ExecFunctionScan
* ----------------------------------------------------------------
*/
static TupleTableSlot *
FunctionNext(FunctionScanState *node)
{
2002-09-04 22:31:48 +02:00
EState *estate;
ScanDirection direction;
Tuplestorestate *tuplestorestate;
TupleTableSlot *scanslot;
TupleTableSlot *funcslot;
if (node->func_slot)
{
/*
* ORDINALITY case:
*
* We fetch the function result into FUNCSLOT (which matches the
* function return type), and then copy the values to SCANSLOT
* (which matches the scan result type), setting the ordinal
* column in the process.
*/
funcslot = node->func_slot;
scanslot = node->ss.ss_ScanTupleSlot;
}
else
{
/*
* non-ORDINALITY case: the function return type and scan result
* type are the same, so we fetch the function result straight
* into the scan result slot.
*/
funcslot = node->ss.ss_ScanTupleSlot;
scanslot = NULL;
}
/*
* get information from the estate and scan state
*/
estate = node->ss.ps.state;
direction = estate->es_direction;
tuplestorestate = node->tuplestorestate;
/*
2005-10-15 04:49:52 +02:00
* If first time through, read all tuples from function and put them in a
* tuplestore. Subsequent calls just fetch tuples from tuplestore.
*/
if (tuplestorestate == NULL)
{
node->tuplestorestate = tuplestorestate =
ExecMakeTableFunctionResult(node->funcexpr,
node->ss.ps.ps_ExprContext,
node->func_tupdesc,
node->eflags & EXEC_FLAG_BACKWARD);
}
/*
* Get the next tuple from tuplestore. Return NULL if no more tuples.
*/
(void) tuplestore_gettupleslot(tuplestorestate,
ScanDirectionIsForward(direction),
false,
funcslot);
if (!scanslot)
return funcslot;
/*
* we're doing ordinality, so we copy the values from the function return
* slot to the (distinct) scan slot. We can do this because the lifetimes
* of the values in each slot are the same; until we reset the scan or
* fetch the next tuple, both will be valid.
*/
ExecClearTuple(scanslot);
/*
* increment or decrement before checking for end-of-data, so that we can
* move off either end of the result by 1 (and no more than 1) without
* losing correct count. See PortalRunSelect for why we assume that we
* won't be called repeatedly in the end-of-data state.
*/
if (ScanDirectionIsForward(direction))
node->ordinal++;
else
node->ordinal--;
if (!TupIsNull(funcslot))
{
int natts = funcslot->tts_tupleDescriptor->natts;
int i;
slot_getallattrs(funcslot);
for (i = 0; i < natts; ++i)
{
scanslot->tts_values[i] = funcslot->tts_values[i];
scanslot->tts_isnull[i] = funcslot->tts_isnull[i];
}
scanslot->tts_values[natts] = Int64GetDatumFast(node->ordinal);
scanslot->tts_isnull[natts] = false;
ExecStoreVirtualTuple(scanslot);
}
return scanslot;
}
/*
* FunctionRecheck -- access method routine to recheck a tuple in EvalPlanQual
*/
static bool
FunctionRecheck(FunctionScanState *node, TupleTableSlot *slot)
{
/* nothing to check */
return true;
}
/* ----------------------------------------------------------------
* ExecFunctionScan(node)
*
* Scans the function sequentially and returns the next qualifying
* tuple.
* We call the ExecScan() routine and pass it the appropriate
* access method functions.
* ----------------------------------------------------------------
*/
TupleTableSlot *
ExecFunctionScan(FunctionScanState *node)
{
return ExecScan(&node->ss,
(ExecScanAccessMtd) FunctionNext,
(ExecScanRecheckMtd) FunctionRecheck);
}
/* ----------------------------------------------------------------
* ExecInitFunctionScan
* ----------------------------------------------------------------
*/
FunctionScanState *
ExecInitFunctionScan(FunctionScan *node, EState *estate, int eflags)
{
2002-09-04 22:31:48 +02:00
FunctionScanState *scanstate;
Oid funcrettype;
TypeFuncClass functypclass;
TupleDesc func_tupdesc = NULL;
TupleDesc scan_tupdesc = NULL;
/* check for unsupported flags */
Assert(!(eflags & EXEC_FLAG_MARK));
/*
* FunctionScan should not have any children.
*/
Assert(outerPlan(node) == NULL);
Assert(innerPlan(node) == NULL);
/*
* create new ScanState for node
*/
scanstate = makeNode(FunctionScanState);
scanstate->ss.ps.plan = (Plan *) node;
scanstate->ss.ps.state = estate;
scanstate->eflags = eflags;
/*
* Miscellaneous initialization
*
* create expression context for node
*/
ExecAssignExprContext(estate, &scanstate->ss.ps);
/*
* tuple table initialization
*/
ExecInitResultTupleSlot(estate, &scanstate->ss.ps);
ExecInitScanTupleSlot(estate, &scanstate->ss);
/*
* We only need a separate slot for the function result if we are doing
* ordinality; otherwise, we fetch function results directly into the
* scan slot.
*/
if (node->funcordinality)
scanstate->func_slot = ExecInitExtraTupleSlot(estate);
else
scanstate->func_slot = NULL;
/*
* initialize child expressions
*/
scanstate->ss.ps.targetlist = (List *)
ExecInitExpr((Expr *) node->scan.plan.targetlist,
(PlanState *) scanstate);
scanstate->ss.ps.qual = (List *)
ExecInitExpr((Expr *) node->scan.plan.qual,
(PlanState *) scanstate);
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
/*
* Now determine if the function returns a simple or composite
* type, and build an appropriate tupdesc. This tupdesc
* (func_tupdesc) is the one that matches the shape of the
* function result, no extra columns.
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
*/
functypclass = get_expr_result_type(node->funcexpr,
&funcrettype,
&func_tupdesc);
if (functypclass == TYPEFUNC_COMPOSITE)
{
/* Composite data type, e.g. a table's row type */
Assert(func_tupdesc);
/*
* XXX
* Existing behaviour is a bit inconsistent with regard to aliases and
* whole-row Vars of the function result. If the function returns a
* composite type, then the whole-row Var will refer to this tupdesc,
* which has the type's own column names rather than the alias column
* names given in the query. This affects the output of constructs like
* row_to_json which read the column names from the passed-in values.
*/
/* Must copy it out of typcache for safety */
func_tupdesc = CreateTupleDescCopy(func_tupdesc);
}
else if (functypclass == TYPEFUNC_SCALAR)
{
/* Base data type, i.e. scalar */
char *attname = strVal(linitial(node->funccolnames));
func_tupdesc = CreateTemplateTupleDesc(1, false);
TupleDescInitEntry(func_tupdesc,
(AttrNumber) 1,
attname,
funcrettype,
-1,
0);
TupleDescInitEntryCollation(func_tupdesc,
(AttrNumber) 1,
exprCollation(node->funcexpr));
}
else if (functypclass == TYPEFUNC_RECORD)
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
{
func_tupdesc = BuildDescFromLists(node->funccolnames,
node->funccoltypes,
node->funccoltypmods,
node->funccolcollations);
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
}
else
{
/* crummy error message, but parser should have caught this */
elog(ERROR, "function in FROM has unsupported return type");
}
Attached are two patches to implement and document anonymous composite types for Table Functions, as previously proposed on HACKERS. Here is a brief explanation: 1. Creates a new pg_type typtype: 'p' for pseudo type (currently either 'b' for base or 'c' for catalog, i.e. a class). 2. Creates new builtin type of typtype='p' named RECORD. This is the first of potentially several pseudo types. 3. Modify FROM clause grammer to accept: SELECT * FROM my_func() AS m(colname1 type1, colname2 type1, ...) where m is the table alias, colname1, etc are the column names, and type1, etc are the column types. 4. When typtype == 'p' and the function return type is RECORD, a list of column defs is required, and when typtype != 'p', it is disallowed. 5. A check was added to ensure that the tupdesc provide via the parser and the actual return tupdesc match in number and type of attributes. When creating a function you can do: CREATE FUNCTION foo(text) RETURNS setof RECORD ... When using it you can do: SELECT * from foo(sqlstmt) AS (f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) AS f(f1 int, f2 text, f3 timestamp) or SELECT * from foo(sqlstmt) f(f1 int, f2 text, f3 timestamp) Included in the patches are adjustments to the regression test sql and expected files, and documentation. p.s. This potentially solves (or at least improves) the issue of builtin Table Functions. They can be bootstrapped as returning RECORD, and we can wrap system views around them with properly specified column defs. For example: CREATE VIEW pg_settings AS SELECT s.name, s.setting FROM show_all_settings()AS s(name text, setting text); Then we can also add the UPDATE RULE that I previously posted to pg_settings, and have pg_settings act like a virtual table, allowing settings to be queried and set. Joe Conway
2002-08-04 21:48:11 +02:00
/*
* For RECORD results, make sure a typmod has been assigned. (The
2005-10-15 04:49:52 +02:00
* function should do this for itself, but let's cover things in case it
* doesn't.)
*/
BlessTupleDesc(func_tupdesc);
/*
* If doing ordinality, we need a new tupdesc with one additional column
* tacked on, always of type "bigint". The name to use has already been
* recorded by the parser as the last element of funccolnames.
*
* Without ordinality, the scan result tupdesc is the same as the
* function result tupdesc. (No need to make a copy.)
*/
if (node->funcordinality)
{
int natts = func_tupdesc->natts;
scan_tupdesc = CreateTupleDescCopyExtend(func_tupdesc, 1);
TupleDescInitEntry(scan_tupdesc,
natts + 1,
strVal(llast(node->funccolnames)),
INT8OID,
-1,
0);
BlessTupleDesc(scan_tupdesc);
}
else
scan_tupdesc = func_tupdesc;
scanstate->scan_tupdesc = scan_tupdesc;
scanstate->func_tupdesc = func_tupdesc;
ExecAssignScanType(&scanstate->ss, scan_tupdesc);
if (scanstate->func_slot)
ExecSetSlotDescriptor(scanstate->func_slot, func_tupdesc);
/*
* Other node-specific setup
*/
scanstate->ordinal = 0;
scanstate->tuplestorestate = NULL;
scanstate->funcexpr = ExecInitExpr((Expr *) node->funcexpr,
(PlanState *) scanstate);
scanstate->ss.ps.ps_TupFromTlist = false;
/*
* Initialize result tuple type and projection info.
*/
ExecAssignResultTypeFromTL(&scanstate->ss.ps);
ExecAssignScanProjectionInfo(&scanstate->ss);
return scanstate;
}
/* ----------------------------------------------------------------
* ExecEndFunctionScan
*
* frees any storage allocated through C routines.
* ----------------------------------------------------------------
*/
void
ExecEndFunctionScan(FunctionScanState *node)
{
/*
* Free the exprcontext
*/
ExecFreeExprContext(&node->ss.ps);
/*
* clean out the tuple table
*/
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
ExecClearTuple(node->ss.ss_ScanTupleSlot);
if (node->func_slot)
ExecClearTuple(node->func_slot);
/*
* Release tuplestore resources
*/
if (node->tuplestorestate != NULL)
tuplestore_end(node->tuplestorestate);
node->tuplestorestate = NULL;
}
/* ----------------------------------------------------------------
* ExecReScanFunctionScan
*
* Rescans the relation.
* ----------------------------------------------------------------
*/
void
ExecReScanFunctionScan(FunctionScanState *node)
{
ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
if (node->func_slot)
ExecClearTuple(node->func_slot);
ExecScanReScan(&node->ss);
node->ordinal = 0;
/*
* If we haven't materialized yet, just return.
*/
if (!node->tuplestorestate)
return;
/*
2005-10-15 04:49:52 +02:00
* Here we have a choice whether to drop the tuplestore (and recompute the
* function outputs) or just rescan it. We must recompute if the
* expression contains parameters, else we rescan. XXX maybe we should
* recompute if the function is volatile?
*/
if (node->ss.ps.chgParam != NULL)
{
tuplestore_end(node->tuplestorestate);
node->tuplestorestate = NULL;
}
else
tuplestore_rescan(node->tuplestorestate);
}