Remove add_missing_from GUC and associated parser support for "implicit RTEs".

Per recent discussion, add_missing_from has been deprecated for long enough to
consider removing, and it's getting in the way of planned parser refactoring.
The system now always behaves as though add_missing_from were OFF.
This commit is contained in:
Tom Lane 2009-10-21 20:22:38 +00:00
parent e1c96527c7
commit 289e2905c8
17 changed files with 57 additions and 204 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.230 2009/10/03 23:10:47 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.231 2009/10/21 20:22:38 tgl Exp $ -->
<chapter Id="runtime-config">
<title>Server Configuration</title>
@ -4659,37 +4659,6 @@ dynamic_library_path = 'C:\tools\postgresql;H:\my_project\lib;$libdir'
<variablelist>
<varlistentry id="guc-add-missing-from" xreflabel="add_missing_from">
<term><varname>add_missing_from</varname> (<type>boolean</type>)</term>
<indexterm><primary>FROM</><secondary>missing</></>
<indexterm>
<primary><varname>add_missing_from</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
When on, tables that are referenced by a query will be
automatically added to the <literal>FROM</> clause if not
already present. This behavior does not comply with the SQL
standard and many people dislike it because it can mask mistakes
(such as referencing a table where you should have referenced
its alias). The default is <literal>off</>. This variable can be
enabled for compatibility with releases of
<productname>PostgreSQL</> prior to 8.1, where this behavior was
allowed by default.
</para>
<para>
Note that even when this variable is enabled, a warning
message will be emitted for each implicit <literal>FROM</>
entry referenced by a query. Users are encouraged to update
their applications to not rely on this behavior, by adding all
tables referenced by a query to the query's <literal>FROM</>
clause (or its <literal>USING</> clause in the case of
<command>DELETE</>).
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-array-nulls" xreflabel="array_nulls">
<term><varname>array_nulls</varname> (<type>boolean</type>)</term>
<indexterm>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/queries.sgml,v 1.55 2009/06/17 21:58:49 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/queries.sgml,v 1.56 2009/10/21 20:22:38 tgl Exp $ -->
<chapter id="queries">
<title>Queries</title>
@ -521,23 +521,13 @@ SELECT * FROM some_very_long_table_name s JOIN another_fairly_long_name a ON s.i
</para>
<para>
The alias becomes the new name of the table reference for the
current query &mdash; it is no longer possible to refer to the table
by the original name. Thus:
The alias becomes the new name of the table reference so far as the
current query is concerned &mdash; it is not allowed to refer to the
table by the original name elsewhere in the query. Thus, this is not
valid:
<programlisting>
SELECT * FROM my_table AS m WHERE my_table.a &gt; 5;
SELECT * FROM my_table AS m WHERE my_table.a &gt; 5; -- wrong
</programlisting>
is not valid according to the SQL standard. In
<productname>PostgreSQL</productname> this will draw an error, assuming the
<xref linkend="guc-add-missing-from"> configuration variable is
<literal>off</> (as it is by default). If it is <literal>on</>,
an implicit table reference will be added to the
<literal>FROM</literal> clause, so the query is processed as if
it were written as:
<programlisting>
SELECT * FROM my_table AS m, my_table AS my_table WHERE my_table.a &gt; 5;
</programlisting>
That will result in a cross join, which is usually not what you want.
</para>
<para>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.125 2009/09/18 05:00:42 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/select.sgml,v 1.126 2009/10/21 20:22:38 tgl Exp $
PostgreSQL documentation
-->
@ -1451,12 +1451,7 @@ SELECT distributors.* WHERE distributors.name = 'Westward';
<productname>PostgreSQL</productname> releases prior to
8.1 would accept queries of this form, and add an implicit entry
to the query's <literal>FROM</literal> clause for each table
referenced by the query. This is no longer the default behavior,
because it does not comply with the SQL standard, and is
considered by many to be error-prone. For compatibility with
applications that rely on this behavior the <xref
linkend="guc-add-missing-from"> configuration variable can be
enabled.
referenced by the query. This is no longer allowed.
</para>
</refsect2>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/show.sgml,v 1.47 2008/11/14 10:22:47 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/show.sgml,v 1.48 2009/10/21 20:22:38 tgl Exp $
PostgreSQL documentation
-->
@ -168,16 +168,15 @@ SHOW geqo;
Show all settings:
<programlisting>
SHOW ALL;
name | setting | description
--------------------------------+--------------------------------+----------------------------------------------------------------------------------------------
add_missing_from | off | Automatically adds missing table references to FROM clauses.
allow_system_table_mods | off | Allows modifications of the structure of system tables.
name | setting | description
---------------------------------+-------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------
allow_system_table_mods | off | Allows modifications of the structure of system tables.
.
.
.
work_mem | 1024 | Sets the maximum memory to be used for query workspaces.
zero_damaged_pages | off | Continues processing past damaged page headers.
(146 rows)
xmloption | content | Sets whether XML data in implicit parsing and serialization operations is to be considered as documents or content fragments.
zero_damaged_pages | off | Continues processing past damaged page headers.
(196 rows)
</programlisting>
</para>
</refsect1>

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.244 2009/10/08 02:39:23 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.245 2009/10/21 20:22:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -500,14 +500,13 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
name2 = strVal(field2);
/* Try to identify as a once-qualified column */
node = qualifiedNameToVar(pstate, NULL, name1, name2, true,
node = qualifiedNameToVar(pstate, NULL, name1, name2,
cref->location);
if (node == NULL)
{
/*
* Not known as a column of any range-table entry, so try
* it as a function call. Here, we will create an
* implicit RTE for tables not already entered.
* it as a function call.
*/
node = transformWholeRowRef(pstate, NULL, name1,
cref->location);
@ -545,7 +544,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
name3 = strVal(field3);
/* Try to identify as a twice-qualified column */
node = qualifiedNameToVar(pstate, name1, name2, name3, true,
node = qualifiedNameToVar(pstate, name1, name2, name3,
cref->location);
if (node == NULL)
{
@ -600,7 +599,7 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref)
name4 = strVal(field4);
/* Try to identify as a twice-qualified column */
node = qualifiedNameToVar(pstate, name2, name3, name4, true,
node = qualifiedNameToVar(pstate, name2, name3, name4,
cref->location);
if (node == NULL)
{
@ -1906,14 +1905,14 @@ transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname,
int sublevels_up;
Oid toid;
/* Look up the referenced RTE, creating it if needed */
/* Look up the referenced RTE, failing if not present */
rte = refnameRangeTblEntry(pstate, schemaname, relname, location,
&sublevels_up);
if (rte == NULL)
rte = addImplicitRTE(pstate,
makeRangeVar(schemaname, relname, location));
errorMissingRTE(pstate,
makeRangeVar(schemaname, relname, location));
vnum = RTERangeTablePosn(pstate, rte, &sublevels_up);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.143 2009/07/16 06:33:43 petere Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.144 2009/10/21 20:22:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -32,9 +32,6 @@
#include "utils/syscache.h"
/* GUC parameter */
bool add_missing_from;
static RangeTblEntry *scanNameSpaceForRefname(ParseState *pstate,
const char *refname, int location);
static RangeTblEntry *scanNameSpaceForRelid(ParseState *pstate, Oid relid,
@ -51,7 +48,6 @@ static void expandTupleDesc(TupleDesc tupdesc, Alias *eref,
int location, bool include_dropped,
List **colnames, List **colvars);
static int specialAttNum(const char *attname);
static void warnAutoRange(ParseState *pstate, RangeVar *relation);
/*
@ -249,7 +245,7 @@ isFutureCTE(ParseState *pstate, const char *refname)
* visible in the p_relnamespace lists. This behavior is invalid per the SQL
* spec, and it may give ambiguous results (there might be multiple equally
* valid matches, but only one will be returned). This must be used ONLY
* as a heuristic in giving suitable error messages. See warnAutoRange.
* as a heuristic in giving suitable error messages. See errorMissingRTE.
*
* Notice that we consider both matches on actual relation (or CTE) name
* and matches on alias.
@ -573,7 +569,6 @@ qualifiedNameToVar(ParseState *pstate,
char *schemaname,
char *refname,
char *colname,
bool implicitRTEOK,
int location)
{
RangeTblEntry *rte;
@ -581,14 +576,8 @@ qualifiedNameToVar(ParseState *pstate,
rte = refnameRangeTblEntry(pstate, schemaname, refname, location,
&sublevels_up);
if (rte == NULL)
{
if (!implicitRTEOK)
return NULL;
rte = addImplicitRTE(pstate,
makeRangeVar(schemaname, refname, location));
}
return NULL;
return scanRTEForColumn(pstate, rte, colname, location);
}
@ -1527,42 +1516,6 @@ addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
pstate->p_varnamespace = lappend(pstate->p_varnamespace, rte);
}
/*
* Add a POSTQUEL-style implicit RTE.
*
* We assume caller has already checked that there is no RTE or join with
* a conflicting name.
*/
RangeTblEntry *
addImplicitRTE(ParseState *pstate, RangeVar *relation)
{
CommonTableExpr *cte = NULL;
Index levelsup = 0;
RangeTblEntry *rte;
/* issue warning or error as needed */
warnAutoRange(pstate, relation);
/* if it is an unqualified name, it might be a CTE reference */
if (!relation->schemaname)
cte = scanNameSpaceForCTE(pstate, relation->relname, &levelsup);
/*
* Note that we set inFromCl true, so that the RTE will be listed
* explicitly if the parsetree is ever decompiled by ruleutils.c. This
* provides a migration path for views/rules that were originally written
* with implicit-RTE syntax.
*/
if (cte)
rte = addRangeTableEntryForCTE(pstate, cte, levelsup, NULL, true);
else
rte = addRangeTableEntry(pstate, relation, NULL, false, true);
/* Add to joinlist and relnamespace, but not varnamespace */
addRTEtoQuery(pstate, rte, true, true, false);
return rte;
}
/*
* expandRTE -- expand the columns of a rangetable entry
*
@ -2417,13 +2370,13 @@ attnumTypeId(Relation rd, int attid)
}
/*
* Generate a warning or error about an implicit RTE, if appropriate.
* Generate a suitable error about a missing RTE.
*
* If ADD_MISSING_FROM is not enabled, raise an error. Otherwise, emit
* a warning.
* Since this is a very common type of error, we work rather hard to
* produce a helpful message.
*/
static void
warnAutoRange(ParseState *pstate, RangeVar *relation)
void
errorMissingRTE(ParseState *pstate, RangeVar *relation)
{
RangeTblEntry *rte;
int sublevels_up;
@ -2431,7 +2384,7 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
/*
* Check to see if there are any potential matches in the query's
* rangetable. This affects the message we provide.
* rangetable.
*/
rte = searchRangeTable(pstate, relation);
@ -2452,39 +2405,21 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
&sublevels_up) == rte)
badAlias = rte->eref->aliasname;
if (!add_missing_from)
{
if (rte)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
(badAlias ?
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias) :
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname)),
parser_errposition(pstate, relation->location)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("missing FROM-clause entry for table \"%s\"",
relation->relname),
parser_errposition(pstate, relation->location)));
}
else
{
/* just issue a warning */
ereport(NOTICE,
if (rte)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("adding missing FROM-clause entry for table \"%s\"",
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
relation->relname),
(badAlias ?
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias) :
(rte ?
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname) : 0)),
errhint("Perhaps you meant to reference the table alias \"%s\".",
badAlias) :
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
rte->eref->aliasname)),
parser_errposition(pstate, relation->location)));
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("missing FROM-clause entry for table \"%s\"",
relation->relname),
parser_errposition(pstate, relation->location)));
}
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.172 2009/07/16 06:33:43 petere Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.173 2009/10/21 20:22:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -927,9 +927,8 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
rte = refnameRangeTblEntry(pstate, schemaname, relname, cref->location,
&sublevels_up);
if (rte == NULL)
rte = addImplicitRTE(pstate,
makeRangeVar(schemaname, relname,
cref->location));
errorMissingRTE(pstate,
makeRangeVar(schemaname, relname, cref->location));
rtindex = RTERangeTablePosn(pstate, rte, &sublevels_up);
@ -973,8 +972,7 @@ ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref,
*
* tlist entries are generated for each relation appearing in the query's
* varnamespace. We do not consider relnamespace because that would include
* input tables of aliasless JOINs, NEW/OLD pseudo-entries, implicit RTEs,
* etc.
* input tables of aliasless JOINs, NEW/OLD pseudo-entries, etc.
*
* The referenced relations/columns are marked as requiring SELECT access.
*/

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.521 2009/10/13 14:18:40 alvherre Exp $
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.522 2009/10/21 20:22:38 tgl Exp $
*
*--------------------------------------------------------------------
*/
@ -45,7 +45,6 @@
#include "optimizer/paths.h"
#include "optimizer/planmain.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "parser/parser.h"
#include "parser/scansup.h"
@ -1057,14 +1056,6 @@ static struct config_bool ConfigureNamesBool[] =
&XactReadOnly,
false, assign_transaction_read_only, NULL
},
{
{"add_missing_from", PGC_USERSET, COMPAT_OPTIONS_PREVIOUS,
gettext_noop("Automatically adds missing table references to FROM clauses."),
NULL
},
&add_missing_from,
false, NULL, NULL
},
{
{"check_function_bodies", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Check function bodies during CREATE FUNCTION."),

View File

@ -484,7 +484,6 @@
# - Previous PostgreSQL Versions -
#add_missing_from = off
#array_nulls = on
#backslash_quote = safe_encoding # on, off, or safe_encoding
#default_with_oids = off

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.63 2009/09/09 03:32:52 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.64 2009/10/21 20:22:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -50,9 +50,8 @@
* This is different from p_relnamespace because a JOIN without an alias does
* not hide the contained tables (so they must still be in p_relnamespace)
* but it does hide their columns (unqualified references to the columns must
* refer to the JOIN, not the member tables). Also, we put POSTQUEL-style
* implicit RTEs into p_relnamespace but not p_varnamespace, so that they
* do not affect the set of columns available for unqualified references.
* refer to the JOIN, not the member tables). Other special RTEs such as
* NEW/OLD for rules may also appear in just one of these lists.
*
* p_ctenamespace: list of CommonTableExprs (WITH items) that are visible
* at the moment. This is different from p_relnamespace because you have

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.64 2009/06/11 14:49:11 momjian Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.65 2009/10/21 20:22:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,8 +16,6 @@
#include "parser/parse_node.h"
extern bool add_missing_from;
extern RangeTblEntry *refnameRangeTblEntry(ParseState *pstate,
const char *schemaname,
const char *refname,
@ -44,7 +42,6 @@ extern Node *qualifiedNameToVar(ParseState *pstate,
char *schemaname,
char *refname,
char *colname,
bool implicitRTEOK,
int location);
extern void markVarForSelectPriv(ParseState *pstate, Var *var,
RangeTblEntry *rte);
@ -87,7 +84,7 @@ extern RangeTblEntry *addRangeTableEntryForCTE(ParseState *pstate,
extern void addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
bool addToJoinList,
bool addToRelNameSpace, bool addToVarNameSpace);
extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation);
extern void errorMissingRTE(ParseState *pstate, RangeVar *relation);
extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up,
int location, bool include_dropped,
List **colnames, List **colvars);

