aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils')
-rw-r--r--src/backend/utils/adt/misc.c129
1 files changed, 129 insertions, 0 deletions
diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c
index 9c132512315..d678d286009 100644
--- a/src/backend/utils/adt/misc.c
+++ b/src/backend/utils/adt/misc.c
@@ -32,6 +32,8 @@
#include "common/keywords.h"
#include "funcapi.h"
#include "miscadmin.h"
+#include "nodes/miscnodes.h"
+#include "parser/parse_type.h"
#include "parser/scansup.h"
#include "pgstat.h"
#include "postmaster/syslogger.h"
@@ -45,6 +47,25 @@
#include "utils/ruleutils.h"
#include "utils/timestamp.h"
+
+/*
+ * structure to cache metadata needed in pg_input_is_valid_common
+ */
+typedef struct ValidIOData
+{
+ Oid typoid;
+ int32 typmod;
+ bool typname_constant;
+ Oid typiofunc;
+ Oid typioparam;
+ FmgrInfo inputproc;
+} ValidIOData;
+
+static bool pg_input_is_valid_common(FunctionCallInfo fcinfo,
+ text *txt, text *typname,
+ ErrorSaveContext *escontext);
+
+
/*
* Common subroutine for num_nulls() and num_nonnulls().
* Returns true if successful, false if function should return NULL.
@@ -641,6 +662,114 @@ pg_column_is_updatable(PG_FUNCTION_ARGS)
/*
+ * pg_input_is_valid - test whether string is valid input for datatype.
+ *
+ * Returns true if OK, false if not.
+ *
+ * This will only work usefully if the datatype's input function has been
+ * updated to return "soft" errors via errsave/ereturn.
+ */
+Datum
+pg_input_is_valid(PG_FUNCTION_ARGS)
+{
+ text *txt = PG_GETARG_TEXT_PP(0);
+ text *typname = PG_GETARG_TEXT_PP(1);
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ PG_RETURN_BOOL(pg_input_is_valid_common(fcinfo, txt, typname,
+ &escontext));
+}
+
+/*
+ * pg_input_error_message - test whether string is valid input for datatype.
+ *
+ * Returns NULL if OK, else the primary message string from the error.
+ *
+ * This will only work usefully if the datatype's input function has been
+ * updated to return "soft" errors via errsave/ereturn.
+ */
+Datum
+pg_input_error_message(PG_FUNCTION_ARGS)
+{
+ text *txt = PG_GETARG_TEXT_PP(0);
+ text *typname = PG_GETARG_TEXT_PP(1);
+ ErrorSaveContext escontext = {T_ErrorSaveContext};
+
+ /* Enable details_wanted */
+ escontext.details_wanted = true;
+
+ if (pg_input_is_valid_common(fcinfo, txt, typname,
+ &escontext))
+ PG_RETURN_NULL();
+
+ Assert(escontext.error_occurred);
+ Assert(escontext.error_data != NULL);
+ Assert(escontext.error_data->message != NULL);
+
+ PG_RETURN_TEXT_P(cstring_to_text(escontext.error_data->message));
+}
+
+/* Common subroutine for the above */
+static bool
+pg_input_is_valid_common(FunctionCallInfo fcinfo,
+ text *txt, text *typname,
+ ErrorSaveContext *escontext)
+{
+ char *str = text_to_cstring(txt);
+ ValidIOData *my_extra;
+ Datum converted;
+
+ /*
+ * We arrange to look up the needed I/O info just once per series of
+ * calls, assuming the data type doesn't change underneath us.
+ */
+ my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
+ if (my_extra == NULL)
+ {
+ fcinfo->flinfo->fn_extra =
+ MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ sizeof(ValidIOData));
+ my_extra = (ValidIOData *) fcinfo->flinfo->fn_extra;
+ my_extra->typoid = InvalidOid;
+ /* Detect whether typname argument is constant. */
+ my_extra->typname_constant = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
+ }
+
+ /*
+ * If the typname argument is constant, we only need to parse it the first
+ * time through.
+ */
+ if (my_extra->typoid == InvalidOid || !my_extra->typname_constant)
+ {
+ char *typnamestr = text_to_cstring(typname);
+ Oid typoid;
+
+ /* Parse type-name argument to obtain type OID and encoded typmod. */
+ parseTypeString(typnamestr, &typoid, &my_extra->typmod, false);
+
+ /* Update type-specific info if typoid changed. */
+ if (my_extra->typoid != typoid)
+ {
+ getTypeInputInfo(typoid,
+ &my_extra->typiofunc,
+ &my_extra->typioparam);
+ fmgr_info_cxt(my_extra->typiofunc, &my_extra->inputproc,
+ fcinfo->flinfo->fn_mcxt);
+ my_extra->typoid = typoid;
+ }
+ }
+
+ /* Now we can try to perform the conversion. */
+ return InputFunctionCallSafe(&my_extra->inputproc,
+ str,
+ my_extra->typioparam,
+ my_extra->typmod,
+ (Node *) escontext,
+ &converted);
+}
+
+
+/*
* Is character a valid identifier start?
* Must match scan.l's {ident_start} character class.
*/