mirror of
https://github.com/postgres/postgres.git
synced 2025-09-09 13:09:39 +03:00
In the past, we used a 'Lispy' linked list implementation: a "list" was merely a pointer to the head node of the list. The problem with that design is that it makes lappend() and length() linear time. This patch fixes that problem (and others) by maintaining a count of the list length and a pointer to the tail node along with each head node pointer. A "list" is now a pointer to a structure containing some meta-data about the list; the head and tail pointers in that structure refer to ListCell structures that maintain the actual linked list of nodes. The function names of the list API have also been changed to, I hope, be more logically consistent. By default, the old function names are still available; they will be disabled-by-default once the rest of the tree has been updated to use the new API names.
283 lines
6.7 KiB
C
283 lines
6.7 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* define.c
|
|
* Support routines for various kinds of object creation.
|
|
*
|
|
*
|
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* $PostgreSQL: pgsql/src/backend/commands/define.c,v 1.89 2004/05/26 04:41:10 neilc 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 "parser/scansup.h"
|
|
#include "utils/int8.h"
|
|
|
|
|
|
/*
|
|
* Translate the input language name to lower case, and truncate if needed.
|
|
*
|
|
* Returns a palloc'd string
|
|
*/
|
|
char *
|
|
case_translate_language_name(const char *input)
|
|
{
|
|
return downcase_truncate_identifier(input, strlen(input), false);
|
|
}
|
|
|
|
|
|
/*
|
|
* Extract a string value (otherwise uninterpreted) from a DefElem.
|
|
*/
|
|
char *
|
|
defGetString(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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, "unrecognized node type: %d", (int) nodeTag(def->arg));
|
|
}
|
|
return NULL; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a numeric value (actually double) from a DefElem.
|
|
*/
|
|
double
|
|
defGetNumeric(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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:
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%s requires a numeric value",
|
|
def->defname)));
|
|
}
|
|
return 0; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract a boolean value from a DefElem.
|
|
*/
|
|
bool
|
|
defGetBoolean(DefElem *def)
|
|
{
|
|
/*
|
|
* Presently, boolean flags must simply be present or absent.
|
|
* Later we could allow 'flag = t', 'flag = f', etc.
|
|
*/
|
|
if (def->arg == NULL)
|
|
return true;
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%s does not take a parameter",
|
|
def->defname)));
|
|
return false; /* keep compiler quiet */
|
|
}
|
|
|
|
/*
|
|
* Extract an int64 value from a DefElem.
|
|
*/
|
|
int64
|
|
defGetInt64(DefElem *def)
|
|
{
|
|
if (def->arg == NULL)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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:
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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 list_make1(def->arg);
|
|
default:
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("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)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%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 = list_make1(def->arg);
|
|
n->typmod = -1;
|
|
return n;
|
|
}
|
|
default:
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("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)
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%s requires a parameter",
|
|
def->defname)));
|
|
switch (nodeTag(def->arg))
|
|
{
|
|
case T_Integer:
|
|
return intVal(def->arg);
|
|
case T_Float:
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("%s requires an integer value",
|
|
def->defname)));
|
|
break;
|
|
case T_String:
|
|
if (pg_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 (pg_strcasecmp(TypeNameToString((TypeName *) def->arg),
|
|
"variable") == 0)
|
|
return -1; /* variable length */
|
|
break;
|
|
case T_List:
|
|
/* must be an operator name */
|
|
break;
|
|
default:
|
|
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
|
|
}
|
|
ereport(ERROR,
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
errmsg("invalid argument for %s: \"%s\"",
|
|
def->defname, defGetString(def))));
|
|
return 0; /* keep compiler quiet */
|
|
}
|