mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-09-07 13:09:24 +02:00
with OPAQUE. CREATE LANGUAGE, CREATE TRIGGER, and CREATE TYPE will all accept references to functions declared with OPAQUE --- but they will issue a NOTICE, and will modify the function entries in pg_proc to have the preferred type-safe argument or result types instead of OPAQUE. Per recent pghackers discussions.
246 lines
5.9 KiB
C
246 lines
5.9 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* define.c
|
|
* Support routines for various kinds of object creation.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.81 2002/09/21 18:39:25 tgl Exp $
|
|
*
|
|
* DESCRIPTION
|
|
* The "DefineFoo" routines take the parse tree and pick out the
|
|
* appropriate arguments/flags, passing the results to the
|
|
* corresponding "FooDefine" routines (in src/catalog) that do
|
|
* the actual catalog-munging. These routines also verify permission
|
|
* of the user to execute the command.
|
|
*
|
|
* NOTES
|
|
* These things must be defined and committed in the following order:
|
|
* "create function":
|
|
* input/output, recv/send procedures
|
|
* "create type":
|
|
* type
|
|
* "create operator":
|
|
* operators
|
|
*
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#include "catalog/namespace.h"
|
|
#include "commands/defrem.h"
|
|
#include "parser/parse_type.h"
|
|
#include "utils/int8.h"
|
|
|
|
|
|
/*
|
|
* Translate the input language name to lower case.
|
|
*
|
|
* Output buffer must be NAMEDATALEN long.
|
|
*/
|
|
void
|
|
case_translate_language_name(const char *input, char *output)
|
|
{
|
|
int i;
|
|
|
|
MemSet(output, 0, NAMEDATALEN); /* ensure result Name is zero-filled */
|
|
|
|
for (i = 0; i < NAMEDATALEN - 1 && input[i]; ++i)
|
|
output[i] = tolower((unsigned char) input[i]);
|
|
}
|
|
|
|
|
|
/*
|
|
* Extract a string value (otherwise uninterpreted) from a DefElem.
|
|
*/
|
|
char *
|
|
defGetString(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a parameter",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_Integer:
|
|
{
|
|
char *str = palloc(32);
|
|
|
|
snprintf(str, 32, "%ld", (long) intVal(def->arg));
|
|
return str;
|
|
}
|
|
case T_Float:
|
|
|
|
/*
|
|
* T_Float values are kept in string form, so this type cheat
|
|
* works (and doesn't risk losing precision)
|
|
*/
|
|
return strVal(def->arg);
|
|
case T_String:
|
|
return strVal(def->arg);
|
|
case T_TypeName:
|
|
return TypeNameToString((TypeName *) def->arg);
|
|
case T_List:
|
|
return NameListToString((List *) def->arg);
|
|
default:
|
|
elog(ERROR, "Define: cannot interpret argument of \"%s\"",
|
|
def->defname);
|
|
}
|
|
return NULL; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a numeric value (actually double) from a DefElem.
|
|
*/
|
|
double
|
|
defGetNumeric(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a numeric value",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_Integer:
|
|
return (double) intVal(def->arg);
|
|
case T_Float:
|
|
return floatVal(def->arg);
|
|
default:
|
|
elog(ERROR, "Define: \"%s\" requires a numeric value",
|
|
def->defname);
|
|
}
|
|
return 0; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract an int64 value from a DefElem.
|
|
*/
|
|
int64
|
|
defGetInt64(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a numeric value",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_Integer:
|
|
return (int64) intVal(def->arg);
|
|
case T_Float:
|
|
|
|
/*
|
|
* Values too large for int4 will be represented as Float
|
|
* constants by the lexer. Accept these if they are valid
|
|
* int8 strings.
|
|
*/
|
|
return DatumGetInt64(DirectFunctionCall1(int8in,
|
|
CStringGetDatum(strVal(def->arg))));
|
|
default:
|
|
elog(ERROR, "Define: \"%s\" requires a numeric value",
|
|
def->defname);
|
|
}
|
|
return 0; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a possibly-qualified name (as a List of Strings) from a DefElem.
|
|
*/
|
|
List *
|
|
defGetQualifiedName(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a parameter",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_TypeName:
|
|
return ((TypeName *) def->arg)->names;
|
|
case T_List:
|
|
return (List *) def->arg;
|
|
case T_String:
|
|
/* Allow quoted name for backwards compatibility */
|
|
return makeList1(def->arg);
|
|
default:
|
|
elog(ERROR, "Define: argument of \"%s\" must be a name",
|
|
def->defname);
|
|
}
|
|
return NIL; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a TypeName from a DefElem.
|
|
*
|
|
* Note: we do not accept a List arg here, because the parser will only
|
|
* return a bare List when the name looks like an operator name.
|
|
*/
|
|
TypeName *
|
|
defGetTypeName(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a parameter",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_TypeName:
|
|
return (TypeName *) def->arg;
|
|
case T_String:
|
|
{
|
|
/* Allow quoted typename for backwards compatibility */
|
|
TypeName *n = makeNode(TypeName);
|
|
|
|
n->names = makeList1(def->arg);
|
|
n->typmod = -1;
|
|
return n;
|
|
}
|
|
default:
|
|
elog(ERROR, "Define: argument of \"%s\" must be a type name",
|
|
def->defname);
|
|
}
|
|
return NULL; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a type length indicator (either absolute bytes, or
|
|
* -1 for "variable") from a DefElem.
|
|
*/
|
|
int
|
|
defGetTypeLength(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
elog(ERROR, "Define: \"%s\" requires a parameter",
|
|
def->defname);
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_Integer:
|
|
return intVal(def->arg);
|
|
case T_Float:
|
|
elog(ERROR, "Define: \"%s\" requires an integral value",
|
|
def->defname);
|
|
break;
|
|
case T_String:
|
|
if (strcasecmp(strVal(def->arg), "variable") == 0)
|
|
return -1; /* variable length */
|
|
break;
|
|
case T_TypeName:
|
|
/* cope if grammar chooses to believe "variable" is a typename */
|
|
if (strcasecmp(TypeNameToString((TypeName *) def->arg),
|
|
"variable") == 0)
|
|
return -1; /* variable length */
|
|
break;
|
|
case T_List:
|
|
/* must be an operator name */
|
|
break;
|
|
default:
|
|
elog(ERROR, "Define: cannot interpret argument of \"%s\"",
|
|
def->defname);
|
|
}
|
|
elog(ERROR, "Define: invalid argument for \"%s\": \"%s\"",
|
|
def->defname, defGetString(def));
|
|
return 0; /* keep compiler quiet */
|
|
}
|