mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +03:00
Code review for standalone composite types, query-specified composite
types, SRFs. Not happy with memory management yet, but I'll commit these other changes.
This commit is contained in:
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.363 2002/08/28 20:46:23 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.364 2002/08/29 00:17:04 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -204,8 +204,8 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%type <list> stmtblock, stmtmulti,
|
||||
OptTableElementList, TableElementList, OptInherit, definition,
|
||||
opt_distinct, opt_definition, func_args, rowdefinition
|
||||
func_args_list, func_as, createfunc_opt_list
|
||||
opt_distinct, opt_definition, func_args,
|
||||
func_args_list, func_as, createfunc_opt_list,
|
||||
oper_argtypes, RuleActionList, RuleActionMulti,
|
||||
opt_column_list, columnList, opt_name_list,
|
||||
sort_clause, opt_sort_clause, sortby_list, index_params,
|
||||
@@ -216,7 +216,7 @@ static void doNegateFloat(Value *v);
|
||||
insert_target_list, def_list, opt_indirection,
|
||||
group_clause, TriggerFuncArgs, select_limit,
|
||||
opt_select_limit, opclass_item_list, trans_options,
|
||||
TableFuncElementList, OptTableFuncElementList,
|
||||
TableFuncElementList,
|
||||
convert_args, prep_type_clause, prep_type_list,
|
||||
execute_param_clause, execute_param_list
|
||||
|
||||
@@ -1424,14 +1424,14 @@ OptTableElementList:
|
||||
;
|
||||
|
||||
TableElementList:
|
||||
TableElementList ',' TableElement
|
||||
{
|
||||
$$ = lappend($1, $3);
|
||||
}
|
||||
| TableElement
|
||||
TableElement
|
||||
{
|
||||
$$ = makeList1($1);
|
||||
}
|
||||
| TableElementList ',' TableElement
|
||||
{
|
||||
$$ = lappend($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
TableElement:
|
||||
@@ -2234,11 +2234,12 @@ DefineStmt:
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE TYPE_P any_name AS rowdefinition
|
||||
| CREATE TYPE_P any_name AS '(' TableFuncElementList ')'
|
||||
{
|
||||
CompositeTypeStmt *n = makeNode(CompositeTypeStmt);
|
||||
RangeVar *r = makeNode(RangeVar);
|
||||
|
||||
/* can't use qualified_name, sigh */
|
||||
switch (length($3))
|
||||
{
|
||||
case 1:
|
||||
@@ -2258,13 +2259,12 @@ DefineStmt:
|
||||
break;
|
||||
default:
|
||||
elog(ERROR,
|
||||
"Improper qualified name "
|
||||
"(too many dotted names): %s",
|
||||
"Improper qualified name (too many dotted names): %s",
|
||||
NameListToString($3));
|
||||
break;
|
||||
}
|
||||
n->typevar = r;
|
||||
n->coldeflist = $5;
|
||||
n->coldeflist = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE CHARACTER SET opt_as any_name GET definition opt_collate
|
||||
@@ -2277,9 +2277,6 @@ DefineStmt:
|
||||
}
|
||||
;
|
||||
|
||||
rowdefinition: '(' TableFuncElementList ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
definition: '(' def_list ')' { $$ = $2; }
|
||||
;
|
||||
|
||||
@@ -4539,14 +4536,22 @@ table_ref: relation_expr
|
||||
n->coldeflist = NIL;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| func_table AS '(' OptTableFuncElementList ')'
|
||||
| func_table alias_clause
|
||||
{
|
||||
RangeFunction *n = makeNode(RangeFunction);
|
||||
n->funccallnode = $1;
|
||||
n->alias = $2;
|
||||
n->coldeflist = NIL;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| func_table AS '(' TableFuncElementList ')'
|
||||
{
|
||||
RangeFunction *n = makeNode(RangeFunction);
|
||||
n->funccallnode = $1;
|
||||
n->coldeflist = $4;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| func_table AS ColId '(' OptTableFuncElementList ')'
|
||||
| func_table AS ColId '(' TableFuncElementList ')'
|
||||
{
|
||||
RangeFunction *n = makeNode(RangeFunction);
|
||||
Alias *a = makeNode(Alias);
|
||||
@@ -4556,7 +4561,7 @@ table_ref: relation_expr
|
||||
n->coldeflist = $5;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| func_table ColId '(' OptTableFuncElementList ')'
|
||||
| func_table ColId '(' TableFuncElementList ')'
|
||||
{
|
||||
RangeFunction *n = makeNode(RangeFunction);
|
||||
Alias *a = makeNode(Alias);
|
||||
@@ -4566,14 +4571,6 @@ table_ref: relation_expr
|
||||
n->coldeflist = $4;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| func_table alias_clause
|
||||
{
|
||||
RangeFunction *n = makeNode(RangeFunction);
|
||||
n->funccallnode = $1;
|
||||
n->alias = $2;
|
||||
n->coldeflist = NIL;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| select_with_parens
|
||||
{
|
||||
/*
|
||||
@@ -4815,25 +4812,19 @@ func_table: func_name '(' ')'
|
||||
|
||||
where_clause:
|
||||
WHERE a_expr { $$ = $2; }
|
||||
/* no qualifiers */
|
||||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
|
||||
OptTableFuncElementList:
|
||||
TableFuncElementList { $$ = $1; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
;
|
||||
|
||||
TableFuncElementList:
|
||||
TableFuncElementList ',' TableFuncElement
|
||||
{
|
||||
$$ = lappend($1, $3);
|
||||
}
|
||||
| TableFuncElement
|
||||
TableFuncElement
|
||||
{
|
||||
$$ = makeList1($1);
|
||||
}
|
||||
| TableFuncElementList ',' TableFuncElement
|
||||
{
|
||||
$$ = lappend($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
TableFuncElement: ColId Typename
|
||||
@@ -4842,7 +4833,6 @@ TableFuncElement: ColId Typename
|
||||
n->colname = $1;
|
||||
n->typename = $2;
|
||||
n->constraints = NIL;
|
||||
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.77 2002/08/08 17:00:19 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.78 2002/08/29 00:17:04 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -900,17 +900,14 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
* Now determine if the function returns a simple or composite type,
|
||||
* and check/add column aliases.
|
||||
*/
|
||||
functyptype = get_typtype(funcrettype);
|
||||
|
||||
if (coldeflist != NIL)
|
||||
{
|
||||
/*
|
||||
* we *only* allow a coldeflist for functions returning a
|
||||
* RECORD pseudo-type
|
||||
*/
|
||||
if (functyptype != 'p' || (functyptype == 'p' && funcrettype != RECORDOID))
|
||||
elog(ERROR, "A column definition list is only allowed for"
|
||||
" functions returning RECORD");
|
||||
if (funcrettype != RECORDOID)
|
||||
elog(ERROR, "A column definition list is only allowed for functions returning RECORD");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -918,57 +915,55 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
* ... and a coldeflist is *required* for functions returning a
|
||||
* RECORD pseudo-type
|
||||
*/
|
||||
if (functyptype == 'p' && funcrettype == RECORDOID)
|
||||
elog(ERROR, "A column definition list is required for functions"
|
||||
" returning RECORD");
|
||||
if (funcrettype == RECORDOID)
|
||||
elog(ERROR, "A column definition list is required for functions returning RECORD");
|
||||
}
|
||||
|
||||
functyptype = get_typtype(funcrettype);
|
||||
|
||||
if (functyptype == 'c')
|
||||
{
|
||||
/*
|
||||
* Named composite data type, i.e. a table's row type
|
||||
*/
|
||||
Oid funcrelid = typeidTypeRelid(funcrettype);
|
||||
Relation rel;
|
||||
int maxattrs;
|
||||
|
||||
if (OidIsValid(funcrelid))
|
||||
if (!OidIsValid(funcrelid))
|
||||
elog(ERROR, "Invalid typrelid for complex type %u",
|
||||
funcrettype);
|
||||
|
||||
/*
|
||||
* Get the rel's relcache entry. This access ensures that we have an
|
||||
* up-to-date relcache entry for the rel.
|
||||
*/
|
||||
rel = relation_open(funcrelid, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Since the rel is open anyway, let's check that the number of column
|
||||
* aliases is reasonable.
|
||||
*/
|
||||
maxattrs = RelationGetNumberOfAttributes(rel);
|
||||
if (maxattrs < numaliases)
|
||||
elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
|
||||
RelationGetRelationName(rel), maxattrs, numaliases);
|
||||
|
||||
/* fill in alias columns using actual column names */
|
||||
for (varattno = numaliases; varattno < maxattrs; varattno++)
|
||||
{
|
||||
/*
|
||||
* Get the rel's relcache entry. This access ensures that we have an
|
||||
* up-to-date relcache entry for the rel.
|
||||
*/
|
||||
Relation rel;
|
||||
int maxattrs;
|
||||
char *attrname;
|
||||
|
||||
rel = heap_open(funcrelid, AccessShareLock);
|
||||
|
||||
/*
|
||||
* Since the rel is open anyway, let's check that the number of column
|
||||
* aliases is reasonable.
|
||||
*/
|
||||
maxattrs = RelationGetNumberOfAttributes(rel);
|
||||
if (maxattrs < numaliases)
|
||||
elog(ERROR, "Table \"%s\" has %d columns available but %d columns specified",
|
||||
RelationGetRelationName(rel), maxattrs, numaliases);
|
||||
|
||||
/* fill in alias columns using actual column names */
|
||||
for (varattno = numaliases; varattno < maxattrs; varattno++)
|
||||
{
|
||||
char *attrname;
|
||||
|
||||
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
|
||||
eref->colnames = lappend(eref->colnames, makeString(attrname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the rel refcount, but keep the access lock till end of
|
||||
* transaction so that the table can't be deleted or have its schema
|
||||
* modified underneath us.
|
||||
*/
|
||||
heap_close(rel, NoLock);
|
||||
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
|
||||
eref->colnames = lappend(eref->colnames, makeString(attrname));
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Invalid return relation specified for function %s",
|
||||
funcname);
|
||||
|
||||
/*
|
||||
* Drop the rel refcount, but keep the access lock till end of
|
||||
* transaction so that the table can't be deleted or have its schema
|
||||
* modified underneath us.
|
||||
*/
|
||||
relation_close(rel, NoLock);
|
||||
}
|
||||
else if (functyptype == 'b' || functyptype == 'd')
|
||||
{
|
||||
@@ -986,10 +981,12 @@ addRangeTableEntryForFunction(ParseState *pstate,
|
||||
{
|
||||
List *col;
|
||||
|
||||
/* Use the column definition list to form the alias list */
|
||||
eref->colnames = NIL;
|
||||
foreach(col, coldeflist)
|
||||
{
|
||||
char *attrname;
|
||||
ColumnDef *n = lfirst(col);
|
||||
char *attrname;
|
||||
|
||||
attrname = pstrdup(n->colname);
|
||||
eref->colnames = lappend(eref->colnames, makeString(attrname));
|
||||
@@ -1277,63 +1274,58 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
|
||||
char functyptype = get_typtype(funcrettype);
|
||||
List *coldeflist = rte->coldeflist;
|
||||
|
||||
/*
|
||||
* Build a suitable tupledesc representing the output rows
|
||||
*/
|
||||
if (functyptype == 'c')
|
||||
{
|
||||
/*
|
||||
* Composite data type, i.e. a table's row type
|
||||
* Same as ordinary relation RTE
|
||||
*/
|
||||
Oid funcrelid = typeidTypeRelid(funcrettype);
|
||||
if (OidIsValid(funcrelid))
|
||||
Relation rel;
|
||||
int maxattrs;
|
||||
int numaliases;
|
||||
|
||||
if (!OidIsValid(funcrelid))
|
||||
elog(ERROR, "Invalid typrelid for complex type %u",
|
||||
funcrettype);
|
||||
|
||||
rel = relation_open(funcrelid, AccessShareLock);
|
||||
maxattrs = RelationGetNumberOfAttributes(rel);
|
||||
numaliases = length(rte->eref->colnames);
|
||||
|
||||
for (varattno = 0; varattno < maxattrs; varattno++)
|
||||
{
|
||||
/*
|
||||
* Composite data type, i.e. a table's row type
|
||||
* Same as ordinary relation RTE
|
||||
*/
|
||||
Relation rel;
|
||||
int maxattrs;
|
||||
int numaliases;
|
||||
Form_pg_attribute attr = rel->rd_att->attrs[varattno];
|
||||
|
||||
rel = heap_open(funcrelid, AccessShareLock);
|
||||
maxattrs = RelationGetNumberOfAttributes(rel);
|
||||
numaliases = length(rte->eref->colnames);
|
||||
if (attr->attisdropped)
|
||||
continue;
|
||||
|
||||
for (varattno = 0; varattno < maxattrs; varattno++)
|
||||
if (colnames)
|
||||
{
|
||||
Form_pg_attribute attr = rel->rd_att->attrs[varattno];
|
||||
char *label;
|
||||
|
||||
if (attr->attisdropped)
|
||||
continue;
|
||||
|
||||
if (colnames)
|
||||
{
|
||||
char *label;
|
||||
|
||||
if (varattno < numaliases)
|
||||
label = strVal(nth(varattno, rte->eref->colnames));
|
||||
else
|
||||
label = NameStr(attr->attname);
|
||||
*colnames = lappend(*colnames, makeString(pstrdup(label)));
|
||||
}
|
||||
|
||||
if (colvars)
|
||||
{
|
||||
Var *varnode;
|
||||
|
||||
varnode = makeVar(rtindex,
|
||||
attr->attnum,
|
||||
attr->atttypid,
|
||||
attr->atttypmod,
|
||||
sublevels_up);
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
if (varattno < numaliases)
|
||||
label = strVal(nth(varattno, rte->eref->colnames));
|
||||
else
|
||||
label = NameStr(attr->attname);
|
||||
*colnames = lappend(*colnames, makeString(pstrdup(label)));
|
||||
}
|
||||
|
||||
heap_close(rel, AccessShareLock);
|
||||
if (colvars)
|
||||
{
|
||||
Var *varnode;
|
||||
|
||||
varnode = makeVar(rtindex,
|
||||
attr->attnum,
|
||||
attr->atttypid,
|
||||
attr->atttypmod,
|
||||
sublevels_up);
|
||||
|
||||
*colvars = lappend(*colvars, varnode);
|
||||
}
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Invalid return relation specified"
|
||||
" for function");
|
||||
|
||||
relation_close(rel, AccessShareLock);
|
||||
}
|
||||
else if (functyptype == 'b' || functyptype == 'd')
|
||||
{
|
||||
@@ -1376,12 +1368,9 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
|
||||
if (colvars)
|
||||
{
|
||||
Var *varnode;
|
||||
HeapTuple typeTuple;
|
||||
Oid atttypid;
|
||||
|
||||
typeTuple = typenameType(colDef->typename);
|
||||
atttypid = HeapTupleGetOid(typeTuple);
|
||||
ReleaseSysCache(typeTuple);
|
||||
atttypid = typenameTypeId(colDef->typename);
|
||||
|
||||
varnode = makeVar(rtindex,
|
||||
attnum,
|
||||
@@ -1394,8 +1383,7 @@ expandRTE(ParseState *pstate, RangeTblEntry *rte,
|
||||
}
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Unknown kind of return type specified"
|
||||
" for function");
|
||||
elog(ERROR, "Unknown kind of return type specified for function");
|
||||
}
|
||||
break;
|
||||
case RTE_JOIN:
|
||||
@@ -1595,9 +1583,6 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
|
||||
char functyptype = get_typtype(funcrettype);
|
||||
List *coldeflist = rte->coldeflist;
|
||||
|
||||
/*
|
||||
* Build a suitable tupledesc representing the output rows
|
||||
*/
|
||||
if (functyptype == 'c')
|
||||
{
|
||||
/*
|
||||
@@ -1605,36 +1590,33 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
|
||||
* Same as ordinary relation RTE
|
||||
*/
|
||||
Oid funcrelid = typeidTypeRelid(funcrettype);
|
||||
HeapTuple tp;
|
||||
Form_pg_attribute att_tup;
|
||||
|
||||
if (OidIsValid(funcrelid))
|
||||
{
|
||||
HeapTuple tp;
|
||||
Form_pg_attribute att_tup;
|
||||
if (!OidIsValid(funcrelid))
|
||||
elog(ERROR, "Invalid typrelid for complex type %u",
|
||||
funcrettype);
|
||||
|
||||
tp = SearchSysCache(ATTNUM,
|
||||
ObjectIdGetDatum(funcrelid),
|
||||
Int16GetDatum(attnum),
|
||||
0, 0);
|
||||
/* this shouldn't happen... */
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "Relation %s does not have attribute %d",
|
||||
get_rel_name(funcrelid), attnum);
|
||||
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
|
||||
/*
|
||||
* If dropped column, pretend it ain't there. See notes
|
||||
* in scanRTEForColumn.
|
||||
*/
|
||||
if (att_tup->attisdropped)
|
||||
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
|
||||
get_rel_name(funcrelid),
|
||||
NameStr(att_tup->attname));
|
||||
*vartype = att_tup->atttypid;
|
||||
*vartypmod = att_tup->atttypmod;
|
||||
ReleaseSysCache(tp);
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Invalid return relation specified"
|
||||
" for function");
|
||||
tp = SearchSysCache(ATTNUM,
|
||||
ObjectIdGetDatum(funcrelid),
|
||||
Int16GetDatum(attnum),
|
||||
0, 0);
|
||||
/* this shouldn't happen... */
|
||||
if (!HeapTupleIsValid(tp))
|
||||
elog(ERROR, "Relation \"%s\" does not have attribute %d",
|
||||
get_rel_name(funcrelid), attnum);
|
||||
att_tup = (Form_pg_attribute) GETSTRUCT(tp);
|
||||
/*
|
||||
* If dropped column, pretend it ain't there. See notes
|
||||
* in scanRTEForColumn.
|
||||
*/
|
||||
if (att_tup->attisdropped)
|
||||
elog(ERROR, "Relation \"%s\" has no column \"%s\"",
|
||||
get_rel_name(funcrelid),
|
||||
NameStr(att_tup->attname));
|
||||
*vartype = att_tup->atttypid;
|
||||
*vartypmod = att_tup->atttypmod;
|
||||
ReleaseSysCache(tp);
|
||||
}
|
||||
else if (functyptype == 'b' || functyptype == 'd')
|
||||
{
|
||||
@@ -1647,19 +1629,12 @@ get_rte_attribute_type(RangeTblEntry *rte, AttrNumber attnum,
|
||||
else if (functyptype == 'p' && funcrettype == RECORDOID)
|
||||
{
|
||||
ColumnDef *colDef = nth(attnum - 1, coldeflist);
|
||||
HeapTuple typeTuple;
|
||||
Oid atttypid;
|
||||
|
||||
typeTuple = typenameType(colDef->typename);
|
||||
atttypid = HeapTupleGetOid(typeTuple);
|
||||
ReleaseSysCache(typeTuple);
|
||||
|
||||
*vartype = atttypid;
|
||||
*vartype = typenameTypeId(colDef->typename);
|
||||
*vartypmod = -1;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "Unknown kind of return type specified"
|
||||
" for function");
|
||||
elog(ERROR, "Unknown kind of return type specified for function");
|
||||
}
|
||||
break;
|
||||
case RTE_JOIN:
|
||||
|
Reference in New Issue
Block a user