00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "postgres.h"
00033
00034 #include "access/htup_details.h"
00035 #include "catalog/pg_type.h"
00036 #include "commands/typecmds.h"
00037 #include "executor/executor.h"
00038 #include "lib/stringinfo.h"
00039 #include "utils/builtins.h"
00040 #include "utils/lsyscache.h"
00041 #include "utils/syscache.h"
00042
00043
00044
00045
00046
00047 typedef struct DomainIOData
00048 {
00049 Oid domain_type;
00050
00051 Oid typiofunc;
00052 Oid typioparam;
00053 int32 typtypmod;
00054 FmgrInfo proc;
00055
00056 List *constraint_list;
00057
00058 ExprContext *econtext;
00059
00060 MemoryContext mcxt;
00061 } DomainIOData;
00062
00063
00064
00065
00066
00067 static void
00068 domain_state_setup(DomainIOData *my_extra, Oid domainType, bool binary,
00069 MemoryContext mcxt)
00070 {
00071 Oid baseType;
00072 MemoryContext oldcontext;
00073
00074
00075 my_extra->domain_type = InvalidOid;
00076
00077
00078 my_extra->typtypmod = -1;
00079 baseType = getBaseTypeAndTypmod(domainType, &my_extra->typtypmod);
00080 if (baseType == domainType)
00081 ereport(ERROR,
00082 (errcode(ERRCODE_DATATYPE_MISMATCH),
00083 errmsg("type %s is not a domain",
00084 format_type_be(domainType))));
00085
00086
00087 if (binary)
00088 getTypeBinaryInputInfo(baseType,
00089 &my_extra->typiofunc,
00090 &my_extra->typioparam);
00091 else
00092 getTypeInputInfo(baseType,
00093 &my_extra->typiofunc,
00094 &my_extra->typioparam);
00095 fmgr_info_cxt(my_extra->typiofunc, &my_extra->proc, mcxt);
00096
00097
00098 oldcontext = MemoryContextSwitchTo(mcxt);
00099 my_extra->constraint_list = GetDomainConstraints(domainType);
00100 MemoryContextSwitchTo(oldcontext);
00101
00102
00103 my_extra->econtext = NULL;
00104 my_extra->mcxt = mcxt;
00105
00106
00107 my_extra->domain_type = domainType;
00108 }
00109
00110
00111
00112
00113
00114
00115 static void
00116 domain_check_input(Datum value, bool isnull, DomainIOData *my_extra)
00117 {
00118 ExprContext *econtext = my_extra->econtext;
00119 ListCell *l;
00120
00121 foreach(l, my_extra->constraint_list)
00122 {
00123 DomainConstraintState *con = (DomainConstraintState *) lfirst(l);
00124
00125 switch (con->constrainttype)
00126 {
00127 case DOM_CONSTRAINT_NOTNULL:
00128 if (isnull)
00129 ereport(ERROR,
00130 (errcode(ERRCODE_NOT_NULL_VIOLATION),
00131 errmsg("domain %s does not allow null values",
00132 format_type_be(my_extra->domain_type)),
00133 errdatatype(my_extra->domain_type)));
00134 break;
00135 case DOM_CONSTRAINT_CHECK:
00136 {
00137 Datum conResult;
00138 bool conIsNull;
00139
00140
00141 if (econtext == NULL)
00142 {
00143 MemoryContext oldcontext;
00144
00145 oldcontext = MemoryContextSwitchTo(my_extra->mcxt);
00146 econtext = CreateStandaloneExprContext();
00147 MemoryContextSwitchTo(oldcontext);
00148 my_extra->econtext = econtext;
00149 }
00150
00151
00152
00153
00154
00155
00156
00157 econtext->domainValue_datum = value;
00158 econtext->domainValue_isNull = isnull;
00159
00160 conResult = ExecEvalExprSwitchContext(con->check_expr,
00161 econtext,
00162 &conIsNull, NULL);
00163
00164 if (!conIsNull &&
00165 !DatumGetBool(conResult))
00166 ereport(ERROR,
00167 (errcode(ERRCODE_CHECK_VIOLATION),
00168 errmsg("value for domain %s violates check constraint \"%s\"",
00169 format_type_be(my_extra->domain_type),
00170 con->name),
00171 errdomainconstraint(my_extra->domain_type,
00172 con->name)));
00173 break;
00174 }
00175 default:
00176 elog(ERROR, "unrecognized constraint type: %d",
00177 (int) con->constrainttype);
00178 break;
00179 }
00180 }
00181
00182
00183
00184
00185
00186
00187 if (econtext)
00188 ReScanExprContext(econtext);
00189 }
00190
00191
00192
00193
00194
00195 Datum
00196 domain_in(PG_FUNCTION_ARGS)
00197 {
00198 char *string;
00199 Oid domainType;
00200 DomainIOData *my_extra;
00201 Datum value;
00202
00203
00204
00205
00206
00207
00208 if (PG_ARGISNULL(0))
00209 string = NULL;
00210 else
00211 string = PG_GETARG_CSTRING(0);
00212 if (PG_ARGISNULL(1))
00213 PG_RETURN_NULL();
00214 domainType = PG_GETARG_OID(1);
00215
00216
00217
00218
00219
00220 my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
00221 if (my_extra == NULL)
00222 {
00223 my_extra = (DomainIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00224 sizeof(DomainIOData));
00225 domain_state_setup(my_extra, domainType, false,
00226 fcinfo->flinfo->fn_mcxt);
00227 fcinfo->flinfo->fn_extra = (void *) my_extra;
00228 }
00229 else if (my_extra->domain_type != domainType)
00230 domain_state_setup(my_extra, domainType, false,
00231 fcinfo->flinfo->fn_mcxt);
00232
00233
00234
00235
00236 value = InputFunctionCall(&my_extra->proc,
00237 string,
00238 my_extra->typioparam,
00239 my_extra->typtypmod);
00240
00241
00242
00243
00244 domain_check_input(value, (string == NULL), my_extra);
00245
00246 if (string == NULL)
00247 PG_RETURN_NULL();
00248 else
00249 PG_RETURN_DATUM(value);
00250 }
00251
00252
00253
00254
00255 Datum
00256 domain_recv(PG_FUNCTION_ARGS)
00257 {
00258 StringInfo buf;
00259 Oid domainType;
00260 DomainIOData *my_extra;
00261 Datum value;
00262
00263
00264
00265
00266
00267
00268 if (PG_ARGISNULL(0))
00269 buf = NULL;
00270 else
00271 buf = (StringInfo) PG_GETARG_POINTER(0);
00272 if (PG_ARGISNULL(1))
00273 PG_RETURN_NULL();
00274 domainType = PG_GETARG_OID(1);
00275
00276
00277
00278
00279
00280 my_extra = (DomainIOData *) fcinfo->flinfo->fn_extra;
00281 if (my_extra == NULL)
00282 {
00283 my_extra = (DomainIOData *) MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
00284 sizeof(DomainIOData));
00285 domain_state_setup(my_extra, domainType, true,
00286 fcinfo->flinfo->fn_mcxt);
00287 fcinfo->flinfo->fn_extra = (void *) my_extra;
00288 }
00289 else if (my_extra->domain_type != domainType)
00290 domain_state_setup(my_extra, domainType, true,
00291 fcinfo->flinfo->fn_mcxt);
00292
00293
00294
00295
00296 value = ReceiveFunctionCall(&my_extra->proc,
00297 buf,
00298 my_extra->typioparam,
00299 my_extra->typtypmod);
00300
00301
00302
00303
00304 domain_check_input(value, (buf == NULL), my_extra);
00305
00306 if (buf == NULL)
00307 PG_RETURN_NULL();
00308 else
00309 PG_RETURN_DATUM(value);
00310 }
00311
00312
00313
00314
00315
00316
00317
00318 void
00319 domain_check(Datum value, bool isnull, Oid domainType,
00320 void **extra, MemoryContext mcxt)
00321 {
00322 DomainIOData *my_extra = NULL;
00323
00324 if (mcxt == NULL)
00325 mcxt = CurrentMemoryContext;
00326
00327
00328
00329
00330
00331 if (extra)
00332 my_extra = (DomainIOData *) *extra;
00333 if (my_extra == NULL)
00334 {
00335 my_extra = (DomainIOData *) MemoryContextAlloc(mcxt,
00336 sizeof(DomainIOData));
00337 domain_state_setup(my_extra, domainType, true, mcxt);
00338 if (extra)
00339 *extra = (void *) my_extra;
00340 }
00341 else if (my_extra->domain_type != domainType)
00342 domain_state_setup(my_extra, domainType, true, mcxt);
00343
00344
00345
00346
00347 domain_check_input(value, isnull, my_extra);
00348 }
00349
00350
00351
00352
00353
00354 int
00355 errdatatype(Oid datatypeOid)
00356 {
00357 HeapTuple tup;
00358 Form_pg_type typtup;
00359
00360 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(datatypeOid));
00361 if (!HeapTupleIsValid(tup))
00362 elog(ERROR, "cache lookup failed for type %u", datatypeOid);
00363 typtup = (Form_pg_type) GETSTRUCT(tup);
00364
00365 err_generic_string(PG_DIAG_SCHEMA_NAME,
00366 get_namespace_name(typtup->typnamespace));
00367 err_generic_string(PG_DIAG_DATATYPE_NAME, NameStr(typtup->typname));
00368
00369 ReleaseSysCache(tup);
00370
00371 return 0;
00372 }
00373
00374
00375
00376
00377
00378 int
00379 errdomainconstraint(Oid datatypeOid, const char *conname)
00380 {
00381 errdatatype(datatypeOid);
00382 err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname);
00383
00384 return 0;
00385 }