mirror of
https://github.com/postgres/postgres.git
synced 2025-08-25 20:23:07 +03:00
pg_type has a typnamespace column; system now supports creating types
in different namespaces. Also, cleanup work on relation namespace support: drop, alter, rename commands work for tables in non-default namespaces.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.223 2002/03/26 19:15:56 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.224 2002/03/29 19:06:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -108,11 +108,7 @@ static void transformIndexConstraints(ParseState *pstate,
|
||||
CreateStmtContext *cxt);
|
||||
static void transformFKConstraints(ParseState *pstate,
|
||||
CreateStmtContext *cxt);
|
||||
static Node *transformTypeRefs(ParseState *pstate, Node *stmt);
|
||||
|
||||
static void applyColumnNames(List *dst, List *src);
|
||||
static void transformTypeRefsList(ParseState *pstate, List *l);
|
||||
static void transformTypeRef(ParseState *pstate, TypeName *tn);
|
||||
static List *getSetColTypes(ParseState *pstate, Node *node);
|
||||
static void transformForUpdate(Query *qry, List *forUpdate);
|
||||
static void transformConstraintAttrs(List *constraintList);
|
||||
@@ -309,18 +305,6 @@ transformStmt(ParseState *pstate, Node *parseTree,
|
||||
(SelectStmt *) parseTree);
|
||||
break;
|
||||
|
||||
/*
|
||||
* Convert use of %TYPE in statements where it is permitted.
|
||||
*/
|
||||
case T_ProcedureStmt:
|
||||
case T_CommentStmt:
|
||||
case T_RemoveFuncStmt:
|
||||
case T_DefineStmt:
|
||||
result = makeNode(Query);
|
||||
result->commandType = CMD_UTILITY;
|
||||
result->utilityStmt = transformTypeRefs(pstate, parseTree);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
/*
|
||||
@@ -792,17 +776,24 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
|
||||
|
||||
/* Check for SERIAL pseudo-types */
|
||||
is_serial = false;
|
||||
if (strcmp(column->typename->name, "serial") == 0 ||
|
||||
strcmp(column->typename->name, "serial4") == 0)
|
||||
if (length(column->typename->names) == 1)
|
||||
{
|
||||
is_serial = true;
|
||||
column->typename->name = pstrdup("int4");
|
||||
}
|
||||
else if (strcmp(column->typename->name, "bigserial") == 0 ||
|
||||
strcmp(column->typename->name, "serial8") == 0)
|
||||
{
|
||||
is_serial = true;
|
||||
column->typename->name = pstrdup("int8");
|
||||
char *typname = strVal(lfirst(column->typename->names));
|
||||
|
||||
if (strcmp(typname, "serial") == 0 ||
|
||||
strcmp(typname, "serial4") == 0)
|
||||
{
|
||||
is_serial = true;
|
||||
column->typename->names = NIL;
|
||||
column->typename->typeid = INT4OID;
|
||||
}
|
||||
else if (strcmp(typname, "bigserial") == 0 ||
|
||||
strcmp(typname, "serial8") == 0)
|
||||
{
|
||||
is_serial = true;
|
||||
column->typename->names = NIL;
|
||||
column->typename->typeid = INT8OID;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do necessary work on the column type declaration */
|
||||
@@ -2634,110 +2625,6 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
|
||||
return qry;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform uses of %TYPE in a statement.
|
||||
*/
|
||||
static Node *
|
||||
transformTypeRefs(ParseState *pstate, Node *stmt)
|
||||
{
|
||||
switch (nodeTag(stmt))
|
||||
{
|
||||
case T_ProcedureStmt:
|
||||
{
|
||||
ProcedureStmt *ps = (ProcedureStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, ps->argTypes);
|
||||
transformTypeRef(pstate, (TypeName *) ps->returnType);
|
||||
transformTypeRefsList(pstate, ps->withClause);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_CommentStmt:
|
||||
{
|
||||
CommentStmt *cs = (CommentStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, cs->objlist);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_RemoveFuncStmt:
|
||||
{
|
||||
RemoveFuncStmt *rs = (RemoveFuncStmt *) stmt;
|
||||
|
||||
transformTypeRefsList(pstate, rs->args);
|
||||
}
|
||||
break;
|
||||
|
||||
case T_DefineStmt:
|
||||
{
|
||||
DefineStmt *ds = (DefineStmt *) stmt;
|
||||
List *ele;
|
||||
|
||||
foreach(ele, ds->definition)
|
||||
{
|
||||
DefElem *de = (DefElem *) lfirst(ele);
|
||||
|
||||
if (de->arg != NULL
|
||||
&& IsA(de->arg, TypeName))
|
||||
transformTypeRef(pstate, (TypeName *) de->arg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "Unsupported type %d in transformTypeRefs",
|
||||
nodeTag(stmt));
|
||||
break;
|
||||
}
|
||||
|
||||
return stmt;
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform uses of %TYPE in a list.
|
||||
*/
|
||||
static void
|
||||
transformTypeRefsList(ParseState *pstate, List *l)
|
||||
{
|
||||
List *ele;
|
||||
|
||||
foreach(ele, l)
|
||||
{
|
||||
Node *elem = lfirst(ele);
|
||||
|
||||
if (elem && IsA(elem, TypeName))
|
||||
transformTypeRef(pstate, (TypeName *) elem);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform a TypeName to not use %TYPE.
|
||||
*/
|
||||
static void
|
||||
transformTypeRef(ParseState *pstate, TypeName *tn)
|
||||
{
|
||||
ColumnRef *cref;
|
||||
Node *n;
|
||||
Var *v;
|
||||
char *tyn;
|
||||
|
||||
if (tn->attrname == NULL)
|
||||
return;
|
||||
/* XXX this needs work; can't type name be qualified? */
|
||||
cref = makeNode(ColumnRef);
|
||||
cref->fields = makeList2(makeString(tn->name), makeString(tn->attrname));
|
||||
cref->indirection = NIL;
|
||||
n = transformExpr(pstate, (Node *) cref);
|
||||
if (!IsA(n, Var))
|
||||
elog(ERROR, "unsupported expression in %%TYPE");
|
||||
v = (Var *) n;
|
||||
tyn = typeidTypeName(v->vartype);
|
||||
elog(NOTICE, "%s.%s%%TYPE converted to %s", tn->name, tn->attrname, tyn);
|
||||
tn->name = tyn;
|
||||
tn->typmod = v->vartypmod;
|
||||
tn->attrname = NULL;
|
||||
}
|
||||
|
||||
/* exported so planner can check again after rewriting, query pullup, etc */
|
||||
void
|
||||
CheckSelectForUpdate(Query *qry)
|
||||
@@ -3059,15 +2946,7 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
|
||||
ColumnDef *col = lfirst(cols);
|
||||
|
||||
if (strcmp(col->colname, colname) == 0)
|
||||
{
|
||||
char *buff = TypeNameToInternalName(col->typename);
|
||||
|
||||
result = typenameTypeId(buff);
|
||||
if (!OidIsValid(result))
|
||||
elog(ERROR, "Unable to lookup type %s",
|
||||
col->typename->name);
|
||||
return result;
|
||||
}
|
||||
return typenameTypeId(col->typename);
|
||||
}
|
||||
/* Perhaps it's a system column name */
|
||||
sysatt = SystemAttributeByName(colname, cxt->hasoids);
|
||||
@@ -3092,7 +2971,6 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
|
||||
if (strcmp(name, colname) == 0)
|
||||
{
|
||||
result = rel->rd_att->attrs[count]->atttypid;
|
||||
|
||||
heap_close(rel, NoLock);
|
||||
return result;
|
||||
}
|
||||
@@ -3111,7 +2989,6 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
|
||||
if (HeapTupleIsValid(atttuple))
|
||||
{
|
||||
result = ((Form_pg_attribute) GETSTRUCT(atttuple))->atttypid;
|
||||
|
||||
ReleaseSysCache(atttuple);
|
||||
return result;
|
||||
}
|
||||
@@ -3233,7 +3110,7 @@ static void
|
||||
transformColumnType(ParseState *pstate, ColumnDef *column)
|
||||
{
|
||||
TypeName *typename = column->typename;
|
||||
Type ctype = typenameType(typename->name);
|
||||
Type ctype = typenameType(typename);
|
||||
|
||||
/*
|
||||
* Is this the name of a complex type? If so, implement it as a set.
|
||||
|
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.296 2002/03/22 02:56:33 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.297 2002/03/29 19:06:10 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "access/htup.h"
|
||||
#include "catalog/index.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/params.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "parser/gramparse.h"
|
||||
@@ -122,8 +123,6 @@ static void doNegateFloat(Value *v);
|
||||
ResTarget *target;
|
||||
PrivTarget *privtarget;
|
||||
|
||||
DefineStmt *dstmt;
|
||||
RuleStmt *rstmt;
|
||||
InsertStmt *istmt;
|
||||
}
|
||||
|
||||
@@ -175,7 +174,8 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%type <str> relation_name, copy_file_name, copy_delimiter, copy_null,
|
||||
database_name, access_method_clause, access_method, attr_name,
|
||||
class, index_name, name, func_name, file_name
|
||||
class, index_name, name, function_name, file_name,
|
||||
func_name, handler_name
|
||||
|
||||
%type <range> qualified_name, OptConstrFromTable
|
||||
|
||||
@@ -200,8 +200,8 @@ static void doNegateFloat(Value *v);
|
||||
opt_column_list, columnList, opt_name_list,
|
||||
sort_clause, sortby_list, index_params, index_list, name_list,
|
||||
from_clause, from_list, opt_array_bounds, qualified_name_list,
|
||||
expr_list, attrs, opt_attrs, target_list, update_target_list,
|
||||
insert_column_list,
|
||||
any_name, any_name_list, expr_list, dotted_name, attrs,
|
||||
target_list, update_target_list, insert_column_list,
|
||||
def_list, opt_indirection, group_clause, TriggerFuncArgs,
|
||||
select_limit, opt_select_limit
|
||||
|
||||
@@ -411,10 +411,10 @@ static void doNegateFloat(Value *v);
|
||||
/* Unary Operators */
|
||||
%left AT ZONE /* sets precedence for AT TIME ZONE */
|
||||
%right UMINUS
|
||||
%left '.'
|
||||
%left '[' ']'
|
||||
%left '(' ')'
|
||||
%left TYPECAST
|
||||
%left '.'
|
||||
%%
|
||||
|
||||
/*
|
||||
@@ -1812,7 +1812,7 @@ IntegerOnly: Iconst
|
||||
*****************************************************************************/
|
||||
|
||||
CreatePLangStmt: CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
|
||||
HANDLER func_name opt_lancompiler
|
||||
HANDLER handler_name opt_lancompiler
|
||||
{
|
||||
CreatePLangStmt *n = makeNode(CreatePLangStmt);
|
||||
n->plname = $5;
|
||||
@@ -1827,6 +1827,16 @@ opt_trusted: TRUSTED { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
/* This ought to be just func_name, but that causes reduce/reduce conflicts
|
||||
* (CREATE LANGUAGE is the only place where func_name isn't followed by '(').
|
||||
* Work around by using name and dotted_name separately.
|
||||
*/
|
||||
handler_name: name
|
||||
{ $$ = $1; }
|
||||
| dotted_name
|
||||
{ $$ = strVal(lfirst($1)); /* XXX changing soon */ }
|
||||
;
|
||||
|
||||
opt_lancompiler: LANCOMPILER Sconst { $$ = $2; }
|
||||
| /*EMPTY*/ { $$ = ""; }
|
||||
;
|
||||
@@ -1853,7 +1863,7 @@ opt_procedural: PROCEDURAL { $$ = TRUE; }
|
||||
|
||||
CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
|
||||
qualified_name TriggerForSpec EXECUTE PROCEDURE
|
||||
name '(' TriggerFuncArgs ')'
|
||||
func_name '(' TriggerFuncArgs ')'
|
||||
{
|
||||
CreateTrigStmt *n = makeNode(CreateTrigStmt);
|
||||
n->trigname = $3;
|
||||
@@ -1877,7 +1887,8 @@ CreateTrigStmt: CREATE TRIGGER name TriggerActionTime TriggerEvents ON
|
||||
| CREATE CONSTRAINT TRIGGER name AFTER TriggerEvents ON
|
||||
qualified_name OptConstrFromTable
|
||||
ConstraintAttributeSpec
|
||||
FOR EACH ROW EXECUTE PROCEDURE name '(' TriggerFuncArgs ')'
|
||||
FOR EACH ROW EXECUTE PROCEDURE
|
||||
func_name '(' TriggerFuncArgs ')'
|
||||
{
|
||||
CreateTrigStmt *n = makeNode(CreateTrigStmt);
|
||||
n->trigname = $4;
|
||||
@@ -2043,7 +2054,7 @@ DefineStmt: CREATE AGGREGATE func_name definition
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->defType = AGGREGATE;
|
||||
n->defname = $3;
|
||||
n->defnames = makeList1(makeString($3)); /* XXX */
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@@ -2051,15 +2062,15 @@ DefineStmt: CREATE AGGREGATE func_name definition
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->defType = OPERATOR;
|
||||
n->defname = $3;
|
||||
n->defnames = makeList1(makeString($3)); /* XXX */
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE TYPE_P name definition
|
||||
| CREATE TYPE_P any_name definition
|
||||
{
|
||||
DefineStmt *n = makeNode(DefineStmt);
|
||||
n->defType = TYPE_P;
|
||||
n->defname = $3;
|
||||
n->defnames = $3;
|
||||
n->definition = $4;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
@@ -2102,10 +2113,7 @@ def_arg: func_return { $$ = (Node *)$1; }
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/* DropStmt needs to use qualified_name_list as many of the objects
|
||||
* are relations or other schema objects (names can be schema-qualified) */
|
||||
|
||||
DropStmt: DROP drop_type qualified_name_list opt_drop_behavior
|
||||
DropStmt: DROP drop_type any_name_list opt_drop_behavior
|
||||
{
|
||||
DropStmt *n = makeNode(DropStmt);
|
||||
n->removeType = $2;
|
||||
@@ -2124,6 +2132,18 @@ drop_type: TABLE { $$ = DROP_TABLE; }
|
||||
| DOMAIN_P { $$ = DROP_DOMAIN; }
|
||||
;
|
||||
|
||||
any_name_list: any_name
|
||||
{ $$ = makeList1($1); }
|
||||
| any_name_list ',' any_name
|
||||
{ $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
any_name: ColId
|
||||
{ $$ = makeList1(makeString($1)); }
|
||||
| dotted_name
|
||||
{ $$ = $1; }
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* QUERY:
|
||||
@@ -2192,7 +2212,7 @@ CommentStmt: COMMENT ON comment_type name IS comment_text
|
||||
n->comment = $10;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON AGGREGATE name '(' aggr_argtype ')' IS comment_text
|
||||
| COMMENT ON AGGREGATE func_name '(' aggr_argtype ')' IS comment_text
|
||||
{
|
||||
CommentStmt *n = makeNode(CommentStmt);
|
||||
n->objtype = AGGREGATE;
|
||||
@@ -2203,18 +2223,6 @@ CommentStmt: COMMENT ON comment_type name IS comment_text
|
||||
n->comment = $9;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON AGGREGATE name aggr_argtype IS comment_text
|
||||
{
|
||||
/* Obsolete syntax, but must support for awhile */
|
||||
CommentStmt *n = makeNode(CommentStmt);
|
||||
n->objtype = AGGREGATE;
|
||||
n->objschema = NULL;
|
||||
n->objname = $4;
|
||||
n->objproperty = NULL;
|
||||
n->objlist = makeList1($5);
|
||||
n->comment = $7;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| COMMENT ON FUNCTION func_name func_args IS comment_text
|
||||
{
|
||||
CommentStmt *n = makeNode(CommentStmt);
|
||||
@@ -2691,9 +2699,9 @@ ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args
|
||||
{
|
||||
ProcedureStmt *n = makeNode(ProcedureStmt);
|
||||
n->replace = $2;
|
||||
n->funcname = $4;
|
||||
n->funcname = makeList1(makeString($4)); /* XXX */
|
||||
n->argTypes = $5;
|
||||
n->returnType = (Node *) $7;
|
||||
n->returnType = $7;
|
||||
n->withClause = $12;
|
||||
n->as = $9;
|
||||
n->language = $11;
|
||||
@@ -2765,19 +2773,19 @@ func_return: func_type
|
||||
;
|
||||
|
||||
/*
|
||||
* We would like to make the second production here be ColId '.' ColId etc,
|
||||
* We would like to make the second production here be ColId attrs etc,
|
||||
* but that causes reduce/reduce conflicts. type_name is next best choice.
|
||||
*/
|
||||
func_type: Typename
|
||||
{
|
||||
$$ = $1;
|
||||
}
|
||||
| type_name '.' ColId '%' TYPE_P
|
||||
| type_name attrs '%' TYPE_P
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
$$->names = lcons(makeString($1), $2);
|
||||
$$->pct_type = true;
|
||||
$$->typmod = -1;
|
||||
$$->attrname = $3;
|
||||
}
|
||||
;
|
||||
|
||||
@@ -2804,15 +2812,7 @@ RemoveAggrStmt: DROP AGGREGATE func_name '(' aggr_argtype ')'
|
||||
{
|
||||
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
|
||||
n->aggname = $3;
|
||||
n->aggtype = (Node *) $5;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| DROP AGGREGATE func_name aggr_argtype
|
||||
{
|
||||
/* Obsolete syntax, but must support for awhile */
|
||||
RemoveAggrStmt *n = makeNode(RemoveAggrStmt);
|
||||
n->aggname = $3;
|
||||
n->aggtype = (Node *) $4;
|
||||
n->aggtype = $5;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
@@ -3293,7 +3293,7 @@ DropdbStmt: DROP DATABASE database_name
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
CreateDomainStmt: CREATE DOMAIN_P name opt_as Typename ColQualList opt_collate
|
||||
CreateDomainStmt: CREATE DOMAIN_P any_name opt_as Typename ColQualList opt_collate
|
||||
{
|
||||
CreateDomainStmt *n = makeNode(CreateDomainStmt);
|
||||
n->domainname = $3;
|
||||
@@ -4237,6 +4237,14 @@ opt_array_bounds: opt_array_bounds '[' ']'
|
||||
{ $$ = NIL; }
|
||||
;
|
||||
|
||||
/*
|
||||
* XXX ideally, the production for a qualified typename should be ColId attrs
|
||||
* (there's no obvious reason why the first name should need to be restricted)
|
||||
* and should be an alternative of GenericType (so that it can be used to
|
||||
* specify a type for a literal in AExprConst). However doing either causes
|
||||
* reduce/reduce conflicts that I haven't been able to find a workaround
|
||||
* for. FIXME later.
|
||||
*/
|
||||
SimpleTypename: ConstTypename
|
||||
| ConstInterval opt_interval
|
||||
{
|
||||
@@ -4249,6 +4257,12 @@ SimpleTypename: ConstTypename
|
||||
$$ = $1;
|
||||
$$->typmod = ((($5 & 0x7FFF) << 16) | $3);
|
||||
}
|
||||
| type_name attrs
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->names = lcons(makeString($1), $2);
|
||||
$$->typmod = -1;
|
||||
}
|
||||
;
|
||||
|
||||
ConstTypename: GenericType
|
||||
@@ -4260,9 +4274,7 @@ ConstTypename: GenericType
|
||||
|
||||
GenericType: type_name
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType($1);
|
||||
$$->typmod = -1;
|
||||
$$ = makeTypeName(xlateSqlType($1));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -4273,32 +4285,25 @@ GenericType: type_name
|
||||
*/
|
||||
Numeric: FLOAT opt_float
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $2; /* already xlated */
|
||||
$$->typmod = -1;
|
||||
$$ = makeTypeName($2); /* already xlated */
|
||||
}
|
||||
| DOUBLE PRECISION
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType("float8");
|
||||
$$->typmod = -1;
|
||||
$$ = makeTypeName(xlateSqlType("float8"));
|
||||
}
|
||||
| DECIMAL opt_decimal
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType("decimal");
|
||||
$$ = makeTypeName(xlateSqlType("decimal"));
|
||||
$$->typmod = $2;
|
||||
}
|
||||
| DEC opt_decimal
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType("decimal");
|
||||
$$ = makeTypeName(xlateSqlType("decimal"));
|
||||
$$->typmod = $2;
|
||||
}
|
||||
| NUMERIC opt_numeric
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType("numeric");
|
||||
$$ = makeTypeName(xlateSqlType("numeric"));
|
||||
$$->typmod = $2;
|
||||
}
|
||||
;
|
||||
@@ -4379,8 +4384,7 @@ opt_decimal: '(' Iconst ',' Iconst ')'
|
||||
*/
|
||||
Bit: bit '(' Iconst ')'
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
$$ = makeTypeName($1);
|
||||
if ($3 < 1)
|
||||
elog(ERROR,"length for type '%s' must be at least 1",
|
||||
$1);
|
||||
@@ -4391,8 +4395,7 @@ Bit: bit '(' Iconst ')'
|
||||
}
|
||||
| bit
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
$$ = makeTypeName($1);
|
||||
/* bit defaults to bit(1), varbit to no limit */
|
||||
if (strcmp($1, "bit") == 0)
|
||||
$$->typmod = 1;
|
||||
@@ -4418,8 +4421,19 @@ bit: BIT opt_varying
|
||||
*/
|
||||
Character: character '(' Iconst ')' opt_charset
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
if (($5 != NULL) && (strcmp($5, "sql_text") != 0))
|
||||
{
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($1) + 1 + strlen($5) + 1);
|
||||
strcpy(type, $1);
|
||||
strcat(type, "_");
|
||||
strcat(type, $5);
|
||||
$1 = xlateSqlType(type);
|
||||
}
|
||||
|
||||
$$ = makeTypeName($1);
|
||||
|
||||
if ($3 < 1)
|
||||
elog(ERROR,"length for type '%s' must be at least 1",
|
||||
$1);
|
||||
@@ -4433,36 +4447,27 @@ Character: character '(' Iconst ')' opt_charset
|
||||
* truncate where necessary)
|
||||
*/
|
||||
$$->typmod = VARHDRSZ + $3;
|
||||
|
||||
if (($5 != NULL) && (strcmp($5, "sql_text") != 0)) {
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($$->name) + 1 + strlen($5) + 1);
|
||||
strcpy(type, $$->name);
|
||||
strcat(type, "_");
|
||||
strcat(type, $5);
|
||||
$$->name = xlateSqlType(type);
|
||||
};
|
||||
}
|
||||
| character opt_charset
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = $1;
|
||||
if (($2 != NULL) && (strcmp($2, "sql_text") != 0))
|
||||
{
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($1) + 1 + strlen($2) + 1);
|
||||
strcpy(type, $1);
|
||||
strcat(type, "_");
|
||||
strcat(type, $2);
|
||||
$1 = xlateSqlType(type);
|
||||
}
|
||||
|
||||
$$ = makeTypeName($1);
|
||||
|
||||
/* char defaults to char(1), varchar to no limit */
|
||||
if (strcmp($1, "bpchar") == 0)
|
||||
$$->typmod = VARHDRSZ + 1;
|
||||
else
|
||||
$$->typmod = -1;
|
||||
|
||||
if (($2 != NULL) && (strcmp($2, "sql_text") != 0)) {
|
||||
char *type;
|
||||
|
||||
type = palloc(strlen($$->name) + 1 + strlen($2) + 1);
|
||||
strcpy(type, $$->name);
|
||||
strcat(type, "_");
|
||||
strcat(type, $2);
|
||||
$$->name = xlateSqlType(type);
|
||||
};
|
||||
}
|
||||
;
|
||||
|
||||
@@ -4488,11 +4493,10 @@ opt_collate: COLLATE ColId { $$ = $2; }
|
||||
|
||||
ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($5)
|
||||
$$->name = xlateSqlType("timestamptz");
|
||||
$$ = makeTypeName(xlateSqlType("timestamptz"));
|
||||
else
|
||||
$$->name = xlateSqlType("timestamp");
|
||||
$$ = makeTypeName(xlateSqlType("timestamp"));
|
||||
/* XXX the timezone field seems to be unused
|
||||
* - thomas 2001-09-06
|
||||
*/
|
||||
@@ -4504,11 +4508,10 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
}
|
||||
| TIMESTAMP opt_timezone_x
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($2)
|
||||
$$->name = xlateSqlType("timestamptz");
|
||||
$$ = makeTypeName(xlateSqlType("timestamptz"));
|
||||
else
|
||||
$$->name = xlateSqlType("timestamp");
|
||||
$$ = makeTypeName(xlateSqlType("timestamp"));
|
||||
/* XXX the timezone field seems to be unused
|
||||
* - thomas 2001-09-06
|
||||
*/
|
||||
@@ -4524,11 +4527,10 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
}
|
||||
| TIME '(' Iconst ')' opt_timezone
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($5)
|
||||
$$->name = xlateSqlType("timetz");
|
||||
$$ = makeTypeName(xlateSqlType("timetz"));
|
||||
else
|
||||
$$->name = xlateSqlType("time");
|
||||
$$ = makeTypeName(xlateSqlType("time"));
|
||||
if (($3 < 0) || ($3 > 13))
|
||||
elog(ERROR,"TIME(%d)%s precision must be between %d and %d",
|
||||
$3, ($5 ? " WITH TIME ZONE": ""), 0, 13);
|
||||
@@ -4536,11 +4538,10 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
}
|
||||
| TIME opt_timezone
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
if ($2)
|
||||
$$->name = xlateSqlType("timetz");
|
||||
$$ = makeTypeName(xlateSqlType("timetz"));
|
||||
else
|
||||
$$->name = xlateSqlType("time");
|
||||
$$ = makeTypeName(xlateSqlType("time"));
|
||||
/* SQL99 specified a default precision of zero.
|
||||
* See comments for timestamp above on why we will
|
||||
* leave this unspecified for now. - thomas 2001-12-07
|
||||
@@ -4551,9 +4552,7 @@ ConstDatetime: TIMESTAMP '(' Iconst ')' opt_timezone_x
|
||||
|
||||
ConstInterval: INTERVAL
|
||||
{
|
||||
$$ = makeNode(TypeName);
|
||||
$$->name = xlateSqlType("interval");
|
||||
$$->typmod = -1;
|
||||
$$ = makeTypeName(xlateSqlType("interval"));
|
||||
}
|
||||
;
|
||||
|
||||
@@ -5161,7 +5160,7 @@ c_expr: columnref
|
||||
| CURRENT_DATE opt_empty_parentheses
|
||||
{
|
||||
/*
|
||||
* Translate as "date('now'::text)".
|
||||
* Translate as "'now'::text::date".
|
||||
*
|
||||
* We cannot use "'now'::date" because coerce_type() will
|
||||
* immediately reduce that to a constant representing
|
||||
@@ -5174,43 +5173,30 @@ c_expr: columnref
|
||||
* of type-input conversion functions...
|
||||
*/
|
||||
A_Const *s = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
TypeName *d = makeNode(TypeName);
|
||||
TypeName *d;
|
||||
|
||||
s->val.type = T_String;
|
||||
s->val.val.str = "now";
|
||||
s->typename = t;
|
||||
s->typename = makeTypeName(xlateSqlType("text"));
|
||||
|
||||
t->name = xlateSqlType("text");
|
||||
t->setof = FALSE;
|
||||
t->typmod = -1;
|
||||
|
||||
d->name = xlateSqlType("date");
|
||||
d->setof = FALSE;
|
||||
d->typmod = -1;
|
||||
d = makeTypeName(xlateSqlType("date"));
|
||||
|
||||
$$ = (Node *)makeTypeCast((Node *)s, d);
|
||||
}
|
||||
| CURRENT_TIME opt_empty_parentheses
|
||||
{
|
||||
/*
|
||||
* Translate as "timetz('now'::text)".
|
||||
* Translate as "'now'::text::timetz".
|
||||
* See comments for CURRENT_DATE.
|
||||
*/
|
||||
A_Const *s = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
TypeName *d = makeNode(TypeName);
|
||||
TypeName *d;
|
||||
|
||||
s->val.type = T_String;
|
||||
s->val.val.str = "now";
|
||||
s->typename = t;
|
||||
s->typename = makeTypeName(xlateSqlType("text"));
|
||||
|
||||
t->name = xlateSqlType("text");
|
||||
t->setof = FALSE;
|
||||
t->typmod = -1;
|
||||
|
||||
d->name = xlateSqlType("timetz");
|
||||
d->setof = FALSE;
|
||||
d = makeTypeName(xlateSqlType("timetz"));
|
||||
/* SQL99 mandates a default precision of zero for TIME
|
||||
* fields in schemas. However, for CURRENT_TIME
|
||||
* let's preserve the microsecond precision we
|
||||
@@ -5223,23 +5209,17 @@ c_expr: columnref
|
||||
| CURRENT_TIME '(' Iconst ')'
|
||||
{
|
||||
/*
|
||||
* Translate as "timetz('now'::text)".
|
||||
* Translate as "'now'::text::timetz(n)".
|
||||
* See comments for CURRENT_DATE.
|
||||
*/
|
||||
A_Const *s = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
TypeName *d = makeNode(TypeName);
|
||||
TypeName *d;
|
||||
|
||||
s->val.type = T_String;
|
||||
s->val.val.str = "now";
|
||||
s->typename = t;
|
||||
s->typename = makeTypeName(xlateSqlType("text"));
|
||||
|
||||
t->name = xlateSqlType("text");
|
||||
t->setof = FALSE;
|
||||
t->typmod = -1;
|
||||
|
||||
d->name = xlateSqlType("timetz");
|
||||
d->setof = FALSE;
|
||||
d = makeTypeName(xlateSqlType("timetz"));
|
||||
if (($3 < 0) || ($3 > 13))
|
||||
elog(ERROR,"CURRENT_TIME(%d) precision must be between %d and %d",
|
||||
$3, 0, 13);
|
||||
@@ -5250,23 +5230,17 @@ c_expr: columnref
|
||||
| CURRENT_TIMESTAMP opt_empty_parentheses
|
||||
{
|
||||
/*
|
||||
* Translate as "timestamptz('now'::text)".
|
||||
* Translate as "'now'::text::timestamptz".
|
||||
* See comments for CURRENT_DATE.
|
||||
*/
|
||||
A_Const *s = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
TypeName *d = makeNode(TypeName);
|
||||
TypeName *d;
|
||||
|
||||
s->val.type = T_String;
|
||||
s->val.val.str = "now";
|
||||
s->typename = t;
|
||||
s->typename = makeTypeName(xlateSqlType("text"));
|
||||
|
||||
t->name = xlateSqlType("text");
|
||||
t->setof = FALSE;
|
||||
t->typmod = -1;
|
||||
|
||||
d->name = xlateSqlType("timestamptz");
|
||||
d->setof = FALSE;
|
||||
d = makeTypeName(xlateSqlType("timestamptz"));
|
||||
/* SQL99 mandates a default precision of 6 for timestamp.
|
||||
* Also, that is about as precise as we will get since
|
||||
* we are using a microsecond time interface.
|
||||
@@ -5279,23 +5253,17 @@ c_expr: columnref
|
||||
| CURRENT_TIMESTAMP '(' Iconst ')'
|
||||
{
|
||||
/*
|
||||
* Translate as "timestamptz('now'::text)".
|
||||
* Translate as "'now'::text::timestamptz(n)".
|
||||
* See comments for CURRENT_DATE.
|
||||
*/
|
||||
A_Const *s = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
TypeName *d = makeNode(TypeName);
|
||||
TypeName *d;
|
||||
|
||||
s->val.type = T_String;
|
||||
s->val.val.str = "now";
|
||||
s->typename = t;
|
||||
s->typename = makeTypeName(xlateSqlType("text"));
|
||||
|
||||
t->name = xlateSqlType("text");
|
||||
t->setof = FALSE;
|
||||
t->typmod = -1;
|
||||
|
||||
d->name = xlateSqlType("timestamptz");
|
||||
d->setof = FALSE;
|
||||
d = makeTypeName(xlateSqlType("timestamptz"));
|
||||
if (($3 < 0) || ($3 > 13))
|
||||
elog(ERROR,"CURRENT_TIMESTAMP(%d) precision must be between %d and %d",
|
||||
$3, 0, 13);
|
||||
@@ -5645,24 +5613,24 @@ columnref: relation_name opt_indirection
|
||||
$$->fields = makeList1(makeString($1));
|
||||
$$->indirection = $2;
|
||||
}
|
||||
| relation_name attrs opt_indirection
|
||||
| dotted_name opt_indirection
|
||||
{
|
||||
$$ = makeNode(ColumnRef);
|
||||
$$->fields = lcons(makeString($1), $2);
|
||||
$$->indirection = $3;
|
||||
$$->fields = $1;
|
||||
$$->indirection = $2;
|
||||
}
|
||||
;
|
||||
|
||||
attrs: opt_attrs '.' attr_name
|
||||
{ $$ = lappend($1, makeString($3)); }
|
||||
| opt_attrs '.' '*'
|
||||
{ $$ = lappend($1, makeString("*")); }
|
||||
dotted_name: relation_name attrs
|
||||
{ $$ = lcons(makeString($1), $2); }
|
||||
;
|
||||
|
||||
opt_attrs: /*EMPTY*/
|
||||
{ $$ = NIL; }
|
||||
| opt_attrs '.' attr_name
|
||||
{ $$ = lappend($1, makeString($3)); }
|
||||
attrs: '.' attr_name
|
||||
{ $$ = makeList1(makeString($2)); }
|
||||
| '.' '*'
|
||||
{ $$ = makeList1(makeString("*")); }
|
||||
| '.' attr_name attrs
|
||||
{ $$ = lcons(makeString($2), $3); }
|
||||
;
|
||||
|
||||
opt_empty_parentheses: '(' ')' { $$ = TRUE; }
|
||||
@@ -5742,11 +5710,11 @@ relation_name: SpecialRuleRelation
|
||||
$$ = $1;
|
||||
}
|
||||
;
|
||||
|
||||
|
||||
qualified_name_list: qualified_name
|
||||
{ $$ = makeList1($1); }
|
||||
{ $$ = makeList1($1); }
|
||||
| qualified_name_list ',' qualified_name
|
||||
{ $$ = lappend($1, $3); }
|
||||
{ $$ = lappend($1, $3); }
|
||||
;
|
||||
|
||||
qualified_name: ColId
|
||||
@@ -5787,6 +5755,21 @@ class: ColId { $$ = $1; };
|
||||
index_name: ColId { $$ = $1; };
|
||||
file_name: Sconst { $$ = $1; };
|
||||
|
||||
/* func_name will soon return a List ... but not yet */
|
||||
/*
|
||||
func_name: function_name
|
||||
{ $$ = makeList1(makeString($1)); }
|
||||
| dotted_name
|
||||
{ $$ = $1; }
|
||||
;
|
||||
*/
|
||||
func_name: function_name
|
||||
{ $$ = $1; }
|
||||
| dotted_name
|
||||
{ $$ = strVal(lfirst($1)); }
|
||||
;
|
||||
|
||||
|
||||
/* Constants
|
||||
* Include TRUE/FALSE for SQL3 support. - thomas 1997-10-24
|
||||
*/
|
||||
@@ -5867,9 +5850,7 @@ AexprConst: Iconst
|
||||
A_Const *n = makeNode(A_Const);
|
||||
n->val.type = T_String;
|
||||
n->val.val.str = "t";
|
||||
n->typename = makeNode(TypeName);
|
||||
n->typename->name = xlateSqlType("bool");
|
||||
n->typename->typmod = -1;
|
||||
n->typename = makeTypeName(xlateSqlType("bool"));
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| FALSE_P
|
||||
@@ -5877,9 +5858,7 @@ AexprConst: Iconst
|
||||
A_Const *n = makeNode(A_Const);
|
||||
n->val.type = T_String;
|
||||
n->val.val.str = "f";
|
||||
n->typename = makeNode(TypeName);
|
||||
n->typename->name = xlateSqlType("bool");
|
||||
n->typename->typmod = -1;
|
||||
n->typename = makeTypeName(xlateSqlType("bool"));
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| NULL_P
|
||||
@@ -5920,7 +5899,7 @@ type_name: IDENT { $$ = $1; }
|
||||
|
||||
/* Function identifier --- names that can be function names.
|
||||
*/
|
||||
func_name: IDENT { $$ = xlateSqlFunc($1); }
|
||||
function_name: IDENT { $$ = xlateSqlFunc($1); }
|
||||
| unreserved_keyword { $$ = xlateSqlFunc($1); }
|
||||
| func_name_keyword { $$ = xlateSqlFunc($1); }
|
||||
;
|
||||
@@ -6304,6 +6283,7 @@ static Node *
|
||||
makeStringConst(char *str, TypeName *typename)
|
||||
{
|
||||
A_Const *n = makeNode(A_Const);
|
||||
|
||||
n->val.type = T_String;
|
||||
n->val.val.str = str;
|
||||
n->typename = typename;
|
||||
@@ -6315,12 +6295,10 @@ static Node *
|
||||
makeFloatConst(char *str)
|
||||
{
|
||||
A_Const *n = makeNode(A_Const);
|
||||
TypeName *t = makeNode(TypeName);
|
||||
|
||||
n->val.type = T_Float;
|
||||
n->val.val.str = str;
|
||||
t->name = xlateSqlType("float");
|
||||
t->typmod = -1;
|
||||
n->typename = t;
|
||||
n->typename = makeTypeName(xlateSqlType("float"));
|
||||
|
||||
return (Node *)n;
|
||||
}
|
||||
@@ -6435,7 +6413,6 @@ makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg)
|
||||
return (Node *) n;
|
||||
}
|
||||
|
||||
|
||||
/* xlateSqlFunc()
|
||||
* Convert alternate function names to internal Postgres functions.
|
||||
*
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.111 2002/03/21 16:01:03 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.112 2002/03/29 19:06:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -1103,7 +1103,7 @@ parser_typecast_constant(Value *expr, TypeName *typename)
|
||||
bool string_palloced = false;
|
||||
bool isNull = false;
|
||||
|
||||
tp = typenameType(TypeNameToInternalName(typename));
|
||||
tp = typenameType(typename);
|
||||
|
||||
switch (nodeTag(expr))
|
||||
{
|
||||
@@ -1161,7 +1161,7 @@ parser_typecast_expression(ParseState *pstate,
|
||||
Oid inputType = exprType(expr);
|
||||
Oid targetType;
|
||||
|
||||
targetType = typenameTypeId(TypeNameToInternalName(typename));
|
||||
targetType = typenameTypeId(typename);
|
||||
|
||||
if (inputType == InvalidOid)
|
||||
return expr; /* do nothing if NULL input */
|
||||
@@ -1185,27 +1185,3 @@ parser_typecast_expression(ParseState *pstate,
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a TypeName node as returned by the grammar, generate the internal
|
||||
* name of the corresponding type. Note this does NOT check if the type
|
||||
* exists or not.
|
||||
*/
|
||||
char *
|
||||
TypeNameToInternalName(TypeName *typename)
|
||||
{
|
||||
Assert(typename->attrname == NULL);
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
/*
|
||||
* By convention, the name of an array type is the name of its
|
||||
* element type with "_" prepended.
|
||||
*/
|
||||
char *arrayname = palloc(strlen(typename->name) + 2);
|
||||
|
||||
sprintf(arrayname, "_%s", typename->name);
|
||||
return arrayname;
|
||||
}
|
||||
else
|
||||
return typename->name;
|
||||
}
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.120 2002/03/22 02:56:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.121 2002/03/29 19:06:11 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "catalog/indexing.h"
|
||||
#include "catalog/pg_aggregate.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "parser/parse_agg.h"
|
||||
@@ -969,9 +970,14 @@ func_get_detail(char *funcname,
|
||||
{
|
||||
Oid targetType;
|
||||
|
||||
targetType = GetSysCacheOid(TYPENAME,
|
||||
/* XXX WRONG: need to search searchpath for name; but little
|
||||
* point in fixing before we revise this code for qualified
|
||||
* funcnames too.
|
||||
*/
|
||||
targetType = GetSysCacheOid(TYPENAMENSP,
|
||||
PointerGetDatum(funcname),
|
||||
0, 0, 0);
|
||||
ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
|
||||
0, 0);
|
||||
if (OidIsValid(targetType) &&
|
||||
!ISCOMPLEX(targetType))
|
||||
{
|
||||
@@ -1222,13 +1228,11 @@ find_inheritors(Oid relid, Oid **supervec)
|
||||
{
|
||||
/* return the type id, rather than the relation id */
|
||||
Relation rd;
|
||||
Oid trelid;
|
||||
|
||||
relid = lfirsti(elt);
|
||||
rd = heap_open(relid, NoLock);
|
||||
trelid = typenameTypeId(RelationGetRelationName(rd));
|
||||
*relidvec++ = rd->rd_rel->reltype;
|
||||
heap_close(rd, NoLock);
|
||||
*relidvec++ = trelid;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1473,7 +1477,9 @@ ParseComplexProjection(ParseState *pstate,
|
||||
* argument types
|
||||
*/
|
||||
void
|
||||
func_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg)
|
||||
func_error(const char *caller, const char *funcname,
|
||||
int nargs, const Oid *argtypes,
|
||||
const char *msg)
|
||||
{
|
||||
char p[(NAMEDATALEN + 2) * FUNC_MAX_ARGS],
|
||||
*ptr;
|
||||
@@ -1488,9 +1494,9 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes, char *msg)
|
||||
*ptr++ = ',';
|
||||
*ptr++ = ' ';
|
||||
}
|
||||
if (argtypes[i] != 0)
|
||||
if (OidIsValid(argtypes[i]))
|
||||
{
|
||||
strcpy(ptr, typeidTypeName(argtypes[i]));
|
||||
strncpy(ptr, typeidTypeName(argtypes[i]), NAMEDATALEN);
|
||||
*(ptr + NAMEDATALEN) = '\0';
|
||||
}
|
||||
else
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.79 2002/03/22 02:56:34 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.80 2002/03/29 19:06:12 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -525,8 +525,15 @@ FigureColnameInternal(Node *node, char **name)
|
||||
case T_A_Const:
|
||||
if (((A_Const *) node)->typename != NULL)
|
||||
{
|
||||
*name = ((A_Const *) node)->typename->name;
|
||||
return 1;
|
||||
List *names = ((A_Const *) node)->typename->names;
|
||||
|
||||
if (names != NIL)
|
||||
{
|
||||
while (lnext(names) != NIL)
|
||||
names = lnext(names);
|
||||
*name = strVal(lfirst(names));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_TypeCast:
|
||||
@@ -536,8 +543,15 @@ FigureColnameInternal(Node *node, char **name)
|
||||
{
|
||||
if (((TypeCast *) node)->typename != NULL)
|
||||
{
|
||||
*name = ((TypeCast *) node)->typename->name;
|
||||
return 1;
|
||||
List *names = ((TypeCast *) node)->typename->names;
|
||||
|
||||
if (names != NIL)
|
||||
{
|
||||
while (lnext(names) != NIL)
|
||||
names = lnext(names);
|
||||
*name = strVal(lfirst(names));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@@ -8,20 +8,250 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.37 2001/10/25 05:49:40 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.38 2002/03/29 19:06:12 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "miscadmin.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "parser/parser.h"
|
||||
#include "parser/parse_expr.h"
|
||||
#include "parser/parse_type.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
/*
|
||||
* LookupTypeName
|
||||
* Given a TypeName object, get the OID of the referenced type.
|
||||
* Returns InvalidOid if no such type can be found.
|
||||
*
|
||||
* NB: even if the returned OID is not InvalidOid, the type might be
|
||||
* just a shell. Caller should check typisdefined before using the type.
|
||||
*/
|
||||
Oid
|
||||
LookupTypeName(const TypeName *typename)
|
||||
{
|
||||
Oid restype;
|
||||
|
||||
/* Easy if it's an internally generated TypeName */
|
||||
if (typename->names == NIL)
|
||||
return typename->typeid;
|
||||
|
||||
if (typename->pct_type)
|
||||
{
|
||||
/* Handle %TYPE reference to type of an existing field */
|
||||
RangeVar *rel = makeRangeVar(NULL, NULL);
|
||||
char *field = NULL;
|
||||
Oid relid;
|
||||
AttrNumber attnum;
|
||||
|
||||
/* deconstruct the name list */
|
||||
switch (length(typename->names))
|
||||
{
|
||||
case 1:
|
||||
elog(ERROR, "Improper %%TYPE reference (too few dotted names)");
|
||||
break;
|
||||
case 2:
|
||||
rel->relname = strVal(lfirst(typename->names));
|
||||
field = strVal(lsecond(typename->names));
|
||||
break;
|
||||
case 3:
|
||||
rel->schemaname = strVal(lfirst(typename->names));
|
||||
rel->relname = strVal(lsecond(typename->names));
|
||||
field = strVal(lfirst(lnext(lnext(typename->names))));
|
||||
break;
|
||||
case 4:
|
||||
rel->catalogname = strVal(lfirst(typename->names));
|
||||
rel->schemaname = strVal(lsecond(typename->names));
|
||||
rel->relname = strVal(lfirst(lnext(lnext(typename->names))));
|
||||
field = strVal(lfirst(lnext(lnext(lnext(typename->names)))));
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "Improper %%TYPE reference (too many dotted names)");
|
||||
break;
|
||||
}
|
||||
|
||||
/* look up the field */
|
||||
relid = RangeVarGetRelid(rel, false);
|
||||
attnum = get_attnum(relid, field);
|
||||
if (attnum == InvalidAttrNumber)
|
||||
elog(ERROR, "'%s' is not an attribute of class '%s'",
|
||||
field, rel->relname);
|
||||
restype = get_atttype(relid, attnum);
|
||||
|
||||
/* this construct should never have an array indicator */
|
||||
Assert(typename->arrayBounds == NIL);
|
||||
|
||||
/* emit nuisance warning */
|
||||
elog(NOTICE, "%s converted to %s",
|
||||
TypeNameToString(typename), typeidTypeName(restype));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Normal reference to a type name */
|
||||
char *catalogname;
|
||||
char *schemaname = NULL;
|
||||
char *typname = NULL;
|
||||
|
||||
/* deconstruct the name list */
|
||||
switch (length(typename->names))
|
||||
{
|
||||
case 1:
|
||||
typname = strVal(lfirst(typename->names));
|
||||
break;
|
||||
case 2:
|
||||
schemaname = strVal(lfirst(typename->names));
|
||||
typname = strVal(lsecond(typename->names));
|
||||
break;
|
||||
case 3:
|
||||
catalogname = strVal(lfirst(typename->names));
|
||||
schemaname = strVal(lsecond(typename->names));
|
||||
typname = strVal(lfirst(lnext(lnext(typename->names))));
|
||||
/*
|
||||
* We check the catalog name and then ignore it.
|
||||
*/
|
||||
if (strcmp(catalogname, DatabaseName) != 0)
|
||||
elog(ERROR, "Cross-database references are not implemented");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "Improper type name (too many dotted names)");
|
||||
break;
|
||||
}
|
||||
|
||||
/* If an array reference, look up the array type instead */
|
||||
if (typename->arrayBounds != NIL)
|
||||
typname = makeArrayTypeName(typname);
|
||||
|
||||
if (schemaname)
|
||||
{
|
||||
Oid namespaceId;
|
||||
|
||||
namespaceId = GetSysCacheOid(NAMESPACENAME,
|
||||
CStringGetDatum(schemaname),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(namespaceId))
|
||||
elog(ERROR, "Namespace \"%s\" does not exist",
|
||||
schemaname);
|
||||
restype = GetSysCacheOid(TYPENAMENSP,
|
||||
PointerGetDatum(typname),
|
||||
ObjectIdGetDatum(namespaceId),
|
||||
0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* XXX wrong, should use namespace search */
|
||||
restype = GetSysCacheOid(TYPENAMENSP,
|
||||
PointerGetDatum(typname),
|
||||
ObjectIdGetDatum(PG_CATALOG_NAMESPACE),
|
||||
0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return restype;
|
||||
}
|
||||
|
||||
/*
|
||||
* TypeNameToString
|
||||
* Produce a string representing the name of a TypeName.
|
||||
*
|
||||
* NB: this must work on TypeNames that do not describe any actual type;
|
||||
* it is mostly used for reporting lookup errors.
|
||||
*/
|
||||
char *
|
||||
TypeNameToString(const TypeName *typename)
|
||||
{
|
||||
StringInfoData string;
|
||||
|
||||
initStringInfo(&string);
|
||||
|
||||
if (typename->names != NIL)
|
||||
{
|
||||
/* Emit possibly-qualified name as-is */
|
||||
List *l;
|
||||
|
||||
foreach(l, typename->names)
|
||||
{
|
||||
if (l != typename->names)
|
||||
appendStringInfoChar(&string, '.');
|
||||
appendStringInfo(&string, "%s", strVal(lfirst(l)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look up internally-specified type */
|
||||
appendStringInfo(&string, "%s", typeidTypeName(typename->typeid));
|
||||
}
|
||||
|
||||
/*
|
||||
* Add decoration as needed, but only for fields considered by
|
||||
* LookupTypeName
|
||||
*/
|
||||
if (typename->pct_type)
|
||||
appendStringInfo(&string, "%%TYPE");
|
||||
|
||||
if (typename->arrayBounds != NIL)
|
||||
appendStringInfo(&string, "[]");
|
||||
|
||||
return string.data;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameTypeId - given a TypeName, return the type's OID
|
||||
*
|
||||
* This is equivalent to LookupTypeName, except that this will report
|
||||
* a suitable error message if the type cannot be found or is not defined.
|
||||
*/
|
||||
Oid
|
||||
typenameTypeId(const TypeName *typename)
|
||||
{
|
||||
Oid typoid;
|
||||
|
||||
typoid = LookupTypeName(typename);
|
||||
if (!OidIsValid(typoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
if (!get_typisdefined(typoid))
|
||||
elog(ERROR, "Type \"%s\" is only a shell",
|
||||
TypeNameToString(typename));
|
||||
return typoid;
|
||||
}
|
||||
|
||||
/*
|
||||
* typenameType - given a TypeName, return a Type structure
|
||||
*
|
||||
* This is equivalent to typenameTypeId + syscache fetch of Type tuple.
|
||||
* NB: caller must ReleaseSysCache the type tuple when done with it.
|
||||
*/
|
||||
Type
|
||||
typenameType(const TypeName *typename)
|
||||
{
|
||||
Oid typoid;
|
||||
HeapTuple tup;
|
||||
|
||||
typoid = LookupTypeName(typename);
|
||||
if (!OidIsValid(typoid))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
tup = SearchSysCache(TYPEOID,
|
||||
ObjectIdGetDatum(typoid),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "Type \"%s\" does not exist",
|
||||
TypeNameToString(typename));
|
||||
if (! ((Form_pg_type) GETSTRUCT(tup))->typisdefined)
|
||||
elog(ERROR, "Type \"%s\" is only a shell",
|
||||
TypeNameToString(typename));
|
||||
return (Type) tup;
|
||||
}
|
||||
|
||||
/* check to see if a type id is valid,
|
||||
* returns true if it is. By using this call before calling
|
||||
* typeidType or typeidTypeName, more meaningful error messages
|
||||
@@ -51,24 +281,6 @@ typeidType(Oid id)
|
||||
return (Type) tup;
|
||||
}
|
||||
|
||||
/* return a Type structure, given type name */
|
||||
/* NB: caller must ReleaseSysCache the type tuple when done with it */
|
||||
Type
|
||||
typenameType(char *s)
|
||||
{
|
||||
HeapTuple tup;
|
||||
|
||||
if (s == NULL)
|
||||
elog(ERROR, "typenameType: Null typename");
|
||||
|
||||
tup = SearchSysCache(TYPENAME,
|
||||
PointerGetDatum(s),
|
||||
0, 0, 0);
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "Unable to locate type name '%s' in catalog", s);
|
||||
return (Type) tup;
|
||||
}
|
||||
|
||||
/* given type (as type struct), return the type OID */
|
||||
Oid
|
||||
typeTypeId(Type tp)
|
||||
@@ -207,6 +419,7 @@ typeidOutfunc(Oid type_id)
|
||||
#endif
|
||||
|
||||
/* return a type name, given a typeid */
|
||||
/* nb: type name is NOT unique; use this only for error messages */
|
||||
char *
|
||||
typeidTypeName(Oid id)
|
||||
{
|
||||
@@ -251,18 +464,6 @@ typeidTypeRelid(Oid type_id)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* given a type name, return the type's typeid */
|
||||
Oid
|
||||
typenameTypeId(char *s)
|
||||
{
|
||||
Type typ = typenameType(s);
|
||||
Oid result;
|
||||
|
||||
result = typ->t_data->t_oid;
|
||||
ReleaseSysCache(typ);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a string that is supposed to be a SQL-compatible type declaration,
|
||||
* such as "int4" or "integer" or "character varying(32)", parse
|
||||
@@ -327,7 +528,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
|
||||
!IsA(typename, TypeName))
|
||||
elog(ERROR, "Invalid type name '%s'", str);
|
||||
|
||||
*type_id = typenameTypeId(TypeNameToInternalName(typename));
|
||||
*type_id = typenameTypeId(typename);
|
||||
*typmod = typename->typmod;
|
||||
|
||||
pfree(buf);
|
||||
|
Reference in New Issue
Block a user