summaryrefslogtreecommitdiffstats
path: root/src/backend/commands/define.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/define.c')
-rw-r--r--src/backend/commands/define.c391
1 files changed, 391 insertions, 0 deletions
diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c
new file mode 100644
index 0000000..1e07fa9
--- /dev/null
+++ b/src/backend/commands/define.c
@@ -0,0 +1,391 @@
+/*-------------------------------------------------------------------------
+ *
+ * define.c
+ * Support routines for various kinds of object creation.
+ *
+ *
+ * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * src/backend/commands/define.c
+ *
+ * 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 "nodes/makefuncs.h"
+#include "parser/parse_type.h"
+#include "parser/scansup.h"
+#include "utils/builtins.h"
+
+/*
+ * 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:
+ return psprintf("%ld", (long) intVal(def->arg));
+ case T_Float:
+ return castNode(Float, def->arg)->fval;
+ case T_Boolean:
+ return boolVal(def->arg) ? "true" : "false";
+ case T_String:
+ return strVal(def->arg);
+ case T_TypeName:
+ return TypeNameToString((TypeName *) def->arg);
+ case T_List:
+ return NameListToString((List *) def->arg);
+ case T_A_Star:
+ return pstrdup("*");
+ 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)
+{
+ /*
+ * If no parameter given, assume "true" is meant.
+ */
+ if (def->arg == NULL)
+ return true;
+
+ /*
+ * Allow 0, 1, "true", "false", "on", "off"
+ */
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ switch (intVal(def->arg))
+ {
+ case 0:
+ return false;
+ case 1:
+ return true;
+ default:
+ /* otherwise, error out below */
+ break;
+ }
+ break;
+ default:
+ {
+ char *sval = defGetString(def);
+
+ /*
+ * The set of strings accepted here should match up with the
+ * grammar's opt_boolean_or_string production.
+ */
+ if (pg_strcasecmp(sval, "true") == 0)
+ return true;
+ if (pg_strcasecmp(sval, "false") == 0)
+ return false;
+ if (pg_strcasecmp(sval, "on") == 0)
+ return true;
+ if (pg_strcasecmp(sval, "off") == 0)
+ return false;
+ }
+ break;
+ }
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires a Boolean value",
+ def->defname)));
+ return false; /* keep compiler quiet */
+}
+
+/*
+ * Extract an int32 value from a DefElem.
+ */
+int32
+defGetInt32(DefElem *def)
+{
+ if (def->arg == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ switch (nodeTag(def->arg))
+ {
+ case T_Integer:
+ return (int32) intVal(def->arg);
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires an integer value",
+ def->defname)));
+ }
+ return 0; /* 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(castNode(Float, def->arg)->fval)));
+ default:
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires a numeric value",
+ def->defname)));
+ }
+ return 0; /* keep compiler quiet */
+}
+
+/*
+ * Extract an OID value from a DefElem.
+ */
+Oid
+defGetObjectId(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 (Oid) 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 OID
+ * strings.
+ */
+ return DatumGetObjectId(DirectFunctionCall1(oidin,
+ CStringGetDatum(castNode(Float, def->arg)->fval)));
+ 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 */
+ return makeTypeNameFromNameList(list_make1(def->arg));
+ 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 */
+}
+
+/*
+ * Extract a list of string values (otherwise uninterpreted) from a DefElem.
+ */
+List *
+defGetStringList(DefElem *def)
+{
+ ListCell *cell;
+
+ if (def->arg == NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("%s requires a parameter",
+ def->defname)));
+ if (nodeTag(def->arg) != T_List)
+ elog(ERROR, "unrecognized node type: %d", (int) nodeTag(def->arg));
+
+ foreach(cell, (List *) def->arg)
+ {
+ Node *str = (Node *) lfirst(cell);
+
+ if (!IsA(str, String))
+ elog(ERROR, "unexpected node type in name list: %d",
+ (int) nodeTag(str));
+ }
+
+ return (List *) def->arg;
+}
+
+/*
+ * Raise an error about a conflicting DefElem.
+ */
+void
+errorConflictingDefElem(DefElem *defel, ParseState *pstate)
+{
+ ereport(ERROR,
+ errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("conflicting or redundant options"),
+ parser_errposition(pstate, defel->location));
+}