* Copyright (c) 2022 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
* ---------------------------------------------------------------------------------------
*
* subtype.cpp
* I/O functions for subtypes
*
* SUBTYPE is only suport in PLpgSQL, The syntax for defining a subtype is
* { precision [, scale ] } [ NOT NULL ]
* The output functions for a subtype are just the same one provided by its
* underlying base type. The input functions, however, must be prepare to
* apply any constaints defined by the type. So, we create special input
* functions that invoke the base type's input funtions and the check the
* constraints.
*
* IDENTIFICATION
* src/backend/utils/adt/subtype.cpp
*
* -------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_variable.h"
#include "commands/typecmds.h"
#include "executor/executor.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
* struct to cache state across ultiple calls
*/
typedef struct SubtypeIOData {
Oid domain_type;
Oid typiofunc;
Oid typioparam;
int32 typtypmod;
FmgrInfo proc;
bool isNotNull;
MemoryContext mcxt;
} SubtypeIOData;
static void subtype_state_setup(SubtypeIOData* myExtra, Oid subType, bool binary, MemoryContext mcxt);
static void subtype_check_input(int32 value, bool isnull, SubtypeIOData* myExtra);
Datum subtype_in(PG_FUNCTION_ARGS)
{
char* string = NULL;
Oid subType;
SubtypeIOData* myExtra = NULL;
Datum value;
int32 typmod;
if (PG_ARGISNULL(0)) {
string = NULL;
} else {
string = PG_GETARG_CSTRING(0);
}
if (PG_ARGISNULL(1)) {
PG_RETURN_NULL();
}
subType = PG_GETARG_OID(1);
typmod = PG_GETARG_INT32(2);
myExtra = (SubtypeIOData*)fcinfo->flinfo->fn_extra;
if (myExtra == NULL) {
myExtra = (SubtypeIOData*)MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(SubtypeIOData));
subtype_state_setup((myExtra), subType, false, fcinfo->flinfo->fn_mcxt);
fcinfo->flinfo->fn_extra = (void*)myExtra;
}
Assert(myExtra != NULL);
typmod = (typmod != -1) ? typmod : myExtra->typtypmod;
value = InputFunctionCall(&myExtra->proc, string, myExtra->typioparam, typmod);
subtype_check_input(Int32GetDatum(value), (string == NULL), myExtra);
if (string == NULL) {
PG_RETURN_NULL();
} else {
PG_RETURN_DATUM(value);
}
}
* subtype_recv - binary input routine for any subtype
*/
Datum subtype_recv(PG_FUNCTION_ARGS)
{
StringInfo buf;
Oid subType;
SubtypeIOData* myExtra;
Datum value;
int32 typmod;
if (PG_ARGISNULL(0)) {
buf = NULL;
} else {
buf =(StringInfo)PG_GETARG_POINTER(0);
}
if (PG_ARGISNULL(1)) {
PG_RETURN_NULL();
}
subType = PG_GETARG_OID(1);
* Use basetype's typmod in pg_type or this
* This typmod is use to support bounded precision ranges
*/
typmod = PG_GETARG_INT32(2);
myExtra = (SubtypeIOData*)fcinfo->flinfo->fn_extra;
if (myExtra == NULL) {
myExtra = (SubtypeIOData*)MemoryContextAlloc(fcinfo->flinfo->fn_mcxt, sizeof(SubtypeIOData));
subtype_state_setup(myExtra, subType, false, fcinfo->flinfo->fn_mcxt);
fcinfo->flinfo->fn_extra = (void*)myExtra;
}
Assert(myExtra != NULL);
typmod = (typmod != -1) ? typmod : myExtra->typtypmod;
value = ReceiveFunctionCall(&myExtra->proc, buf, myExtra->typioparam, typmod);
subtype_check_input(Int32GetDatum(value), (buf == NULL), myExtra);
if (buf == NULL) {
PG_RETURN_NULL();
} else {
PG_RETURN_DATUM(value);
}
}
* subtype_state_setup - initialize the cache for a new subtype
*/
static void subtype_state_setup(SubtypeIOData* myExtra, Oid subType, bool binary, MemoryContext mcxt)
{
Oid baseType;
myExtra->domain_type = InvalidOid;
myExtra->typtypmod = -1;
baseType = getBaseTypeAndTypmod(subType, &myExtra->typtypmod);
if (baseType == subType) {
ereport(
ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("type %s is not a subtype", format_type_be(subType))
));
}
if (binary) {
getTypeBinaryInputInfo(baseType, &myExtra->typiofunc, &myExtra->typioparam);
} else {
getTypeInputInfo(baseType, &myExtra->typiofunc, &myExtra->typioparam);
}
fmgr_info_cxt(myExtra->typiofunc, &myExtra->proc, mcxt);
HeapTuple tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(subType));
Form_pg_type typTup = (Form_pg_type)GETSTRUCT(tup);
myExtra->isNotNull = typTup->typnotnull;
ReleaseSysCache(tup);
myExtra->mcxt = mcxt;
myExtra->domain_type = subType;
}
* subtype_check_input - check constraints
*/
static void subtype_check_input(int32 value, bool isnull, SubtypeIOData* myExtra)
{
if (isnull) {
if (myExtra->isNotNull) {
ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION),
errmsg("value of subtype %s can not be null", format_type_be(myExtra->domain_type))));
}
return;
}
}