Add COST and ROWS options to CREATE/ALTER FUNCTION, plus underlying pg_proc
columns procost and prorows, to allow simple user adjustment of the estimated cost of a function call, as well as control of the estimated number of rows returned by a set-returning function. We might eventually wish to extend this to allow function-specific estimation routines, but there seems to be consensus that we should try a simple constant estimate first. In particular this provides a relatively simple way to control the order in which different WHERE clauses are applied in a plan node, which is a Good Thing in view of the fact that the recent EquivalenceClass planner rewrite made that much less predictable than before.
This commit is contained in:
parent
a85e9c61e5
commit
5a7471c307
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.142 2007/01/20 23:13:01 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.143 2007/01/22 01:35:19 tgl Exp $ -->
|
||||||
<!--
|
<!--
|
||||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||||
-->
|
-->
|
||||||
@ -3375,6 +3375,22 @@
|
|||||||
<entry>Implementation language or call interface of this function</entry>
|
<entry>Implementation language or call interface of this function</entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>procost</structfield></entry>
|
||||||
|
<entry><type>float4</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Estimated execution cost (in units of
|
||||||
|
<xref linkend="guc-cpu-operator-cost">); if <structfield>proretset</>,
|
||||||
|
this is cost per row returned</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
|
<row>
|
||||||
|
<entry><structfield>prorows</structfield></entry>
|
||||||
|
<entry><type>float4</type></entry>
|
||||||
|
<entry></entry>
|
||||||
|
<entry>Estimated number of result rows (zero if not <structfield>proretset</>)</entry>
|
||||||
|
</row>
|
||||||
|
|
||||||
<row>
|
<row>
|
||||||
<entry><structfield>proisagg</structfield></entry>
|
<entry><structfield>proisagg</structfield></entry>
|
||||||
<entry><type>bool</type></entry>
|
<entry><type>bool</type></entry>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.12 2006/09/16 00:30:16 momjian Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_function.sgml,v 1.13 2007/01/22 01:35:19 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -34,6 +34,8 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
|
|||||||
CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
||||||
IMMUTABLE | STABLE | VOLATILE
|
IMMUTABLE | STABLE | VOLATILE
|
||||||
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||||
|
COST <replaceable class="parameter">execution_cost</replaceable>
|
||||||
|
ROWS <replaceable class="parameter">result_rows</replaceable>
|
||||||
</synopsis>
|
</synopsis>
|
||||||
</refsynopsisdiv>
|
</refsynopsisdiv>
|
||||||
|
|
||||||
@ -186,6 +188,30 @@ where <replaceable class="PARAMETER">action</replaceable> is one of:
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>COST</literal> <replaceable class="parameter">execution_cost</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Change the estimated execution cost of the function.
|
||||||
|
See <xref linkend="sql-createfunction"
|
||||||
|
endterm="sql-createfunction-title"> for more information.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><literal>ROWS</literal> <replaceable class="parameter">result_rows</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Change the estimated number of rows returned by a set-returning
|
||||||
|
function. See <xref linkend="sql-createfunction"
|
||||||
|
endterm="sql-createfunction-title"> for more information.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><literal>RESTRICT</literal></term>
|
<term><literal>RESTRICT</literal></term>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.70 2006/11/10 20:52:18 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.71 2007/01/22 01:35:19 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<refentry id="SQL-CREATEFUNCTION">
|
<refentry id="SQL-CREATEFUNCTION">
|
||||||
@ -26,6 +26,8 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
| IMMUTABLE | STABLE | VOLATILE
|
| IMMUTABLE | STABLE | VOLATILE
|
||||||
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
|
||||||
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
|
||||||
|
| COST <replaceable class="parameter">execution_cost</replaceable>
|
||||||
|
| ROWS <replaceable class="parameter">result_rows</replaceable>
|
||||||
| AS '<replaceable class="parameter">definition</replaceable>'
|
| AS '<replaceable class="parameter">definition</replaceable>'
|
||||||
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
|
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
|
||||||
} ...
|
} ...
|
||||||
@ -52,7 +54,7 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
To update the definition of an existing function, use
|
To replace the current definition of an existing function, use
|
||||||
<command>CREATE OR REPLACE FUNCTION</command>. It is not possible
|
<command>CREATE OR REPLACE FUNCTION</command>. It is not possible
|
||||||
to change the name or argument types of a function this way (if you
|
to change the name or argument types of a function this way (if you
|
||||||
tried, you would actually be creating a new, distinct function).
|
tried, you would actually be creating a new, distinct function).
|
||||||
@ -289,6 +291,35 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">execution_cost</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A positive number giving the estimated execution cost for the function,
|
||||||
|
in units of <xref linkend="guc-cpu-operator-cost">. If the function
|
||||||
|
returns a set, this is the cost per returned row. If the cost is
|
||||||
|
not specified, 1 unit is assumed for C-language and internal functions,
|
||||||
|
and 100 units for functions in all other languages. Larger values
|
||||||
|
cause the planner to try to avoid evaluating the function more often
|
||||||
|
than necessary.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="parameter">result_rows</replaceable></term>
|
||||||
|
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
A positive number giving the estimated number of rows that the planner
|
||||||
|
should expect the function to return. This is only allowed when the
|
||||||
|
function is declared to return a set. The default assumption is
|
||||||
|
1000 rows.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><replaceable class="parameter">definition</replaceable></term>
|
<term><replaceable class="parameter">definition</replaceable></term>
|
||||||
|
|
||||||
@ -400,7 +431,8 @@ CREATE FUNCTION foo(int, out text) ...
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
When repeated <command>CREATE FUNCTION</command> calls refer to
|
When repeated <command>CREATE FUNCTION</command> calls refer to
|
||||||
the same object file, the file is only loaded once. To unload and
|
the same object file, the file is only loaded once per session.
|
||||||
|
To unload and
|
||||||
reload the file (perhaps during development), use the <xref
|
reload the file (perhaps during development), use the <xref
|
||||||
linkend="sql-load" endterm="sql-load-title"> command.
|
linkend="sql-load" endterm="sql-load-title"> command.
|
||||||
</para>
|
</para>
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.228 2007/01/05 22:19:24 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.229 2007/01/22 01:35:19 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -115,16 +115,18 @@ static const struct typinfo TypInfo[] = {
|
|||||||
F_BYTEAIN, F_BYTEAOUT},
|
F_BYTEAIN, F_BYTEAOUT},
|
||||||
{"char", CHAROID, 0, 1, true, 'c', 'p',
|
{"char", CHAROID, 0, 1, true, 'c', 'p',
|
||||||
F_CHARIN, F_CHAROUT},
|
F_CHARIN, F_CHAROUT},
|
||||||
{"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'i', 'p',
|
|
||||||
F_NAMEIN, F_NAMEOUT},
|
|
||||||
{"int2", INT2OID, 0, 2, true, 's', 'p',
|
{"int2", INT2OID, 0, 2, true, 's', 'p',
|
||||||
F_INT2IN, F_INT2OUT},
|
F_INT2IN, F_INT2OUT},
|
||||||
{"int4", INT4OID, 0, 4, true, 'i', 'p',
|
{"int4", INT4OID, 0, 4, true, 'i', 'p',
|
||||||
F_INT4IN, F_INT4OUT},
|
F_INT4IN, F_INT4OUT},
|
||||||
{"regproc", REGPROCOID, 0, 4, true, 'i', 'p',
|
{"float4", FLOAT4OID, 0, 4, false, 'i', 'p',
|
||||||
F_REGPROCIN, F_REGPROCOUT},
|
F_FLOAT4IN, F_FLOAT4OUT},
|
||||||
|
{"name", NAMEOID, CHAROID, NAMEDATALEN, false, 'i', 'p',
|
||||||
|
F_NAMEIN, F_NAMEOUT},
|
||||||
{"regclass", REGCLASSOID, 0, 4, true, 'i', 'p',
|
{"regclass", REGCLASSOID, 0, 4, true, 'i', 'p',
|
||||||
F_REGCLASSIN, F_REGCLASSOUT},
|
F_REGCLASSIN, F_REGCLASSOUT},
|
||||||
|
{"regproc", REGPROCOID, 0, 4, true, 'i', 'p',
|
||||||
|
F_REGPROCIN, F_REGPROCOUT},
|
||||||
{"regtype", REGTYPEOID, 0, 4, true, 'i', 'p',
|
{"regtype", REGTYPEOID, 0, 4, true, 'i', 'p',
|
||||||
F_REGTYPEIN, F_REGTYPEOUT},
|
F_REGTYPEIN, F_REGTYPEOUT},
|
||||||
{"text", TEXTOID, 0, -1, false, 'i', 'x',
|
{"text", TEXTOID, 0, -1, false, 'i', 'x',
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.84 2007/01/05 22:19:25 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.85 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -214,7 +214,9 @@ AggregateCreate(const char *aggName,
|
|||||||
numArgs), /* paramTypes */
|
numArgs), /* paramTypes */
|
||||||
PointerGetDatum(NULL), /* allParamTypes */
|
PointerGetDatum(NULL), /* allParamTypes */
|
||||||
PointerGetDatum(NULL), /* parameterModes */
|
PointerGetDatum(NULL), /* parameterModes */
|
||||||
PointerGetDatum(NULL)); /* parameterNames */
|
PointerGetDatum(NULL), /* parameterNames */
|
||||||
|
1, /* procost */
|
||||||
|
0); /* prorows */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay to create the pg_aggregate entry.
|
* Okay to create the pg_aggregate entry.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.142 2007/01/05 22:19:25 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.143 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -71,7 +71,9 @@ ProcedureCreate(const char *procedureName,
|
|||||||
oidvector *parameterTypes,
|
oidvector *parameterTypes,
|
||||||
Datum allParameterTypes,
|
Datum allParameterTypes,
|
||||||
Datum parameterModes,
|
Datum parameterModes,
|
||||||
Datum parameterNames)
|
Datum parameterNames,
|
||||||
|
float4 procost,
|
||||||
|
float4 prorows)
|
||||||
{
|
{
|
||||||
Oid retval;
|
Oid retval;
|
||||||
int parameterCount;
|
int parameterCount;
|
||||||
@ -219,6 +221,8 @@ ProcedureCreate(const char *procedureName,
|
|||||||
values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
|
values[Anum_pg_proc_pronamespace - 1] = ObjectIdGetDatum(procNamespace);
|
||||||
values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(GetUserId());
|
values[Anum_pg_proc_proowner - 1] = ObjectIdGetDatum(GetUserId());
|
||||||
values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
|
values[Anum_pg_proc_prolang - 1] = ObjectIdGetDatum(languageObjectId);
|
||||||
|
values[Anum_pg_proc_procost - 1] = Float4GetDatum(procost);
|
||||||
|
values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
|
||||||
values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
|
values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
|
||||||
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
|
values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
|
||||||
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
|
values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.81 2007/01/05 22:19:26 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.82 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* These routines take the parse tree and pick out the
|
* These routines take the parse tree and pick out the
|
||||||
@ -273,7 +273,9 @@ static bool
|
|||||||
compute_common_attribute(DefElem *defel,
|
compute_common_attribute(DefElem *defel,
|
||||||
DefElem **volatility_item,
|
DefElem **volatility_item,
|
||||||
DefElem **strict_item,
|
DefElem **strict_item,
|
||||||
DefElem **security_item)
|
DefElem **security_item,
|
||||||
|
DefElem **cost_item,
|
||||||
|
DefElem **rows_item)
|
||||||
{
|
{
|
||||||
if (strcmp(defel->defname, "volatility") == 0)
|
if (strcmp(defel->defname, "volatility") == 0)
|
||||||
{
|
{
|
||||||
@ -296,6 +298,20 @@ compute_common_attribute(DefElem *defel,
|
|||||||
|
|
||||||
*security_item = defel;
|
*security_item = defel;
|
||||||
}
|
}
|
||||||
|
else if (strcmp(defel->defname, "cost") == 0)
|
||||||
|
{
|
||||||
|
if (*cost_item)
|
||||||
|
goto duplicate_error;
|
||||||
|
|
||||||
|
*cost_item = defel;
|
||||||
|
}
|
||||||
|
else if (strcmp(defel->defname, "rows") == 0)
|
||||||
|
{
|
||||||
|
if (*rows_item)
|
||||||
|
goto duplicate_error;
|
||||||
|
|
||||||
|
*rows_item = defel;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -337,7 +353,9 @@ compute_attributes_sql_style(List *options,
|
|||||||
char **language,
|
char **language,
|
||||||
char *volatility_p,
|
char *volatility_p,
|
||||||
bool *strict_p,
|
bool *strict_p,
|
||||||
bool *security_definer)
|
bool *security_definer,
|
||||||
|
float4 *procost,
|
||||||
|
float4 *prorows)
|
||||||
{
|
{
|
||||||
ListCell *option;
|
ListCell *option;
|
||||||
DefElem *as_item = NULL;
|
DefElem *as_item = NULL;
|
||||||
@ -345,6 +363,8 @@ compute_attributes_sql_style(List *options,
|
|||||||
DefElem *volatility_item = NULL;
|
DefElem *volatility_item = NULL;
|
||||||
DefElem *strict_item = NULL;
|
DefElem *strict_item = NULL;
|
||||||
DefElem *security_item = NULL;
|
DefElem *security_item = NULL;
|
||||||
|
DefElem *cost_item = NULL;
|
||||||
|
DefElem *rows_item = NULL;
|
||||||
|
|
||||||
foreach(option, options)
|
foreach(option, options)
|
||||||
{
|
{
|
||||||
@ -369,7 +389,9 @@ compute_attributes_sql_style(List *options,
|
|||||||
else if (compute_common_attribute(defel,
|
else if (compute_common_attribute(defel,
|
||||||
&volatility_item,
|
&volatility_item,
|
||||||
&strict_item,
|
&strict_item,
|
||||||
&security_item))
|
&security_item,
|
||||||
|
&cost_item,
|
||||||
|
&rows_item))
|
||||||
{
|
{
|
||||||
/* recognized common option */
|
/* recognized common option */
|
||||||
continue;
|
continue;
|
||||||
@ -407,6 +429,22 @@ compute_attributes_sql_style(List *options,
|
|||||||
*strict_p = intVal(strict_item->arg);
|
*strict_p = intVal(strict_item->arg);
|
||||||
if (security_item)
|
if (security_item)
|
||||||
*security_definer = intVal(security_item->arg);
|
*security_definer = intVal(security_item->arg);
|
||||||
|
if (cost_item)
|
||||||
|
{
|
||||||
|
*procost = defGetNumeric(cost_item);
|
||||||
|
if (*procost <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("COST must be positive")));
|
||||||
|
}
|
||||||
|
if (rows_item)
|
||||||
|
{
|
||||||
|
*prorows = defGetNumeric(rows_item);
|
||||||
|
if (*prorows <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("ROWS must be positive")));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -519,6 +557,8 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
bool isStrict,
|
bool isStrict,
|
||||||
security;
|
security;
|
||||||
char volatility;
|
char volatility;
|
||||||
|
float4 procost;
|
||||||
|
float4 prorows;
|
||||||
HeapTuple languageTuple;
|
HeapTuple languageTuple;
|
||||||
Form_pg_language languageStruct;
|
Form_pg_language languageStruct;
|
||||||
List *as_clause;
|
List *as_clause;
|
||||||
@ -537,10 +577,14 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
isStrict = false;
|
isStrict = false;
|
||||||
security = false;
|
security = false;
|
||||||
volatility = PROVOLATILE_VOLATILE;
|
volatility = PROVOLATILE_VOLATILE;
|
||||||
|
procost = -1; /* indicates not set */
|
||||||
|
prorows = -1; /* indicates not set */
|
||||||
|
|
||||||
/* override attributes from explicit list */
|
/* override attributes from explicit list */
|
||||||
compute_attributes_sql_style(stmt->options,
|
compute_attributes_sql_style(stmt->options,
|
||||||
&as_clause, &language, &volatility, &isStrict, &security);
|
&as_clause, &language,
|
||||||
|
&volatility, &isStrict, &security,
|
||||||
|
&procost, &prorows);
|
||||||
|
|
||||||
/* Convert language name to canonical case */
|
/* Convert language name to canonical case */
|
||||||
languageName = case_translate_language_name(language);
|
languageName = case_translate_language_name(language);
|
||||||
@ -645,6 +689,32 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
prosrc_str = funcname;
|
prosrc_str = funcname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Set default values for COST and ROWS depending on other parameters;
|
||||||
|
* reject ROWS if it's not returnsSet. NB: pg_dump knows these default
|
||||||
|
* values, keep it in sync if you change them.
|
||||||
|
*/
|
||||||
|
if (procost < 0)
|
||||||
|
{
|
||||||
|
/* SQL and PL-language functions are assumed more expensive */
|
||||||
|
if (languageOid == INTERNALlanguageId ||
|
||||||
|
languageOid == ClanguageId)
|
||||||
|
procost = 1;
|
||||||
|
else
|
||||||
|
procost = 100;
|
||||||
|
}
|
||||||
|
if (prorows < 0)
|
||||||
|
{
|
||||||
|
if (returnsSet)
|
||||||
|
prorows = 1000;
|
||||||
|
else
|
||||||
|
prorows = 0; /* dummy value if not returnsSet */
|
||||||
|
}
|
||||||
|
else if (!returnsSet)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("ROWS is not applicable when function does not return a set")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And now that we have all the parameters, and know we're permitted to do
|
* And now that we have all the parameters, and know we're permitted to do
|
||||||
* so, go ahead and create the function.
|
* so, go ahead and create the function.
|
||||||
@ -665,7 +735,9 @@ CreateFunction(CreateFunctionStmt *stmt)
|
|||||||
parameterTypes,
|
parameterTypes,
|
||||||
PointerGetDatum(allParameterTypes),
|
PointerGetDatum(allParameterTypes),
|
||||||
PointerGetDatum(parameterModes),
|
PointerGetDatum(parameterModes),
|
||||||
PointerGetDatum(parameterNames));
|
PointerGetDatum(parameterNames),
|
||||||
|
procost,
|
||||||
|
prorows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1012,6 +1084,8 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
DefElem *volatility_item = NULL;
|
DefElem *volatility_item = NULL;
|
||||||
DefElem *strict_item = NULL;
|
DefElem *strict_item = NULL;
|
||||||
DefElem *security_def_item = NULL;
|
DefElem *security_def_item = NULL;
|
||||||
|
DefElem *cost_item = NULL;
|
||||||
|
DefElem *rows_item = NULL;
|
||||||
|
|
||||||
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
||||||
|
|
||||||
@ -1046,7 +1120,9 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
if (compute_common_attribute(defel,
|
if (compute_common_attribute(defel,
|
||||||
&volatility_item,
|
&volatility_item,
|
||||||
&strict_item,
|
&strict_item,
|
||||||
&security_def_item) == false)
|
&security_def_item,
|
||||||
|
&cost_item,
|
||||||
|
&rows_item) == false)
|
||||||
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1056,6 +1132,26 @@ AlterFunction(AlterFunctionStmt *stmt)
|
|||||||
procForm->proisstrict = intVal(strict_item->arg);
|
procForm->proisstrict = intVal(strict_item->arg);
|
||||||
if (security_def_item)
|
if (security_def_item)
|
||||||
procForm->prosecdef = intVal(security_def_item->arg);
|
procForm->prosecdef = intVal(security_def_item->arg);
|
||||||
|
if (cost_item)
|
||||||
|
{
|
||||||
|
procForm->procost = defGetNumeric(cost_item);
|
||||||
|
if (procForm->procost <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("COST must be positive")));
|
||||||
|
}
|
||||||
|
if (rows_item)
|
||||||
|
{
|
||||||
|
procForm->prorows = defGetNumeric(rows_item);
|
||||||
|
if (procForm->prorows <= 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("ROWS must be positive")));
|
||||||
|
if (!procForm->proretset)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
|
errmsg("ROWS is not applicable when function does not return a set")));
|
||||||
|
}
|
||||||
|
|
||||||
/* Do the update */
|
/* Do the update */
|
||||||
simple_heap_update(rel, &tup->t_self, tup);
|
simple_heap_update(rel, &tup->t_self, tup);
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.70 2007/01/05 22:19:26 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.71 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -130,7 +130,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
buildoidvector(funcargtypes, 0),
|
buildoidvector(funcargtypes, 0),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL));
|
PointerGetDatum(NULL),
|
||||||
|
1,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -160,7 +162,9 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
|
|||||||
buildoidvector(funcargtypes, 1),
|
buildoidvector(funcargtypes, 1),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL),
|
PointerGetDatum(NULL),
|
||||||
PointerGetDatum(NULL));
|
PointerGetDatum(NULL),
|
||||||
|
1,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -54,7 +54,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.175 2007/01/20 20:45:38 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.176 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -68,6 +68,7 @@
|
|||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/cost.h"
|
#include "optimizer/cost.h"
|
||||||
#include "optimizer/pathnode.h"
|
#include "optimizer/pathnode.h"
|
||||||
|
#include "optimizer/planmain.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/selfuncs.h"
|
#include "utils/selfuncs.h"
|
||||||
@ -842,17 +843,19 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
|
|||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
Cost cpu_per_tuple;
|
Cost cpu_per_tuple;
|
||||||
|
RangeTblEntry *rte;
|
||||||
|
QualCost exprcost;
|
||||||
|
|
||||||
/* Should only be applied to base relations that are functions */
|
/* Should only be applied to base relations that are functions */
|
||||||
Assert(baserel->relid > 0);
|
Assert(baserel->relid > 0);
|
||||||
Assert(baserel->rtekind == RTE_FUNCTION);
|
rte = rt_fetch(baserel->relid, root->parse->rtable);
|
||||||
|
Assert(rte->rtekind == RTE_FUNCTION);
|
||||||
|
|
||||||
/*
|
/* Estimate costs of executing the function expression */
|
||||||
* For now, estimate function's cost at one operator eval per function
|
cost_qual_eval_node(&exprcost, rte->funcexpr);
|
||||||
* call. Someday we should revive the function cost estimate columns in
|
|
||||||
* pg_proc...
|
startup_cost += exprcost.startup;
|
||||||
*/
|
cpu_per_tuple = exprcost.per_tuple;
|
||||||
cpu_per_tuple = cpu_operator_cost;
|
|
||||||
|
|
||||||
/* Add scanning CPU costs */
|
/* Add scanning CPU costs */
|
||||||
startup_cost += baserel->baserestrictcost.startup;
|
startup_cost += baserel->baserestrictcost.startup;
|
||||||
@ -1068,6 +1071,10 @@ cost_agg(Path *path, PlannerInfo *root,
|
|||||||
* there's roundoff error we might do the wrong thing. So be sure that
|
* there's roundoff error we might do the wrong thing. So be sure that
|
||||||
* the computations below form the same intermediate values in the same
|
* the computations below form the same intermediate values in the same
|
||||||
* order.
|
* order.
|
||||||
|
*
|
||||||
|
* Note: ideally we should use the pg_proc.procost costs of each
|
||||||
|
* aggregate's component functions, but for now that seems like an
|
||||||
|
* excessive amount of work.
|
||||||
*/
|
*/
|
||||||
if (aggstrategy == AGG_PLAIN)
|
if (aggstrategy == AGG_PLAIN)
|
||||||
{
|
{
|
||||||
@ -1694,7 +1701,8 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
|
|||||||
* cost_qual_eval
|
* cost_qual_eval
|
||||||
* Estimate the CPU costs of evaluating a WHERE clause.
|
* Estimate the CPU costs of evaluating a WHERE clause.
|
||||||
* The input can be either an implicitly-ANDed list of boolean
|
* The input can be either an implicitly-ANDed list of boolean
|
||||||
* expressions, or a list of RestrictInfo nodes.
|
* expressions, or a list of RestrictInfo nodes. (The latter is
|
||||||
|
* preferred since it allows caching of the results.)
|
||||||
* The result includes both a one-time (startup) component,
|
* The result includes both a one-time (startup) component,
|
||||||
* and a per-evaluation component.
|
* and a per-evaluation component.
|
||||||
*/
|
*/
|
||||||
@ -1712,41 +1720,20 @@ cost_qual_eval(QualCost *cost, List *quals)
|
|||||||
{
|
{
|
||||||
Node *qual = (Node *) lfirst(l);
|
Node *qual = (Node *) lfirst(l);
|
||||||
|
|
||||||
/*
|
|
||||||
* RestrictInfo nodes contain an eval_cost field reserved for this
|
|
||||||
* routine's use, so that it's not necessary to evaluate the qual
|
|
||||||
* clause's cost more than once. If the clause's cost hasn't been
|
|
||||||
* computed yet, the field's startup value will contain -1.
|
|
||||||
*
|
|
||||||
* If the RestrictInfo is marked pseudoconstant, it will be tested
|
|
||||||
* only once, so treat its cost as all startup cost.
|
|
||||||
*/
|
|
||||||
if (qual && IsA(qual, RestrictInfo))
|
|
||||||
{
|
|
||||||
RestrictInfo *rinfo = (RestrictInfo *) qual;
|
|
||||||
|
|
||||||
if (rinfo->eval_cost.startup < 0)
|
|
||||||
{
|
|
||||||
rinfo->eval_cost.startup = 0;
|
|
||||||
rinfo->eval_cost.per_tuple = 0;
|
|
||||||
cost_qual_eval_walker((Node *) rinfo->clause,
|
|
||||||
&rinfo->eval_cost);
|
|
||||||
if (rinfo->pseudoconstant)
|
|
||||||
{
|
|
||||||
/* count one execution during startup */
|
|
||||||
rinfo->eval_cost.startup += rinfo->eval_cost.per_tuple;
|
|
||||||
rinfo->eval_cost.per_tuple = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cost->startup += rinfo->eval_cost.startup;
|
|
||||||
cost->per_tuple += rinfo->eval_cost.per_tuple;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* If it's a bare expression, must always do it the hard way */
|
|
||||||
cost_qual_eval_walker(qual, cost);
|
cost_qual_eval_walker(qual, cost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cost_qual_eval_node
|
||||||
|
* As above, for a single RestrictInfo or expression.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
cost_qual_eval_node(QualCost *cost, Node *qual)
|
||||||
|
{
|
||||||
|
cost->startup = 0;
|
||||||
|
cost->per_tuple = 0;
|
||||||
|
cost_qual_eval_walker(qual, cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
@ -1756,19 +1743,75 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Our basic strategy is to charge one cpu_operator_cost for each operator
|
* RestrictInfo nodes contain an eval_cost field reserved for this
|
||||||
* or function node in the given tree. Vars and Consts are charged zero,
|
* routine's use, so that it's not necessary to evaluate the qual
|
||||||
* and so are boolean operators (AND, OR, NOT). Simplistic, but a lot
|
* clause's cost more than once. If the clause's cost hasn't been
|
||||||
* better than no model at all.
|
* computed yet, the field's startup value will contain -1.
|
||||||
|
*/
|
||||||
|
if (IsA(node, RestrictInfo))
|
||||||
|
{
|
||||||
|
RestrictInfo *rinfo = (RestrictInfo *) node;
|
||||||
|
|
||||||
|
if (rinfo->eval_cost.startup < 0)
|
||||||
|
{
|
||||||
|
rinfo->eval_cost.startup = 0;
|
||||||
|
rinfo->eval_cost.per_tuple = 0;
|
||||||
|
/*
|
||||||
|
* For an OR clause, recurse into the marked-up tree so that
|
||||||
|
* we set the eval_cost for contained RestrictInfos too.
|
||||||
|
*/
|
||||||
|
if (rinfo->orclause)
|
||||||
|
cost_qual_eval_walker((Node *) rinfo->orclause,
|
||||||
|
&rinfo->eval_cost);
|
||||||
|
else
|
||||||
|
cost_qual_eval_walker((Node *) rinfo->clause,
|
||||||
|
&rinfo->eval_cost);
|
||||||
|
/*
|
||||||
|
* If the RestrictInfo is marked pseudoconstant, it will be tested
|
||||||
|
* only once, so treat its cost as all startup cost.
|
||||||
|
*/
|
||||||
|
if (rinfo->pseudoconstant)
|
||||||
|
{
|
||||||
|
/* count one execution during startup */
|
||||||
|
rinfo->eval_cost.startup += rinfo->eval_cost.per_tuple;
|
||||||
|
rinfo->eval_cost.per_tuple = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
total->startup += rinfo->eval_cost.startup;
|
||||||
|
total->per_tuple += rinfo->eval_cost.per_tuple;
|
||||||
|
/* do NOT recurse into children */
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For each operator or function node in the given tree, we charge the
|
||||||
|
* estimated execution cost given by pg_proc.procost (remember to
|
||||||
|
* multiply this by cpu_operator_cost).
|
||||||
|
*
|
||||||
|
* Vars and Consts are charged zero, and so are boolean operators (AND,
|
||||||
|
* OR, NOT). Simplistic, but a lot better than no model at all.
|
||||||
*
|
*
|
||||||
* Should we try to account for the possibility of short-circuit
|
* Should we try to account for the possibility of short-circuit
|
||||||
* evaluation of AND/OR?
|
* evaluation of AND/OR? Probably *not*, because that would make the
|
||||||
|
* results depend on the clause ordering, and we are not in any position
|
||||||
|
* to expect that the current ordering of the clauses is the one that's
|
||||||
|
* going to end up being used. (Is it worth applying order_qual_clauses
|
||||||
|
* much earlier in the planning process to fix this?)
|
||||||
*/
|
*/
|
||||||
if (IsA(node, FuncExpr) ||
|
if (IsA(node, FuncExpr))
|
||||||
IsA(node, OpExpr) ||
|
{
|
||||||
|
total->per_tuple += get_func_cost(((FuncExpr *) node)->funcid) *
|
||||||
|
cpu_operator_cost;
|
||||||
|
}
|
||||||
|
else if (IsA(node, OpExpr) ||
|
||||||
IsA(node, DistinctExpr) ||
|
IsA(node, DistinctExpr) ||
|
||||||
IsA(node, NullIfExpr))
|
IsA(node, NullIfExpr))
|
||||||
total->per_tuple += cpu_operator_cost;
|
{
|
||||||
|
/* rely on struct equivalence to treat these all alike */
|
||||||
|
set_opfuncid((OpExpr *) node);
|
||||||
|
total->per_tuple += get_func_cost(((OpExpr *) node)->opfuncid) *
|
||||||
|
cpu_operator_cost;
|
||||||
|
}
|
||||||
else if (IsA(node, ScalarArrayOpExpr))
|
else if (IsA(node, ScalarArrayOpExpr))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -1778,15 +1821,23 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
|||||||
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
|
ScalarArrayOpExpr *saop = (ScalarArrayOpExpr *) node;
|
||||||
Node *arraynode = (Node *) lsecond(saop->args);
|
Node *arraynode = (Node *) lsecond(saop->args);
|
||||||
|
|
||||||
total->per_tuple +=
|
set_sa_opfuncid(saop);
|
||||||
|
total->per_tuple += get_func_cost(saop->opfuncid) *
|
||||||
cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
|
cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
|
||||||
}
|
}
|
||||||
else if (IsA(node, RowCompareExpr))
|
else if (IsA(node, RowCompareExpr))
|
||||||
{
|
{
|
||||||
/* Conservatively assume we will check all the columns */
|
/* Conservatively assume we will check all the columns */
|
||||||
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
|
RowCompareExpr *rcexpr = (RowCompareExpr *) node;
|
||||||
|
ListCell *lc;
|
||||||
|
|
||||||
total->per_tuple += cpu_operator_cost * list_length(rcexpr->opnos);
|
foreach(lc, rcexpr->opnos)
|
||||||
|
{
|
||||||
|
Oid opid = lfirst_oid(lc);
|
||||||
|
|
||||||
|
total->per_tuple += get_func_cost(get_opcode(opid)) *
|
||||||
|
cpu_operator_cost;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (IsA(node, SubLink))
|
else if (IsA(node, SubLink))
|
||||||
{
|
{
|
||||||
@ -1873,6 +1924,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* recurse into children */
|
||||||
return expression_tree_walker(node, cost_qual_eval_walker,
|
return expression_tree_walker(node, cost_qual_eval_walker,
|
||||||
(void *) total);
|
(void *) total);
|
||||||
}
|
}
|
||||||
@ -2172,16 +2224,8 @@ set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel)
|
|||||||
rte = rt_fetch(rel->relid, root->parse->rtable);
|
rte = rt_fetch(rel->relid, root->parse->rtable);
|
||||||
Assert(rte->rtekind == RTE_FUNCTION);
|
Assert(rte->rtekind == RTE_FUNCTION);
|
||||||
|
|
||||||
/*
|
/* Estimate number of rows the function itself will return */
|
||||||
* Estimate number of rows the function itself will return.
|
rel->tuples = clamp_row_est(expression_returns_set_rows(rte->funcexpr));
|
||||||
*
|
|
||||||
* XXX no idea how to do this yet; but we can at least check whether
|
|
||||||
* function returns set or not...
|
|
||||||
*/
|
|
||||||
if (expression_returns_set(rte->funcexpr))
|
|
||||||
rel->tuples = 1000;
|
|
||||||
else
|
|
||||||
rel->tuples = 1;
|
|
||||||
|
|
||||||
/* Now estimate number of output rows, etc */
|
/* Now estimate number of output rows, etc */
|
||||||
set_baserel_size_estimates(root, rel);
|
set_baserel_size_estimates(root, rel);
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.222 2007/01/20 20:45:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.223 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -411,14 +411,15 @@ create_gating_plan(PlannerInfo *root, Plan *plan, List *quals)
|
|||||||
{
|
{
|
||||||
List *pseudoconstants;
|
List *pseudoconstants;
|
||||||
|
|
||||||
|
/* Sort into desirable execution order while still in RestrictInfo form */
|
||||||
|
quals = order_qual_clauses(root, quals);
|
||||||
|
|
||||||
/* Pull out any pseudoconstant quals from the RestrictInfo list */
|
/* Pull out any pseudoconstant quals from the RestrictInfo list */
|
||||||
pseudoconstants = extract_actual_clauses(quals, true);
|
pseudoconstants = extract_actual_clauses(quals, true);
|
||||||
|
|
||||||
if (!pseudoconstants)
|
if (!pseudoconstants)
|
||||||
return plan;
|
return plan;
|
||||||
|
|
||||||
pseudoconstants = order_qual_clauses(root, pseudoconstants);
|
|
||||||
|
|
||||||
return (Plan *) make_result((List *) copyObject(plan->targetlist),
|
return (Plan *) make_result((List *) copyObject(plan->targetlist),
|
||||||
(Node *) pseudoconstants,
|
(Node *) pseudoconstants,
|
||||||
plan);
|
plan);
|
||||||
@ -553,6 +554,8 @@ create_result_plan(PlannerInfo *root, ResultPath *best_path)
|
|||||||
Assert(best_path->path.parent == NULL);
|
Assert(best_path->path.parent == NULL);
|
||||||
tlist = NIL;
|
tlist = NIL;
|
||||||
|
|
||||||
|
/* best_path->quals is just bare clauses */
|
||||||
|
|
||||||
quals = order_qual_clauses(root, best_path->quals);
|
quals = order_qual_clauses(root, best_path->quals);
|
||||||
|
|
||||||
return make_result(tlist, (Node *) quals, NULL);
|
return make_result(tlist, (Node *) quals, NULL);
|
||||||
@ -810,12 +813,12 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path,
|
|||||||
Assert(scan_relid > 0);
|
Assert(scan_relid > 0);
|
||||||
Assert(best_path->parent->rtekind == RTE_RELATION);
|
Assert(best_path->parent->rtekind == RTE_RELATION);
|
||||||
|
|
||||||
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
|
||||||
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
/* Sort clauses into best execution order */
|
||||||
scan_clauses = order_qual_clauses(root, scan_clauses);
|
scan_clauses = order_qual_clauses(root, scan_clauses);
|
||||||
|
|
||||||
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
|
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
||||||
|
|
||||||
scan_plan = make_seqscan(tlist,
|
scan_plan = make_seqscan(tlist,
|
||||||
scan_clauses,
|
scan_clauses,
|
||||||
scan_relid);
|
scan_relid);
|
||||||
@ -916,10 +919,6 @@ create_indexscan_plan(PlannerInfo *root,
|
|||||||
* predicate, but only in a plain SELECT; when scanning a target relation
|
* predicate, but only in a plain SELECT; when scanning a target relation
|
||||||
* of UPDATE/DELETE/SELECT FOR UPDATE, we must leave such quals in the
|
* of UPDATE/DELETE/SELECT FOR UPDATE, we must leave such quals in the
|
||||||
* plan so that they'll be properly rechecked by EvalPlanQual testing.
|
* plan so that they'll be properly rechecked by EvalPlanQual testing.
|
||||||
*
|
|
||||||
* While at it, we strip off the RestrictInfos to produce a list of plain
|
|
||||||
* expressions (this loop replaces extract_actual_clauses used in the
|
|
||||||
* other routines in this file). We have to ignore pseudoconstants.
|
|
||||||
*/
|
*/
|
||||||
qpqual = NIL;
|
qpqual = NIL;
|
||||||
foreach(l, scan_clauses)
|
foreach(l, scan_clauses)
|
||||||
@ -928,7 +927,7 @@ create_indexscan_plan(PlannerInfo *root,
|
|||||||
|
|
||||||
Assert(IsA(rinfo, RestrictInfo));
|
Assert(IsA(rinfo, RestrictInfo));
|
||||||
if (rinfo->pseudoconstant)
|
if (rinfo->pseudoconstant)
|
||||||
continue;
|
continue; /* we may drop pseudoconstants here */
|
||||||
if (list_member_ptr(nonlossy_indexquals, rinfo))
|
if (list_member_ptr(nonlossy_indexquals, rinfo))
|
||||||
continue;
|
continue;
|
||||||
if (!contain_mutable_functions((Node *) rinfo->clause))
|
if (!contain_mutable_functions((Node *) rinfo->clause))
|
||||||
@ -946,12 +945,15 @@ create_indexscan_plan(PlannerInfo *root,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
qpqual = lappend(qpqual, rinfo->clause);
|
qpqual = lappend(qpqual, rinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
/* Sort clauses into best execution order */
|
||||||
qpqual = order_qual_clauses(root, qpqual);
|
qpqual = order_qual_clauses(root, qpqual);
|
||||||
|
|
||||||
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
|
qpqual = extract_actual_clauses(qpqual, false);
|
||||||
|
|
||||||
/* Finally ready to build the plan node */
|
/* Finally ready to build the plan node */
|
||||||
scan_plan = make_indexscan(tlist,
|
scan_plan = make_indexscan(tlist,
|
||||||
qpqual,
|
qpqual,
|
||||||
@ -1281,6 +1283,9 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
|
|||||||
Assert(scan_relid > 0);
|
Assert(scan_relid > 0);
|
||||||
Assert(best_path->path.parent->rtekind == RTE_RELATION);
|
Assert(best_path->path.parent->rtekind == RTE_RELATION);
|
||||||
|
|
||||||
|
/* Sort clauses into best execution order */
|
||||||
|
scan_clauses = order_qual_clauses(root, scan_clauses);
|
||||||
|
|
||||||
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
||||||
|
|
||||||
@ -1293,9 +1298,6 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
|
|||||||
ortidquals = list_make1(make_orclause(ortidquals));
|
ortidquals = list_make1(make_orclause(ortidquals));
|
||||||
scan_clauses = list_difference(scan_clauses, ortidquals);
|
scan_clauses = list_difference(scan_clauses, ortidquals);
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
|
||||||
scan_clauses = order_qual_clauses(root, scan_clauses);
|
|
||||||
|
|
||||||
scan_plan = make_tidscan(tlist,
|
scan_plan = make_tidscan(tlist,
|
||||||
scan_clauses,
|
scan_clauses,
|
||||||
scan_relid,
|
scan_relid,
|
||||||
@ -1322,12 +1324,12 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
|
|||||||
Assert(scan_relid > 0);
|
Assert(scan_relid > 0);
|
||||||
Assert(best_path->parent->rtekind == RTE_SUBQUERY);
|
Assert(best_path->parent->rtekind == RTE_SUBQUERY);
|
||||||
|
|
||||||
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
|
||||||
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
/* Sort clauses into best execution order */
|
||||||
scan_clauses = order_qual_clauses(root, scan_clauses);
|
scan_clauses = order_qual_clauses(root, scan_clauses);
|
||||||
|
|
||||||
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
|
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
||||||
|
|
||||||
scan_plan = make_subqueryscan(tlist,
|
scan_plan = make_subqueryscan(tlist,
|
||||||
scan_clauses,
|
scan_clauses,
|
||||||
scan_relid,
|
scan_relid,
|
||||||
@ -1354,12 +1356,12 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
|
|||||||
Assert(scan_relid > 0);
|
Assert(scan_relid > 0);
|
||||||
Assert(best_path->parent->rtekind == RTE_FUNCTION);
|
Assert(best_path->parent->rtekind == RTE_FUNCTION);
|
||||||
|
|
||||||
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
|
||||||
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
/* Sort clauses into best execution order */
|
||||||
scan_clauses = order_qual_clauses(root, scan_clauses);
|
scan_clauses = order_qual_clauses(root, scan_clauses);
|
||||||
|
|
||||||
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
|
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
||||||
|
|
||||||
scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
|
scan_plan = make_functionscan(tlist, scan_clauses, scan_relid);
|
||||||
|
|
||||||
copy_path_costsize(&scan_plan->scan.plan, best_path);
|
copy_path_costsize(&scan_plan->scan.plan, best_path);
|
||||||
@ -1383,12 +1385,12 @@ create_valuesscan_plan(PlannerInfo *root, Path *best_path,
|
|||||||
Assert(scan_relid > 0);
|
Assert(scan_relid > 0);
|
||||||
Assert(best_path->parent->rtekind == RTE_VALUES);
|
Assert(best_path->parent->rtekind == RTE_VALUES);
|
||||||
|
|
||||||
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
|
||||||
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
/* Sort clauses into best execution order */
|
||||||
scan_clauses = order_qual_clauses(root, scan_clauses);
|
scan_clauses = order_qual_clauses(root, scan_clauses);
|
||||||
|
|
||||||
|
/* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
|
||||||
|
scan_clauses = extract_actual_clauses(scan_clauses, false);
|
||||||
|
|
||||||
scan_plan = make_valuesscan(tlist, scan_clauses, scan_relid);
|
scan_plan = make_valuesscan(tlist, scan_clauses, scan_relid);
|
||||||
|
|
||||||
copy_path_costsize(&scan_plan->scan.plan, best_path);
|
copy_path_costsize(&scan_plan->scan.plan, best_path);
|
||||||
@ -1471,6 +1473,9 @@ create_nestloop_plan(PlannerInfo *root,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Sort join qual clauses into best execution order */
|
||||||
|
joinrestrictclauses = order_qual_clauses(root, joinrestrictclauses);
|
||||||
|
|
||||||
/* Get the join qual clauses (in plain expression form) */
|
/* Get the join qual clauses (in plain expression form) */
|
||||||
/* Any pseudoconstant clauses are ignored here */
|
/* Any pseudoconstant clauses are ignored here */
|
||||||
if (IS_OUTER_JOIN(best_path->jointype))
|
if (IS_OUTER_JOIN(best_path->jointype))
|
||||||
@ -1485,10 +1490,6 @@ create_nestloop_plan(PlannerInfo *root,
|
|||||||
otherclauses = NIL;
|
otherclauses = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
|
||||||
joinclauses = order_qual_clauses(root, joinclauses);
|
|
||||||
otherclauses = order_qual_clauses(root, otherclauses);
|
|
||||||
|
|
||||||
join_plan = make_nestloop(tlist,
|
join_plan = make_nestloop(tlist,
|
||||||
joinclauses,
|
joinclauses,
|
||||||
otherclauses,
|
otherclauses,
|
||||||
@ -1527,18 +1528,21 @@ create_mergejoin_plan(PlannerInfo *root,
|
|||||||
ListCell *lop;
|
ListCell *lop;
|
||||||
ListCell *lip;
|
ListCell *lip;
|
||||||
|
|
||||||
|
/* Sort join qual clauses into best execution order */
|
||||||
|
/* NB: do NOT reorder the mergeclauses */
|
||||||
|
joinclauses = order_qual_clauses(root, best_path->jpath.joinrestrictinfo);
|
||||||
|
|
||||||
/* Get the join qual clauses (in plain expression form) */
|
/* Get the join qual clauses (in plain expression form) */
|
||||||
/* Any pseudoconstant clauses are ignored here */
|
/* Any pseudoconstant clauses are ignored here */
|
||||||
if (IS_OUTER_JOIN(best_path->jpath.jointype))
|
if (IS_OUTER_JOIN(best_path->jpath.jointype))
|
||||||
{
|
{
|
||||||
extract_actual_join_clauses(best_path->jpath.joinrestrictinfo,
|
extract_actual_join_clauses(joinclauses,
|
||||||
&joinclauses, &otherclauses);
|
&joinclauses, &otherclauses);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We can treat all clauses alike for an inner join */
|
/* We can treat all clauses alike for an inner join */
|
||||||
joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo,
|
joinclauses = extract_actual_clauses(joinclauses, false);
|
||||||
false);
|
|
||||||
otherclauses = NIL;
|
otherclauses = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1557,11 +1561,6 @@ create_mergejoin_plan(PlannerInfo *root,
|
|||||||
mergeclauses = get_switched_clauses(best_path->path_mergeclauses,
|
mergeclauses = get_switched_clauses(best_path->path_mergeclauses,
|
||||||
best_path->jpath.outerjoinpath->parent->relids);
|
best_path->jpath.outerjoinpath->parent->relids);
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
|
||||||
/* NB: do NOT reorder the mergeclauses */
|
|
||||||
joinclauses = order_qual_clauses(root, joinclauses);
|
|
||||||
otherclauses = order_qual_clauses(root, otherclauses);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create explicit sort nodes for the outer and inner join paths if
|
* Create explicit sort nodes for the outer and inner join paths if
|
||||||
* necessary. The sort cost was already accounted for in the path. Make
|
* necessary. The sort cost was already accounted for in the path. Make
|
||||||
@ -1699,18 +1698,21 @@ create_hashjoin_plan(PlannerInfo *root,
|
|||||||
HashJoin *join_plan;
|
HashJoin *join_plan;
|
||||||
Hash *hash_plan;
|
Hash *hash_plan;
|
||||||
|
|
||||||
|
/* Sort join qual clauses into best execution order */
|
||||||
|
joinclauses = order_qual_clauses(root, best_path->jpath.joinrestrictinfo);
|
||||||
|
/* There's no point in sorting the hash clauses ... */
|
||||||
|
|
||||||
/* Get the join qual clauses (in plain expression form) */
|
/* Get the join qual clauses (in plain expression form) */
|
||||||
/* Any pseudoconstant clauses are ignored here */
|
/* Any pseudoconstant clauses are ignored here */
|
||||||
if (IS_OUTER_JOIN(best_path->jpath.jointype))
|
if (IS_OUTER_JOIN(best_path->jpath.jointype))
|
||||||
{
|
{
|
||||||
extract_actual_join_clauses(best_path->jpath.joinrestrictinfo,
|
extract_actual_join_clauses(joinclauses,
|
||||||
&joinclauses, &otherclauses);
|
&joinclauses, &otherclauses);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We can treat all clauses alike for an inner join */
|
/* We can treat all clauses alike for an inner join */
|
||||||
joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo,
|
joinclauses = extract_actual_clauses(joinclauses, false);
|
||||||
false);
|
|
||||||
otherclauses = NIL;
|
otherclauses = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1728,11 +1730,6 @@ create_hashjoin_plan(PlannerInfo *root,
|
|||||||
hashclauses = get_switched_clauses(best_path->path_hashclauses,
|
hashclauses = get_switched_clauses(best_path->path_hashclauses,
|
||||||
best_path->jpath.outerjoinpath->parent->relids);
|
best_path->jpath.outerjoinpath->parent->relids);
|
||||||
|
|
||||||
/* Sort clauses into best execution order */
|
|
||||||
joinclauses = order_qual_clauses(root, joinclauses);
|
|
||||||
otherclauses = order_qual_clauses(root, otherclauses);
|
|
||||||
hashclauses = order_qual_clauses(root, hashclauses);
|
|
||||||
|
|
||||||
/* We don't want any excess columns in the hashed tuples */
|
/* We don't want any excess columns in the hashed tuples */
|
||||||
disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);
|
disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);
|
||||||
|
|
||||||
@ -2065,35 +2062,82 @@ get_switched_clauses(List *clauses, Relids outerrelids)
|
|||||||
* in at runtime.
|
* in at runtime.
|
||||||
*
|
*
|
||||||
* Ideally the order should be driven by a combination of execution cost and
|
* Ideally the order should be driven by a combination of execution cost and
|
||||||
* selectivity, but unfortunately we have so little information about
|
* selectivity, but it's not immediately clear how to account for both,
|
||||||
* execution cost of operators that it's really hard to do anything smart.
|
* and given the uncertainty of the estimates the reliability of the decisions
|
||||||
* For now, we just move any quals that contain SubPlan references (but not
|
* would be doubtful anyway. So we just order by estimated per-tuple cost,
|
||||||
* InitPlan references) to the end of the list.
|
* being careful not to change the order when (as is often the case) the
|
||||||
|
* estimates are identical.
|
||||||
|
*
|
||||||
|
* Although this will work on either bare clauses or RestrictInfos, it's
|
||||||
|
* much faster to apply it to RestrictInfos, since it can re-use cost
|
||||||
|
* information that is cached in RestrictInfos.
|
||||||
|
*
|
||||||
|
* Note: some callers pass lists that contain entries that will later be
|
||||||
|
* removed; this is the easiest way to let this routine see RestrictInfos
|
||||||
|
* instead of bare clauses. It's OK because we only sort by cost, but
|
||||||
|
* a cost/selectivity combination would likely do the wrong thing.
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
order_qual_clauses(PlannerInfo *root, List *clauses)
|
order_qual_clauses(PlannerInfo *root, List *clauses)
|
||||||
{
|
{
|
||||||
List *nosubplans;
|
typedef struct
|
||||||
List *withsubplans;
|
{
|
||||||
ListCell *l;
|
Node *clause;
|
||||||
|
Cost cost;
|
||||||
|
} QualItem;
|
||||||
|
int nitems = list_length(clauses);
|
||||||
|
QualItem *items;
|
||||||
|
ListCell *lc;
|
||||||
|
int i;
|
||||||
|
List *result;
|
||||||
|
|
||||||
/* No need to work hard if the query is subselect-free */
|
/* No need to work hard for 0 or 1 clause */
|
||||||
if (!root->parse->hasSubLinks)
|
if (nitems <= 1)
|
||||||
return clauses;
|
return clauses;
|
||||||
|
|
||||||
nosubplans = NIL;
|
/*
|
||||||
withsubplans = NIL;
|
* Collect the items and costs into an array. This is to avoid repeated
|
||||||
foreach(l, clauses)
|
* cost_qual_eval work if the inputs aren't RestrictInfos.
|
||||||
|
*/
|
||||||
|
items = (QualItem *) palloc(nitems * sizeof(QualItem));
|
||||||
|
i = 0;
|
||||||
|
foreach(lc, clauses)
|
||||||
{
|
{
|
||||||
Node *clause = (Node *) lfirst(l);
|
Node *clause = (Node *) lfirst(lc);
|
||||||
|
QualCost qcost;
|
||||||
|
|
||||||
if (contain_subplans(clause))
|
cost_qual_eval_node(&qcost, clause);
|
||||||
withsubplans = lappend(withsubplans, clause);
|
items[i].clause = clause;
|
||||||
else
|
items[i].cost = qcost.per_tuple;
|
||||||
nosubplans = lappend(nosubplans, clause);
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list_concat(nosubplans, withsubplans);
|
/*
|
||||||
|
* Sort. We don't use qsort() because it's not guaranteed stable for
|
||||||
|
* equal keys. The expected number of entries is small enough that
|
||||||
|
* a simple insertion sort should be good enough.
|
||||||
|
*/
|
||||||
|
for (i = 1; i < nitems; i++)
|
||||||
|
{
|
||||||
|
QualItem newitem = items[i];
|
||||||
|
int j;
|
||||||
|
|
||||||
|
/* insert newitem into the already-sorted subarray */
|
||||||
|
for (j = i; j > 0; j--)
|
||||||
|
{
|
||||||
|
if (newitem.cost >= items[j-1].cost)
|
||||||
|
break;
|
||||||
|
items[j] = items[j-1];
|
||||||
|
}
|
||||||
|
items[j] = newitem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert back to a list */
|
||||||
|
result = NIL;
|
||||||
|
for (i = 0; i < nitems; i++)
|
||||||
|
result = lappend(result, items[i].clause);
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.127 2007/01/05 22:19:32 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/setrefs.c,v 1.128 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -83,7 +83,6 @@ static Node *replace_vars_with_subplan_refs(Node *node,
|
|||||||
static Node *replace_vars_with_subplan_refs_mutator(Node *node,
|
static Node *replace_vars_with_subplan_refs_mutator(Node *node,
|
||||||
replace_vars_with_subplan_refs_context *context);
|
replace_vars_with_subplan_refs_context *context);
|
||||||
static bool fix_opfuncids_walker(Node *node, void *context);
|
static bool fix_opfuncids_walker(Node *node, void *context);
|
||||||
static void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
@ -1433,7 +1432,7 @@ set_opfuncid(OpExpr *opexpr)
|
|||||||
* set_sa_opfuncid
|
* set_sa_opfuncid
|
||||||
* As above, for ScalarArrayOpExpr nodes.
|
* As above, for ScalarArrayOpExpr nodes.
|
||||||
*/
|
*/
|
||||||
static void
|
void
|
||||||
set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
|
set_sa_opfuncid(ScalarArrayOpExpr *opexpr)
|
||||||
{
|
{
|
||||||
if (opexpr->opfuncid == InvalidOid)
|
if (opexpr->opfuncid == InvalidOid)
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.230 2007/01/17 17:25:52 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.231 2007/01/22 01:35:20 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -64,6 +64,7 @@ typedef struct
|
|||||||
static bool contain_agg_clause_walker(Node *node, void *context);
|
static bool contain_agg_clause_walker(Node *node, void *context);
|
||||||
static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts);
|
static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts);
|
||||||
static bool expression_returns_set_walker(Node *node, void *context);
|
static bool expression_returns_set_walker(Node *node, void *context);
|
||||||
|
static bool expression_returns_set_rows_walker(Node *node, double *count);
|
||||||
static bool contain_subplans_walker(Node *node, void *context);
|
static bool contain_subplans_walker(Node *node, void *context);
|
||||||
static bool contain_mutable_functions_walker(Node *node, void *context);
|
static bool contain_mutable_functions_walker(Node *node, void *context);
|
||||||
static bool contain_volatile_functions_walker(Node *node, void *context);
|
static bool contain_volatile_functions_walker(Node *node, void *context);
|
||||||
@ -566,6 +567,78 @@ expression_returns_set_walker(Node *node, void *context)
|
|||||||
context);
|
context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* expression_returns_set_rows
|
||||||
|
* Estimate the number of rows in a set result.
|
||||||
|
*
|
||||||
|
* We use the product of the rowcount estimates of all the functions in
|
||||||
|
* the given tree. The result is 1 if there are no set-returning functions.
|
||||||
|
*/
|
||||||
|
double
|
||||||
|
expression_returns_set_rows(Node *clause)
|
||||||
|
{
|
||||||
|
double result = 1;
|
||||||
|
|
||||||
|
(void) expression_returns_set_rows_walker(clause, &result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
expression_returns_set_rows_walker(Node *node, double *count)
|
||||||
|
{
|
||||||
|
if (node == NULL)
|
||||||
|
return false;
|
||||||
|
if (IsA(node, FuncExpr))
|
||||||
|
{
|
||||||
|
FuncExpr *expr = (FuncExpr *) node;
|
||||||
|
|
||||||
|
if (expr->funcretset)
|
||||||
|
*count *= get_func_rows(expr->funcid);
|
||||||
|
}
|
||||||
|
if (IsA(node, OpExpr))
|
||||||
|
{
|
||||||
|
OpExpr *expr = (OpExpr *) node;
|
||||||
|
|
||||||
|
if (expr->opretset)
|
||||||
|
{
|
||||||
|
set_opfuncid(expr);
|
||||||
|
*count *= get_func_rows(expr->opfuncid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid recursion for some cases that can't return a set */
|
||||||
|
if (IsA(node, Aggref))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, DistinctExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, ScalarArrayOpExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, BoolExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, SubLink))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, SubPlan))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, ArrayExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, RowExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, RowCompareExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, CoalesceExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, MinMaxExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, XmlExpr))
|
||||||
|
return false;
|
||||||
|
if (IsA(node, NullIfExpr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return expression_tree_walker(node, expression_returns_set_rows_walker,
|
||||||
|
(void *) count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Subplan clause manipulation
|
* Subplan clause manipulation
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.574 2007/01/14 13:11:53 petere Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.575 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -370,7 +370,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
|
|||||||
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
|
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
|
||||||
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
|
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
|
||||||
COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
|
COMMITTED CONCURRENTLY CONNECTION CONSTRAINT CONSTRAINTS
|
||||||
CONTENT_P CONVERSION_P CONVERT COPY CREATE CREATEDB
|
CONTENT_P CONVERSION_P CONVERT COPY COST CREATE CREATEDB
|
||||||
CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
|
CREATEROLE CREATEUSER CROSS CSV CURRENT_DATE CURRENT_ROLE CURRENT_TIME
|
||||||
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
|
CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
|
||||||
|
|
||||||
@ -3958,6 +3958,14 @@ common_func_opt_item:
|
|||||||
{
|
{
|
||||||
$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
|
$$ = makeDefElem("security", (Node *)makeInteger(FALSE));
|
||||||
}
|
}
|
||||||
|
| COST NumericOnly
|
||||||
|
{
|
||||||
|
$$ = makeDefElem("cost", (Node *)$2);
|
||||||
|
}
|
||||||
|
| ROWS NumericOnly
|
||||||
|
{
|
||||||
|
$$ = makeDefElem("rows", (Node *)$2);
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
createfunc_opt_item:
|
createfunc_opt_item:
|
||||||
@ -8564,6 +8572,7 @@ unreserved_keyword:
|
|||||||
| CONTENT_P
|
| CONTENT_P
|
||||||
| CONVERSION_P
|
| CONVERSION_P
|
||||||
| COPY
|
| COPY
|
||||||
|
| COST
|
||||||
| CREATEDB
|
| CREATEDB
|
||||||
| CREATEROLE
|
| CREATEROLE
|
||||||
| CREATEUSER
|
| CREATEUSER
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.181 2007/01/09 02:14:14 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.182 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -93,6 +93,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"conversion", CONVERSION_P},
|
{"conversion", CONVERSION_P},
|
||||||
{"convert", CONVERT},
|
{"convert", CONVERT},
|
||||||
{"copy", COPY},
|
{"copy", COPY},
|
||||||
|
{"cost", COST},
|
||||||
{"create", CREATE},
|
{"create", CREATE},
|
||||||
{"createdb", CREATEDB},
|
{"createdb", CREATEDB},
|
||||||
{"createrole", CREATEROLE},
|
{"createrole", CREATEROLE},
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.34 2007/01/05 22:19:39 momjian Exp $
|
# $PostgreSQL: pgsql/src/backend/utils/Gen_fmgrtab.sh,v 1.35 2007/01/22 01:35:21 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -72,6 +72,8 @@ trap 'echo "Caught signal." ; cleanup ; exit 1' 1 2 15
|
|||||||
#
|
#
|
||||||
# Generate the file containing raw pg_proc tuple data
|
# Generate the file containing raw pg_proc tuple data
|
||||||
# (but only for "internal" language procedures...).
|
# (but only for "internal" language procedures...).
|
||||||
|
# Basically we strip off the DATA macro call, leaving procedure OID as $1
|
||||||
|
# and all the pg_proc field values as $2, $3, etc on each line.
|
||||||
#
|
#
|
||||||
# Note assumption here that prolang == $5 and INTERNALlanguageId == 12.
|
# Note assumption here that prolang == $5 and INTERNALlanguageId == 12.
|
||||||
#
|
#
|
||||||
@ -202,15 +204,15 @@ FuNkYfMgRtAbStUfF
|
|||||||
# may seem tedious, but avoid the temptation to write a quick x?y:z
|
# may seem tedious, but avoid the temptation to write a quick x?y:z
|
||||||
# conditional expression instead. Not all awks have conditional expressions.
|
# conditional expression instead. Not all awks have conditional expressions.
|
||||||
#
|
#
|
||||||
# Note assumptions here that prosrc == $(NF-2), pronargs == $11,
|
# Note assumptions here that prosrc == $(NF-2), pronargs == $13,
|
||||||
# proisstrict == $8, proretset == $9
|
# proisstrict == $10, proretset == $11
|
||||||
|
|
||||||
$AWK 'BEGIN {
|
$AWK 'BEGIN {
|
||||||
Bool["t"] = "true"
|
Bool["t"] = "true"
|
||||||
Bool["f"] = "false"
|
Bool["f"] = "false"
|
||||||
}
|
}
|
||||||
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
|
{ printf (" { %d, \"%s\", %d, %s, %s, %s },\n"), \
|
||||||
$1, $(NF-2), $11, Bool[$8], Bool[$9], $(NF-2)
|
$1, $(NF-2), $13, Bool[$10], Bool[$11], $(NF-2)
|
||||||
}' $SORTEDFILE >> "$$-$TABLEFILE"
|
}' $SORTEDFILE >> "$$-$TABLEFILE"
|
||||||
|
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
|
44
src/backend/utils/cache/lsyscache.c
vendored
44
src/backend/utils/cache/lsyscache.c
vendored
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.145 2007/01/21 00:57:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.146 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Eventually, the index information should go through here, too.
|
* Eventually, the index information should go through here, too.
|
||||||
@ -1295,6 +1295,48 @@ func_volatile(Oid funcid)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_func_cost
|
||||||
|
* Given procedure id, return the function's procost field.
|
||||||
|
*/
|
||||||
|
float4
|
||||||
|
get_func_cost(Oid funcid)
|
||||||
|
{
|
||||||
|
HeapTuple tp;
|
||||||
|
float4 result;
|
||||||
|
|
||||||
|
tp = SearchSysCache(PROCOID,
|
||||||
|
ObjectIdGetDatum(funcid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tp))
|
||||||
|
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||||
|
|
||||||
|
result = ((Form_pg_proc) GETSTRUCT(tp))->procost;
|
||||||
|
ReleaseSysCache(tp);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_func_rows
|
||||||
|
* Given procedure id, return the function's prorows field.
|
||||||
|
*/
|
||||||
|
float4
|
||||||
|
get_func_rows(Oid funcid)
|
||||||
|
{
|
||||||
|
HeapTuple tp;
|
||||||
|
float4 result;
|
||||||
|
|
||||||
|
tp = SearchSysCache(PROCOID,
|
||||||
|
ObjectIdGetDatum(funcid),
|
||||||
|
0, 0, 0);
|
||||||
|
if (!HeapTupleIsValid(tp))
|
||||||
|
elog(ERROR, "cache lookup failed for function %u", funcid);
|
||||||
|
|
||||||
|
result = ((Form_pg_proc) GETSTRUCT(tp))->prorows;
|
||||||
|
ReleaseSysCache(tp);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- RELATION CACHE ---------- */
|
/* ---------- RELATION CACHE ---------- */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* by PostgreSQL
|
* by PostgreSQL
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.456 2007/01/05 22:19:48 momjian Exp $
|
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.457 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -5837,6 +5837,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
char *provolatile;
|
char *provolatile;
|
||||||
char *proisstrict;
|
char *proisstrict;
|
||||||
char *prosecdef;
|
char *prosecdef;
|
||||||
|
char *procost;
|
||||||
|
char *prorows;
|
||||||
char *lanname;
|
char *lanname;
|
||||||
char *rettypename;
|
char *rettypename;
|
||||||
int nallargs;
|
int nallargs;
|
||||||
@ -5857,12 +5859,25 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
selectSourceSchema(finfo->dobj.namespace->dobj.name);
|
selectSourceSchema(finfo->dobj.namespace->dobj.name);
|
||||||
|
|
||||||
/* Fetch function-specific details */
|
/* Fetch function-specific details */
|
||||||
if (g_fout->remoteVersion >= 80100)
|
if (g_fout->remoteVersion >= 80300)
|
||||||
{
|
{
|
||||||
appendPQExpBuffer(query,
|
appendPQExpBuffer(query,
|
||||||
"SELECT proretset, prosrc, probin, "
|
"SELECT proretset, prosrc, probin, "
|
||||||
"proallargtypes, proargmodes, proargnames, "
|
"proallargtypes, proargmodes, proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
|
"procost, prorows, "
|
||||||
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
|
"FROM pg_catalog.pg_proc "
|
||||||
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
|
finfo->dobj.catId.oid);
|
||||||
|
}
|
||||||
|
else if (g_fout->remoteVersion >= 80100)
|
||||||
|
{
|
||||||
|
appendPQExpBuffer(query,
|
||||||
|
"SELECT proretset, prosrc, probin, "
|
||||||
|
"proallargtypes, proargmodes, proargnames, "
|
||||||
|
"provolatile, proisstrict, prosecdef, "
|
||||||
|
"0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -5876,6 +5891,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"null as proargmodes, "
|
"null as proargmodes, "
|
||||||
"proargnames, "
|
"proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
|
"0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -5889,6 +5905,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"null as proargmodes, "
|
"null as proargmodes, "
|
||||||
"null as proargnames, "
|
"null as proargnames, "
|
||||||
"provolatile, proisstrict, prosecdef, "
|
"provolatile, proisstrict, prosecdef, "
|
||||||
|
"0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_catalog.pg_proc "
|
"FROM pg_catalog.pg_proc "
|
||||||
"WHERE oid = '%u'::pg_catalog.oid",
|
"WHERE oid = '%u'::pg_catalog.oid",
|
||||||
@ -5904,6 +5921,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||||
"proisstrict, "
|
"proisstrict, "
|
||||||
"'f'::boolean as prosecdef, "
|
"'f'::boolean as prosecdef, "
|
||||||
|
"0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_proc "
|
"FROM pg_proc "
|
||||||
"WHERE oid = '%u'::oid",
|
"WHERE oid = '%u'::oid",
|
||||||
@ -5919,6 +5937,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
"case when proiscachable then 'i' else 'v' end as provolatile, "
|
||||||
"'f'::boolean as proisstrict, "
|
"'f'::boolean as proisstrict, "
|
||||||
"'f'::boolean as prosecdef, "
|
"'f'::boolean as prosecdef, "
|
||||||
|
"0 as procost, 0 as prorows, "
|
||||||
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
"(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
|
||||||
"FROM pg_proc "
|
"FROM pg_proc "
|
||||||
"WHERE oid = '%u'::oid",
|
"WHERE oid = '%u'::oid",
|
||||||
@ -5946,6 +5965,8 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
|
||||||
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
|
||||||
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
|
||||||
|
procost = PQgetvalue(res, 0, PQfnumber(res, "procost"));
|
||||||
|
prorows = PQgetvalue(res, 0, PQfnumber(res, "prorows"));
|
||||||
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
lanname = PQgetvalue(res, 0, PQfnumber(res, "lanname"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -6072,6 +6093,30 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
|
|||||||
if (prosecdef[0] == 't')
|
if (prosecdef[0] == 't')
|
||||||
appendPQExpBuffer(q, " SECURITY DEFINER");
|
appendPQExpBuffer(q, " SECURITY DEFINER");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* COST and ROWS are emitted only if present and not default, so as not to
|
||||||
|
* break backwards-compatibility of the dump without need. Keep this code
|
||||||
|
* in sync with the defaults in functioncmds.c.
|
||||||
|
*/
|
||||||
|
if (strcmp(procost, "0") != 0)
|
||||||
|
{
|
||||||
|
if (strcmp(lanname, "internal") == 0 || strcmp(lanname, "c") == 0)
|
||||||
|
{
|
||||||
|
/* default cost is 1 */
|
||||||
|
if (strcmp(procost, "1") != 0)
|
||||||
|
appendPQExpBuffer(q, " COST %s", procost);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* default cost is 100 */
|
||||||
|
if (strcmp(procost, "100") != 0)
|
||||||
|
appendPQExpBuffer(q, " COST %s", procost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (proretset[0] == 't' &&
|
||||||
|
strcmp(prorows, "0") != 0 && strcmp(prorows, "1000") != 0)
|
||||||
|
appendPQExpBuffer(q, " ROWS %s", prorows);
|
||||||
|
|
||||||
appendPQExpBuffer(q, ";\n");
|
appendPQExpBuffer(q, ";\n");
|
||||||
|
|
||||||
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
|
ArchiveEntry(fout, finfo->dobj.catId, finfo->dobj.dumpId,
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.375 2007/01/20 23:13:01 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.376 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 200701203
|
#define CATALOG_VERSION_NO 200701211
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.129 2007/01/09 02:14:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.130 2007/01/22 01:35:21 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -290,39 +290,43 @@ DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
|
|||||||
{ 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
{ 1255, {"pronamespace"}, 26, -1, 4, 2, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
{ 1255, {"proowner"}, 26, -1, 4, 3, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
{ 1255, {"prolang"}, 26, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proisagg"}, 16, -1, 1, 5, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
{ 1255, {"procost"}, 700, -1, 4, 5, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"prosecdef"}, 16, -1, 1, 6, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
{ 1255, {"prorows"}, 700, -1, 4, 6, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proisstrict"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
{ 1255, {"proisagg"}, 16, -1, 1, 7, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proretset"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
{ 1255, {"prosecdef"}, 16, -1, 1, 8, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"provolatile"}, 18, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
{ 1255, {"proisstrict"}, 16, -1, 1, 9, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"pronargs"}, 21, -1, 2, 10, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
|
{ 1255, {"proretset"}, 16, -1, 1, 10, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"prorettype"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
{ 1255, {"provolatile"}, 18, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proargtypes"}, 30, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
|
{ 1255, {"pronargs"}, 21, -1, 2, 12, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proallargtypes"}, 1028, -1, -1, 13, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"prorettype"}, 26, -1, 4, 13, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proargmodes"}, 1002, -1, -1, 14, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"proargtypes"}, 30, -1, -1, 14, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
|
||||||
{ 1255, {"proargnames"}, 1009, -1, -1, 15, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"proallargtypes"}, 1028, -1, -1, 15, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"prosrc"}, 25, -1, -1, 16, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"proargmodes"}, 1002, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"probin"}, 17, -1, -1, 17, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
{ 1255, {"proargnames"}, 1009, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
{ 1255, {"proacl"}, 1034, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
{ 1255, {"prosrc"}, 25, -1, -1, 18, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
|
{ 1255, {"probin"}, 17, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
|
||||||
|
{ 1255, {"proacl"}, 1034, -1, -1, 20, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
|
||||||
|
|
||||||
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
|
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
|
||||||
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 proowner 26 -1 4 3 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 proowner 26 -1 4 3 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 prolang 26 -1 4 4 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 proisagg 16 -1 1 5 0 -1 -1 t p c t f f t 0));
|
DATA(insert ( 1255 procost 700 -1 4 5 0 -1 -1 f p i t f f t 0));
|
||||||
DATA(insert ( 1255 prosecdef 16 -1 1 6 0 -1 -1 t p c t f f t 0));
|
DATA(insert ( 1255 prorows 700 -1 4 6 0 -1 -1 f p i t f f t 0));
|
||||||
DATA(insert ( 1255 proisstrict 16 -1 1 7 0 -1 -1 t p c t f f t 0));
|
DATA(insert ( 1255 proisagg 16 -1 1 7 0 -1 -1 t p c t f f t 0));
|
||||||
DATA(insert ( 1255 proretset 16 -1 1 8 0 -1 -1 t p c t f f t 0));
|
DATA(insert ( 1255 prosecdef 16 -1 1 8 0 -1 -1 t p c t f f t 0));
|
||||||
DATA(insert ( 1255 provolatile 18 -1 1 9 0 -1 -1 t p c t f f t 0));
|
DATA(insert ( 1255 proisstrict 16 -1 1 9 0 -1 -1 t p c t f f t 0));
|
||||||
DATA(insert ( 1255 pronargs 21 -1 2 10 0 -1 -1 t p s t f f t 0));
|
DATA(insert ( 1255 proretset 16 -1 1 10 0 -1 -1 t p c t f f t 0));
|
||||||
DATA(insert ( 1255 prorettype 26 -1 4 11 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 provolatile 18 -1 1 11 0 -1 -1 t p c t f f t 0));
|
||||||
DATA(insert ( 1255 proargtypes 30 -1 -1 12 1 -1 -1 f p i t f f t 0));
|
DATA(insert ( 1255 pronargs 21 -1 2 12 0 -1 -1 t p s t f f t 0));
|
||||||
DATA(insert ( 1255 proallargtypes 1028 -1 -1 13 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 prorettype 26 -1 4 13 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 proargmodes 1002 -1 -1 14 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proargtypes 30 -1 -1 14 1 -1 -1 f p i t f f t 0));
|
||||||
DATA(insert ( 1255 proargnames 1009 -1 -1 15 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proallargtypes 1028 -1 -1 15 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 prosrc 25 -1 -1 16 0 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proargmodes 1002 -1 -1 16 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 probin 17 -1 -1 17 0 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 proargnames 1009 -1 -1 17 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 proacl 1034 -1 -1 18 1 -1 -1 f x i f f f t 0));
|
DATA(insert ( 1255 prosrc 25 -1 -1 18 0 -1 -1 f x i f f f t 0));
|
||||||
|
DATA(insert ( 1255 probin 17 -1 -1 19 0 -1 -1 f x i f f f t 0));
|
||||||
|
DATA(insert ( 1255 proacl 1034 -1 -1 20 1 -1 -1 f x i f f f t 0));
|
||||||
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
|
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
|
||||||
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
|
||||||
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
|
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.99 2007/01/05 22:19:52 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.100 2007/01/22 01:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* the genbki.sh script reads this file and generates .bki
|
* the genbki.sh script reads this file and generates .bki
|
||||||
@ -136,7 +136,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 25 0 0
|
|||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 18 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 20 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 27 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 27 0 0 0 0 0 t f f f 3 _null_ _null_ ));
|
||||||
DESCR("");
|
DESCR("");
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.85 2007/01/05 22:19:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.86 2007/01/22 01:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -51,6 +51,7 @@ extern bool contain_agg_clause(Node *clause);
|
|||||||
extern void count_agg_clauses(Node *clause, AggClauseCounts *counts);
|
extern void count_agg_clauses(Node *clause, AggClauseCounts *counts);
|
||||||
|
|
||||||
extern bool expression_returns_set(Node *clause);
|
extern bool expression_returns_set(Node *clause);
|
||||||
|
extern double expression_returns_set_rows(Node *clause);
|
||||||
|
|
||||||
extern bool contain_subplans(Node *clause);
|
extern bool contain_subplans(Node *clause);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.83 2007/01/05 22:19:56 momjian Exp $
|
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.84 2007/01/22 01:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -89,6 +89,7 @@ extern void cost_nestloop(NestPath *path, PlannerInfo *root);
|
|||||||
extern void cost_mergejoin(MergePath *path, PlannerInfo *root);
|
extern void cost_mergejoin(MergePath *path, PlannerInfo *root);
|
||||||
extern void cost_hashjoin(HashPath *path, PlannerInfo *root);
|
extern void cost_hashjoin(HashPath *path, PlannerInfo *root);
|
||||||
extern void cost_qual_eval(QualCost *cost, List *quals);
|
extern void cost_qual_eval(QualCost *cost, List *quals);
|
||||||
|
extern void cost_qual_eval_node(QualCost *cost, Node *qual);
|
||||||
extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||||
extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
||||||
RelOptInfo *outer_rel,
|
RelOptInfo *outer_rel,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.98 2007/01/20 20:45:40 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.99 2007/01/22 01:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -97,5 +97,6 @@ extern List *set_returning_clause_references(List *rlist,
|
|||||||
Index resultRelation);
|
Index resultRelation);
|
||||||
extern void fix_opfuncids(Node *node);
|
extern void fix_opfuncids(Node *node);
|
||||||
extern void set_opfuncid(OpExpr *opexpr);
|
extern void set_opfuncid(OpExpr *opexpr);
|
||||||
|
extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr);
|
||||||
|
|
||||||
#endif /* PLANMAIN_H */
|
#endif /* PLANMAIN_H */
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.114 2007/01/21 00:57:15 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.115 2007/01/22 01:35:22 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -76,6 +76,8 @@ extern Oid get_func_signature(Oid funcid, Oid **argtypes, int *nargs);
|
|||||||
extern bool get_func_retset(Oid funcid);
|
extern bool get_func_retset(Oid funcid);
|
||||||
extern bool func_strict(Oid funcid);
|
extern bool func_strict(Oid funcid);
|
||||||
extern char func_volatile(Oid funcid);
|
extern char func_volatile(Oid funcid);
|
||||||
|
extern float4 get_func_cost(Oid funcid);
|
||||||
|
extern float4 get_func_rows(Oid funcid);
|
||||||
extern Oid get_relname_relid(const char *relname, Oid relnamespace);
|
extern Oid get_relname_relid(const char *relname, Oid relnamespace);
|
||||||
extern char *get_rel_name(Oid relid);
|
extern char *get_rel_name(Oid relid);
|
||||||
extern Oid get_rel_namespace(Oid relid);
|
extern Oid get_rel_namespace(Oid relid);
|
||||||
|
@ -46,7 +46,9 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
|||||||
p1.pronargs < 0 OR
|
p1.pronargs < 0 OR
|
||||||
array_lower(p1.proargtypes, 1) != 0 OR
|
array_lower(p1.proargtypes, 1) != 0 OR
|
||||||
array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR
|
array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR
|
||||||
0::oid = ANY (p1.proargtypes);
|
0::oid = ANY (p1.proargtypes) OR
|
||||||
|
procost <= 0 OR
|
||||||
|
CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END;
|
||||||
oid | proname
|
oid | proname
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
@ -53,7 +53,9 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
|||||||
p1.pronargs < 0 OR
|
p1.pronargs < 0 OR
|
||||||
array_lower(p1.proargtypes, 1) != 0 OR
|
array_lower(p1.proargtypes, 1) != 0 OR
|
||||||
array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR
|
array_upper(p1.proargtypes, 1) != p1.pronargs-1 OR
|
||||||
0::oid = ANY (p1.proargtypes);
|
0::oid = ANY (p1.proargtypes) OR
|
||||||
|
procost <= 0 OR
|
||||||
|
CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END;
|
||||||
|
|
||||||
-- Look for conflicting proc definitions (same names and input datatypes).
|
-- Look for conflicting proc definitions (same names and input datatypes).
|
||||||
-- (This test should be dead code now that we have the unique index
|
-- (This test should be dead code now that we have the unique index
|
||||||
|
Loading…
x
Reference in New Issue
Block a user