View File

@ -11,14 +11,11 @@ INSERT INTO delete_test (a) VALUES (100);
DELETE FROM delete_test AS dt WHERE dt.a > 75;
-- if an alias is specified, don't allow the original table name
-- to be referenced
BEGIN;
SET LOCAL add_missing_from = false;
DELETE FROM delete_test dt WHERE delete_test.a > 25;
ERROR: invalid reference to FROM-clause entry for table "delete_test"
LINE 1: DELETE FROM delete_test dt WHERE delete_test.a > 25;
^
HINT: Perhaps you meant to reference the table alias "dt".
ROLLBACK;
SELECT * FROM delete_test;
id | a
----+----

View File

@ -63,13 +63,10 @@ select * from quadtable;
2 | ("(,4.4)","(5.5,6.6)")
(2 rows)
begin;
set local add_missing_from = false;
select f1, q.c1 from quadtable; -- fails, q is a table reference
ERROR: missing FROM-clause entry for table "q"
LINE 1: select f1, q.c1 from quadtable;
^
rollback;
select f1, (q).c1, (qq.q).c1.i from quadtable qq;
f1 | c1 | i
----+-----------+-----

View File

@ -82,12 +82,9 @@ LINE 1: UPDATE update_test SET (a,b) = (select a,b FROM update_test ...
^
-- if an alias for the target table is specified, don't allow references
-- to the original table name
BEGIN;
SET LOCAL add_missing_from = false;
UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10;
ERROR: invalid reference to FROM-clause entry for table "update_test"
LINE 1: UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a...
^
HINT: Perhaps you meant to reference the table alias "t".
ROLLBACK;
DROP TABLE update_test;

View File

@ -12,11 +12,8 @@ DELETE FROM delete_test AS dt WHERE dt.a > 75;
-- if an alias is specified, don't allow the original table name
-- to be referenced
BEGIN;
SET LOCAL add_missing_from = false;
DELETE FROM delete_test dt WHERE delete_test.a > 25;
ROLLBACK;
SELECT * FROM delete_test;
DROP TABLE delete_test;
DROP TABLE delete_test;

View File

@ -35,10 +35,7 @@ insert into quadtable values (2, ((null,4.4),(5.5,6.6)));
select * from quadtable;
begin;
set local add_missing_from = false;
select f1, q.c1 from quadtable; -- fails, q is a table reference
rollback;
select f1, (q).c1, (qq.q).c1.i from quadtable qq;

View File

@ -52,9 +52,6 @@ UPDATE update_test SET (a,b) = (select a,b FROM update_test where c = 'foo')
-- if an alias for the target table is specified, don't allow references
-- to the original table name
BEGIN;
SET LOCAL add_missing_from = false;
UPDATE update_test AS t SET b = update_test.b + 10 WHERE t.a = 10;
ROLLBACK;
DROP TABLE update_test;