* Copyright (c) Huawei Technologies Co., Ltd. 2024-2026. All rights reserved.
*
* 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.
* --------------------------------------------------------------------------------------
*
* varlena.c
* Functions in common use.
*
* Portions Copyright (c) 2026, Huawei Technologies Co.,Ltd.
* Portions Copyright (c) 2020, AWS
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* contrib/shark/varlena.c
*
* --------------------------------------------------------------------------------------
*/
#include "knl/knl_variable.h"
#include "postgres.h"
#include "miscadmin.h"
#include "knl/knl_instance.h"
#include <stdlib.h>
#include <cmath>
#include "access/sysattr.h"
#include "knl/knl_variable.h"
#include "commands/extension.h"
#include "commands/dbcommands.h"
#include "nodes/execnodes.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/fmgroids.h"
#include "parser/scansup.h"
#include "tcop/ddldeparse.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_attrdef.h"
#include "catalog/indexing.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_trigger.h"
typedef enum
{
OBJECT_TYPE_AGGREGATE_FUNCTION = 1,
OBJECT_TYPE_CHECK_CONSTRAINT,
OBJECT_TYPE_DEFAULT_CONSTRAINT,
OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT,
OBJECT_TYPE_TSQL_SCALAR_FUNCTION,
OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION,
OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION,
OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION,
OBJECT_TYPE_INTERNAL_TABLE,
OBJECT_TYPE_TSQL_STORED_PROCEDURE,
OBJECT_TYPE_ASSEMBLY_STORED_PROCEDURE,
OBJECT_TYPE_PLAN_GUIDE,
OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT,
OBJECT_TYPE_RULE,
OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE,
OBJECT_TYPE_SYSTEM_BASE_TABLE,
OBJECT_TYPE_SYNONYM,
OBJECT_TYPE_SEQUENCE_OBJECT,
OBJECT_TYPE_SERVICE_QUEUE,
OBJECT_TYPE_ASSEMBLY_DML_TRIGGER,
OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION,
OBJECT_TYPE_TSQL_DML_TRIGGER,
OBJECT_TYPE_TABLE,
OBJECT_TYPE_UNIQUE_CONSTRAINT,
OBJECT_TYPE_VIEW,
OBJECT_TYPE_MATERIALIZED_VIEW,
OBJECT_TYPE_EXTENDED_STORED_PROCEDURE,
OBJECT_TYPE_INVALID,
} PropertyType;
Oid tsql_get_proc_nsp_oid(Oid object_id);
Oid tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id);
extern char* GetPhysicalSchemaName(char *dbName, const char *schemaName);
static bool is_shared_schema(const char *name);
static char* GetCurrentPhysicalSchemaName(char* schemaName);
static Oid search_oid_in_class(char* obj_name, Oid schema_oid, char* type_name = NULL);
static Oid search_oid_in_proc(char* obj_name, Oid schema_oid);
static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid);
static Oid search_oid_in_cons(char* obj_name, Oid schema_oid);
static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type);
static int search_type_in_class(Oid* schema_id, Oid object_id, char* object_name);
static int search_type_in_proc(Oid* schema_id, Oid object_id, char* object_name);
static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name);
static int search_type_in_cons(Oid* schema_id, Oid object_id, char* object_name);
static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_name);
static int dealwith_property(int type, Oid schema_id, Oid object_id, char* property);
static inline int dealwith_type_ownerid(int type, Oid schema_id);
static inline int dealwith_type_defcnst(int type);
static inline int dealwith_type_exec_bound(int type, char* property);
static inline int dealwith_type_status_format(int type);
static inline int dealwith_type_issysshipped(int type, Oid schema_id);
static inline int dealwith_type_dete(int type, Oid object_id);
static inline int dealwith_type_procedure(int type);
static inline int dealwith_type_table(int type);
static inline int dealwith_type_view(int type);
static inline int dealwith_type_usertable(int type, Oid schema_id);
static inline int dealwith_type_tablefunc(int type);
static inline int dealwith_type_inlinefunc(int type);
static inline int dealwith_type_scalarfunc(int type);
static inline int dealwith_type_pk(int type);
static inline int dealwith_type_indexed(int type, Oid object_id);
static inline int dealwith_type_trigger(int type);
static Oid search_oid_in_proc(char* obj_name, Oid schema_oid)
{
Oid id = InvalidOid;
CatCList* catlist = NULL;
HeapTuple tuple;
Form_pg_proc procform;
#ifndef ENABLE_MULTIPLE_NODES
if (t_thrd.proc->workingVersionNum < 92470) {
catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(obj_name));
} else {
catlist = SearchSysCacheList1(PROCALLARGS, CStringGetDatum(obj_name));
}
#else
catlist = SearchSysCacheList1(PROCNAMEARGSNSP, CStringGetDatum(obj_name));
#endif
for (int i = 0; i < catlist->n_members; i++) {
tuple = t_thrd.lsc_cxt.FetchTupleFromCatCList(catlist, i);
procform = (Form_pg_proc)GETSTRUCT(tuple);
if (procform->pronamespace != schema_oid) {
continue;
}
id = HeapTupleGetOid(tuple);
break;
}
ReleaseSysCacheList(catlist);
return id;
}
static Oid search_oid_in_trigger(char* obj_name, Oid schema_oid)
{
Oid id = InvalidOid;
Relation tgrel;
ScanKeyData keys[1];
SysScanDesc tgscan;
HeapTuple tuple;
ScanKeyInit(&keys[0], Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(obj_name));
tgrel = heap_open(TriggerRelationId, AccessShareLock);
tgscan = systable_beginscan(tgrel, TriggerNameIndexId, true, SnapshotNow, 1, keys);
if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) {
id = HeapTupleGetOid(tuple);
}
systable_endscan(tgscan);
heap_close(tgrel, AccessShareLock);
return id;
}
static Oid search_oid_in_cons(char* obj_name, Oid schema_oid)
{
Oid id = InvalidOid;
Relation tgrel;
ScanKeyData skeys[2];
SysScanDesc tgscan;
HeapTuple tuple;
ScanKeyInit(&skeys[0], Anum_pg_constraint_conname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(obj_name));
ScanKeyInit(&skeys[1],
Anum_pg_constraint_connamespace,
BTEqualStrategyNumber,
F_OIDEQ,
ObjectIdGetDatum(schema_oid));
tgrel = heap_open(ConstraintRelationId, AccessShareLock);
tgscan = systable_beginscan(tgrel, ConstraintNameNspIndexId, true, SnapshotNow, 2, skeys);
if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) {
id = HeapTupleGetOid(tuple);
}
systable_endscan(tgscan);
heap_close(tgrel, AccessShareLock);
return id;
}
static Oid search_oid_in_class(char* obj_name, Oid schema_oid, char* type_name)
{
Oid id = InvalidOid;
HeapTuple tuple;
Form_pg_class classform;
tuple = SearchSysCache2(RELNAMENSP, PointerGetDatum(obj_name), ObjectIdGetDatum(schema_oid));
if (!HeapTupleIsValid(tuple)) {
return InvalidOid;
}
classform = (Form_pg_class) GETSTRUCT(tuple);
id = HeapTupleGetOid(tuple);
if (type_name != NULL) {
switch (classform->relkind) {
case 'r':
if ((strcmp(type_name, "U") != 0 && strcmp(type_name, "S") != 0) ||
(strcmp(type_name, "U") == 0 && IsSystemObjOid(id)) ||
(strcmp(type_name, "S") == 0 && !IsSystemObjOid(id))) {
id = InvalidOid;
}
break;
case 'v':
if (strcmp(type_name, "V") != 0) {
id = InvalidOid;
}
break;
case 'S':
if (strcmp(type_name, "SO") != 0) {
id = InvalidOid;
}
break;
default:
id = InvalidOid;
break;
}
} else if (classform->relkind == 'i' || classform->relkind == 'l') {
id = InvalidOid;
}
ReleaseSysCache(tuple);
return id;
}
static Oid search_oid_in_schema(char* schema_name, char* obj_name, char *object_type)
{
Oid schema_oid = InvalidOid;
if (schema_name != NULL && strlen(schema_name) > 0)
{
schema_oid = get_namespace_oid(schema_name, true);
if (!OidIsValid(schema_oid))
return InvalidOid;
if (!pg_namespace_ownercheck(schema_oid, GetUserId()))
{
ereport(NOTICE,
(errmsg("Permission denied for schema %s", schema_name)));
return InvalidOid;
}
} else {
char *token, *saveptr;
char* search_path = pstrdup(u_sess->attr.attr_common.namespace_search_path);
token = strtok_r(search_path, ",", &saveptr);
if (strcmp(token, "\"$user\"") == 0) {
token = strtok_r(NULL, ",", &saveptr);
}
schema_oid = SchemaNameGetSchemaOid(token, false);
}
Oid id = InvalidOid;
if (object_type != NULL)
{
char* type_name = pg_strtoupper(object_type);
if (strlen(type_name) == 2 && type_name[1] == ' ') {
type_name[1] = '\0';
}
if (strcmp(type_name, "S") == 0 || strcmp(type_name, "U") == 0 || strcmp(type_name, "V") == 0 ||
strcmp(type_name, "SO") == 0)
{
id = search_oid_in_class(obj_name, schema_oid, type_name);
} else if (strcmp(type_name, "C") == 0 || strcmp(type_name, "D") == 0 || strcmp(type_name, "F") == 0 ||
strcmp(type_name, "PK") == 0 || strcmp(type_name, "UQ") == 0) {
id = search_oid_in_cons(obj_name, schema_oid);
} else if (strcmp(type_name, "AF") == 0 || strcmp(type_name, "FN") == 0 ||
strcmp(type_name, "P") == 0 || strcmp(type_name, "PC") == 0) {
id = search_oid_in_proc(obj_name, schema_oid);
} else if (strcmp(type_name, "TR") == 0) {
id = search_oid_in_trigger(obj_name, schema_oid);
} else {
return InvalidOid;
}
} else {
if (id == InvalidOid) {
id = search_oid_in_class(obj_name, schema_oid);
}
if (id == InvalidOid) {
id = search_oid_in_cons(obj_name, schema_oid);
}
if (id == InvalidOid) {
id = search_oid_in_proc(obj_name, schema_oid);
}
if (id == InvalidOid) {
id = search_oid_in_trigger(obj_name, schema_oid);
}
}
return id;
}
static int search_type_in_class(Oid* schema_id, Oid object_id, char* object_name)
{
int type = OBJECT_TYPE_INVALID;
HeapTuple tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple))
{
Form_pg_class pg_class = (Form_pg_class) GETSTRUCT(tuple);
object_name = NameStr(pg_class->relname);
if (pg_class_aclcheck(object_id, GetUserId(), ACL_SELECT) == ACLCHECK_OK)
*schema_id = get_rel_namespace(object_id);
* Get the type of the object
*/
if ((pg_class->relpersistence == 'p' || pg_class->relpersistence == 'u' || pg_class->relpersistence == 't' ||
pg_class->relpersistence == 'g') && (pg_class->relkind == 'r'))
{
type = OBJECT_TYPE_TABLE;
}
else if (pg_class->relkind == 'v')
type = OBJECT_TYPE_VIEW;
else if (pg_class->relkind == 'm')
type = OBJECT_TYPE_MATERIALIZED_VIEW;
else if (pg_class->relkind == 's')
type = OBJECT_TYPE_SEQUENCE_OBJECT;
ReleaseSysCache(tuple);
}
return type;
}
static int search_type_in_proc(Oid* schema_id, Oid object_id, char* object_name)
{
int type = OBJECT_TYPE_INVALID;
HeapTuple tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple))
{
if (pg_proc_aclcheck(object_id, GetUserId(), ACL_EXECUTE) == ACLCHECK_OK)
{
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple);
object_name = NameStr(procform->proname);
*schema_id = tsql_get_proc_nsp_oid(object_id);
char prokind = get_func_prokind(HeapTupleGetOid(tuple));
if (prokind == 'p')
type = OBJECT_TYPE_TSQL_STORED_PROCEDURE;
else if (prokind == 'a')
type = OBJECT_TYPE_AGGREGATE_FUNCTION;
else
{
* Check whether the object is SQL DML trigger(TR), SQL table-valued-function (TF),
* SQL inline table-valued function (IF), SQL scalar function (FN).
*/
char *temp = format_type_with_typemod(procform->prorettype, -1);
* If the prorettype of the pg_proc object is "trigger", then the type of the object is "TR"
*/
if (pg_strcasecmp(temp, "trigger") == 0)
type = OBJECT_TYPE_TSQL_DML_TRIGGER;
* For SQL table-valued-functions and SQL inline table-valued functions, re-implement the existing SQL.
*/
else if (procform->proretset)
{
HeapTuple tp;
tp = SearchSysCache1(TYPEOID, ObjectIdGetDatum(procform->prorettype));
if (HeapTupleIsValid(tp))
{
Form_pg_type typeform = (Form_pg_type) GETSTRUCT(tuple);
if (typeform->typtype == 'c')
type = OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION;
else
type = OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION;
ReleaseSysCache(tp);
}
}
else
type = OBJECT_TYPE_TSQL_SCALAR_FUNCTION;
pfree_ext(temp);
}
}
ReleaseSysCache(tuple);
}
return type;
}
static int search_type_in_attr(Oid* schema_id, Oid object_id, char* object_name)
{
Relation attrdefrel;
ScanKeyData key;
SysScanDesc attrscan;
int type = OBJECT_TYPE_INVALID;
attrdefrel = table_open(AttrDefaultRelationId, AccessShareLock);
ScanKeyInit(&key,
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object_id));
attrscan = systable_beginscan(attrdefrel, AttrDefaultOidIndexId, false,
NULL, 1, &key);
HeapTuple tuple = systable_getnext(attrscan);
if (HeapTupleIsValid(tuple))
{
* scan pg_attribute catalog to find the corresponding row.
* This pg_attribute pbject will be helpful to check whether the object is DEFAULT (D)
* and to find the schema_id.
*/
Form_pg_attrdef atdform = (Form_pg_attrdef) GETSTRUCT(tuple);
Relation attrRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
Oid user_id = GetUserId();
if (pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_SELECT) &&
pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_INSERT) &&
pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_UPDATE) &&
pg_attribute_aclcheck(atdform->adrelid, atdform->adnum, user_id, ACL_REFERENCES))
{
attrRel = table_open(AttributeRelationId, RowExclusiveLock);
ScanKeyInit(&key[0],
Anum_pg_attribute_attrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(atdform->adrelid));
ScanKeyInit(&key[1],
Anum_pg_attribute_attnum,
BTEqualStrategyNumber, F_INT2EQ,
Int16GetDatum(atdform->adnum));
scan = systable_beginscan(attrRel, AttributeRelidNumIndexId, true,
NULL, 2, key);
if (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_attribute attrform = (Form_pg_attribute) GETSTRUCT(tup);
if (attrform->atthasdef && !atdform->adgencol)
{
object_name = NameStr(attrform->attname);
type = OBJECT_TYPE_DEFAULT_CONSTRAINT;
if (pg_class_aclcheck(atdform->adrelid, user_id, ACL_SELECT) == ACLCHECK_OK)
*schema_id = get_rel_namespace(atdform->adrelid);
}
}
systable_endscan(scan);
table_close(attrRel, RowExclusiveLock);
}
}
systable_endscan(attrscan);
table_close(attrdefrel, AccessShareLock);
return type;
}
static int search_type_in_cons(Oid* schema_id, Oid object_id, char* object_name)
{
int type = OBJECT_TYPE_INVALID;
HeapTuple tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple))
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
object_name = NameStr(con->conname);
*schema_id = tsql_get_constraint_nsp_oid(object_id, GetUserId());
* If the contype is 'f' on the pg_constraint object, then it is a Foreign key constraint
*/
if (con->contype == 'f')
type = OBJECT_TYPE_FOREIGN_KEY_CONSTRAINT;
* If the contype is 'p' on the pg_constraint object, then it is a Primary key constraint
*/
else if (con->contype == 'p')
type = OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT;
* Reimplemented the existing SQL .
* If the contype is 'c' and conrelid is 0 on the pg_constraint object, then it is a Check constraint
*/
else if (con->contype == 'c' && con->conrelid != 0)
type = OBJECT_TYPE_CHECK_CONSTRAINT;
ReleaseSysCache(tuple);
}
return type;
}
static int search_type_in_trigger(Oid* schema_id, Oid object_id, char* object_name)
{
Relation trigDesc;
HeapTuple tup;
Form_pg_trigger trig;
int type = OBJECT_TYPE_INVALID;
trigDesc = table_open(TriggerRelationId, AccessShareLock);
tup = get_catalog_object_by_oid(trigDesc, object_id);
if (HeapTupleIsValid(tup)) {
trig = (Form_pg_trigger) GETSTRUCT(tup);
object_name = NameStr(trig->tgname);
*schema_id = get_rel_namespace(trig->tgrelid);
type = OBJECT_TYPE_ASSEMBLY_DML_TRIGGER;
}
table_close(trigDesc, AccessShareLock);
return type;
}
extern "C" Datum rand_seed(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(rand_seed);
Datum rand_seed(PG_FUNCTION_ARGS)
{
int64 n = PG_GETARG_INT64(0);
gs_srandom((unsigned int)n);
float8 result;
result = (double)gs_random() / ((double)MAX_RANDOM_VALUE + 1);
PG_RETURN_FLOAT8(result);
}
extern "C" Datum object_id_internal(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(object_id_internal);
Datum
object_id_internal(PG_FUNCTION_ARGS)
{
if (PG_ARGISNULL(0)) {
PG_RETURN_NULL();
}
char *object_name = text_to_cstring(PG_GETARG_TEXT_P(0));
char *object_type = PG_NARGS() == 1 ? NULL : text_to_cstring(PG_GETARG_TEXT_P(1));
if (strlen(object_name) < 1) {
PG_RETURN_NULL();
}
char* db_name = NULL;
char* schema_name = NULL;
char* obj_name = NULL;
char *tok = object_name;
while (*tok) {
if (*tok == '.' && *(tok + 1) == '.') {
*tok = '\0';
db_name = object_name;
tok += 2;
break;
} else {
tok++;
}
}
if (db_name != NULL) {
obj_name = tok;
} else {
List* nameList;
PG_TRY();
{
nameList = stringToQualifiedNameList(object_name);
}
PG_CATCH();
{
FlushErrorState();
PG_RETURN_NULL();
}
PG_END_TRY();
switch (list_length(nameList)) {
case 1:
obj_name = strVal(linitial(nameList));
break;
case 2:
obj_name = strVal(lsecond(nameList));
schema_name = GetCurrentPhysicalSchemaName(strVal(linitial(nameList)));
break;
case 3:
obj_name = strVal(lthird(nameList));
schema_name = GetCurrentPhysicalSchemaName(strVal(lsecond(nameList)));
db_name = strVal(linitial(nameList));
break;
default:
PG_RETURN_NULL();
break;
}
}
if (obj_name == NULL || strlen(obj_name) < 1) {
PG_RETURN_NULL();
}
char* current_db = get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, false);
if (db_name != NULL && strcmp(db_name, current_db) != 0) {
pfree_ext(current_db);
PG_RETURN_NULL();
}
pfree_ext(current_db);
Oid id = search_oid_in_schema(schema_name, obj_name, object_type);
if (id == InvalidOid) {
PG_RETURN_NULL();
}
PG_RETURN_OID(id);
}
extern "C" Datum objectproperty_internal(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(objectproperty_internal);
Datum
objectproperty_internal(PG_FUNCTION_ARGS)
{
Oid object_id;
Oid schema_id = InvalidOid;
char *property;
Oid user_id = GetUserId();
int type = 0;
char *object_name = NULL;
char *nspname = NULL;
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL();
else
{
object_id = (Oid) PG_GETARG_INT32(0);
property = text_to_cstring(PG_GETARG_TEXT_P(1));
if (strlen(property) < 1 || object_id == InvalidOid) {
PG_RETURN_NULL();
}
property = downcase_truncate_identifier(property, strlen(property), true);
property = remove_trailing_spaces(property);
}
* Search for the object_id in pg_class, pg_proc, pg_attrdef, pg_constraint.
* If the object_id is not found in any of the above catalogs, return NULL.
* Else, get the object name, type of the object and the schema_id in which
* the object is present.
*/
type = search_type_in_class(&schema_id, object_id, object_name);
if (!schema_id)
{
type = search_type_in_proc(&schema_id, object_id, object_name);
}
if (!schema_id)
{
type = search_type_in_attr(&schema_id, object_id, object_name);
}
if (!schema_id)
{
type = search_type_in_cons(&schema_id, object_id, object_name);
}
if (!schema_id)
{
type = search_type_in_trigger(&schema_id, object_id, object_name);
}
* If the object_id is not found or user does not have enough privileges on the object and schema,
* Return NULL.
*/
if (!schema_id || !pg_namespace_ownercheck(schema_id, user_id))
{
pfree_ext(property);
PG_RETURN_NULL();
}
* schema_id found should be in sys.schemas view except 'sys'.
*/
nspname = get_namespace_name(schema_id);
if (!(nspname && pg_strcasecmp(nspname, "sys") == 0) &&
(!nspname || pg_strcasecmp(nspname, "pg_catalog") == 0 ||
pg_strcasecmp(nspname, "pg_toast") == 0 ||
pg_strcasecmp(nspname, "public") == 0))
{
pfree_ext(property);
if (nspname)
pfree_ext(nspname);
PG_RETURN_NULL();
}
pfree_ext(nspname);
int result = dealwith_property(type, schema_id, object_id, property);
if (property)
pfree_ext(property);
if (result == -1) {
PG_RETURN_NULL();
} else {
PG_RETURN_INT32(result);
}
}
static int dealwith_property(int type, Oid schema_id, Oid object_id, char* property)
{
int result = -1;
if (pg_strcasecmp(property, "ownerid") == 0)
{
result = dealwith_type_ownerid(type, schema_id);
}
else if (pg_strcasecmp(property, "isdefaultcnst") == 0)
{
result = dealwith_type_defcnst(type);
}
else if (pg_strcasecmp(property, "execisquotedidenton") == 0 ||
pg_strcasecmp(property, "isschemabound") == 0 ||
pg_strcasecmp(property, "execisansinullson") == 0)
{
result = dealwith_type_exec_bound(type, property);
}
else if (pg_strcasecmp(property, "tablefulltextpopulatestatus") == 0 ||
pg_strcasecmp(property, "tablehasvardecimalstorageformat") == 0)
{
result = dealwith_type_status_format(type);
}
else if (pg_strcasecmp(property, "issysshipped") == 0)
{
result = dealwith_type_issysshipped(type, schema_id);
}
else if (pg_strcasecmp(property, "isdeterministic") == 0)
{
result = dealwith_type_dete(type, object_id);
}
else if (pg_strcasecmp(property, "isprocedure") == 0)
{
result = dealwith_type_procedure(type);
}
else if (pg_strcasecmp(property, "istable") == 0)
{
result = dealwith_type_table(type);
}
else if (pg_strcasecmp(property, "isview") == 0)
{
result = dealwith_type_view(type);
}
else if (pg_strcasecmp(property, "isusertable") == 0)
{
result = dealwith_type_usertable(type, schema_id);
}
else if (pg_strcasecmp(property, "istablefunction") == 0)
{
result = dealwith_type_tablefunc(type);
}
else if (pg_strcasecmp(property, "isinlinefunction") == 0)
{
result = dealwith_type_inlinefunc(type);
}
else if (pg_strcasecmp(property, "isscalarfunction") == 0)
{
result = dealwith_type_scalarfunc(type);
}
else if (pg_strcasecmp(property, "isprimarykey") == 0)
{
result = dealwith_type_pk(type);
}
else if (pg_strcasecmp(property, "isindexed") == 0)
{
result = dealwith_type_indexed(type, object_id);
}
else if (pg_strcasecmp(property, "isdefault") == 0)
{
* Currently hardcoded to 0.
*/
return 0;
}
else if (pg_strcasecmp(property, "isrule") == 0)
{
* Currently hardcoded to 0.
*/
return 0;
}
else if (pg_strcasecmp(property, "istrigger") == 0)
{
result = dealwith_type_trigger(type);
}
return result;
}
static bool is_shared_schema(const char *name)
{
if (strcmp("sys", name) == 0)
return true;
else if ((strcmp("public", name) == 0)
|| (strcmp("pg_catalog", name) == 0)
|| (strcmp("pg_toast", name) == 0)
|| (strcmp("information_schema", name) == 0))
return true;
else
return false;
}
char* GetPhysicalSchemaName(char* dbName, const char* schemaName)
{
char* name;
int len;
errno_t errorno = EOK;
if (!schemaName) {
return nullptr;
}
len = strlen(schemaName);
if (len == 0) {
return nullptr;
}
if ((get_database_oid(dbName, true)) == InvalidOid) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist. Make sure that the name is entered correctly.", dbName)));
}
if (len >= NAMEDATALEN) {
ereport(ERROR, (errcode(ERRCODE_NAME_TOO_LONG), errmsg("type name too long"),
errdetail("schema name should be less the %d letters.", NAMEDATALEN)));
u_sess->plsql_cxt.have_error = true;
}
name = static_cast<char*>(palloc0(len + 1));
errorno = strncpy_s(name, len + 1, schemaName, len);
securec_check(errorno, "\0", "\0");
if (is_shared_schema(name)) {
return name;
}
* Parser guarantees identifier will always be truncated to 64B. Schema
* name that comes from other source (e.g scheam_id function) needs one
* more truncate function call
*/
truncate_identifier(name, strlen(name), false);
return name;
}
* tsql_get_proc_nsp_oid
* Given Oid of pg_proc entry return namespace_oid
* Returns InvalidOid if Oid is not found
*/
Oid
tsql_get_proc_nsp_oid(Oid object_id)
{
Oid namespace_oid = InvalidOid;
HeapTuple tuple;
bool isnull;
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple))
{
(void) SysCacheGetAttr(PROCOID, tuple,
Anum_pg_proc_pronamespace,
&isnull);
if (!isnull)
{
Form_pg_proc proc = (Form_pg_proc) GETSTRUCT(tuple);
namespace_oid = proc->pronamespace;
}
ReleaseSysCache(tuple);
}
return namespace_oid;
}
* tsql_get_constraint_nsp_oid
* Given Oid of pg_constraint entry return namespace_oid
* Returns InvalidOid if Oid is not found
*/
Oid
tsql_get_constraint_nsp_oid(Oid object_id, Oid user_id)
{
Oid namespace_oid = InvalidOid;
HeapTuple tuple;
bool isnull;
tuple = SearchSysCache1(CONSTROID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple))
{
(void) SysCacheGetAttr(CONSTROID, tuple,
Anum_pg_constraint_connamespace,
&isnull);
if (!isnull)
{
Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);
if (OidIsValid(HeapTupleGetOid(tuple)))
{
* user should have permission of table associated with
* constraint
*/
if (OidIsValid(con->conrelid))
{
if (pg_class_aclcheck(con->conrelid, user_id, ACL_SELECT) == ACLCHECK_OK)
namespace_oid = con->connamespace;
}
}
}
ReleaseSysCache(tuple);
}
return namespace_oid;
}
static char* GetCurrentPhysicalSchemaName(char* schemaName)
{
char* curDbName;
char* ret;
if (strlen(schemaName) < 1) {
return nullptr;
}
curDbName = get_and_check_db_name(u_sess->proc_cxt.MyDatabaseId, true);
ret = GetPhysicalSchemaName(curDbName, schemaName);
return ret;
}
static inline int dealwith_type_ownerid(int type, Oid schema_id)
{
* Search for schema_id in pg_namespace catalog. Return nspowner from
* the found pg_namespace object.
*/
if (OidIsValid(schema_id)) {
HeapTuple tp;
int result;
tp = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(schema_id));
if (HeapTupleIsValid(tp)) {
Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
result = ((int) nsptup->nspowner);
ReleaseSysCache(tp);
return result;
}
}
return -1;
}
static inline int dealwith_type_defcnst(int type)
{
* The type of the object should be OBJECT_TYPE_DEFAULT_CONSTRAINT.
*/
if (type == OBJECT_TYPE_DEFAULT_CONSTRAINT)
{
return 1;
}
return 0;
}
static inline int dealwith_type_exec_bound(int type, char* property)
{
* These properties are only applicable to OBJECT_TYPE_TSQL_STORED_PROCEDURE, OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE,
* OBJECT_TYPE_VIEW, OBJECT_TYPE_TSQL_DML_TRIGGER, OBJECT_TYPE_TSQL_SCALAR_FUNCTION, OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION,
* OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION and OBJECT_TYPE_RULE.
* Hence, return NULL if the object is not from the above types.
*/
if (!(type == OBJECT_TYPE_TSQL_STORED_PROCEDURE || type == OBJECT_TYPE_REPLICATION_FILTER_PROCEDURE ||
type == OBJECT_TYPE_VIEW || type == OBJECT_TYPE_TSQL_DML_TRIGGER || type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION ||
type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION ||
type == OBJECT_TYPE_RULE))
{
return -1;
}
* Currently, for IsSchemaBound property, we have hardcoded the value to 0
*/
if (pg_strcasecmp(property, "isschemabound") == 0)
{
return 0;
}
* For ExecIsQuotedIdentOn and ExecIsAnsiNullsOn, we hardcoded it to 1
*/
return 1;
}
static inline int dealwith_type_status_format(int type)
{
* Currently, we have hardcoded the return value to 0.
*/
if (type == OBJECT_TYPE_TABLE)
{
return 0;
}
* These properties are only applicable if the type of the object is TABLE,
* Hence, return NULL if the object is not a TABLE.
*/
return -1;
}
static inline int dealwith_type_issysshipped(int type, Oid schema_id)
{
* Check whether the object is MS shipped. We are using is_ms_shipped helper function
* to check the same.
*/
char* schema_name = get_namespace_name(schema_id);
if (pg_strcasecmp(schema_name, "sys") == 0)
{
return 1;
}
return 0;
}
static inline int dealwith_type_dete(int type, Oid object_id)
{
int result;
if (type == OBJECT_TYPE_AGGREGATE_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION ||
type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION ||
type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION){
HeapTuple tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(object_id));
if (HeapTupleIsValid(tuple)){
Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(tuple);
result = procform->provolatile == 'i' ? 1 : 0;
ReleaseSysCache(tuple);
return result;
}
}
return -1;
}
static inline int dealwith_type_procedure(int type)
{
* Check whether the type of the object is OBJECT_TYPE_TSQL_STORED_PROCEDURE.
*/
if (type == OBJECT_TYPE_TSQL_STORED_PROCEDURE)
{
return 1;
}
return 0;
}
static inline int dealwith_type_table(int type)
{
* The type of the object should be OBJECT_TYPE_INTERNAL_TABLE or
* TABLE or OBJECT_TYPE_SYSTEM_BASE_TABLE.
*/
if (type == OBJECT_TYPE_INTERNAL_TABLE ||
type == OBJECT_TYPE_TABLE || type == OBJECT_TYPE_SYSTEM_BASE_TABLE)
{
return 1;
}
return 0;
}
static inline int dealwith_type_view(int type)
{
* The type of the object should be OBJECT_TYPE_VIEW.
*/
if (type == OBJECT_TYPE_VIEW)
{
PG_RETURN_INT32(1);
}
PG_RETURN_INT32(0);
}
static inline int dealwith_type_usertable(int type, Oid schema_id)
{
* The object should be of the type TABLE.
*/
char* schema_name = get_namespace_name(schema_id);
if (type == OBJECT_TYPE_TABLE && pg_strcasecmp(schema_name, "sys") == 0)
{
return 1;
}
return 0;
}
static inline int dealwith_type_tablefunc(int type)
{
* The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION or OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION
* OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION.
*/
if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION || type == OBJECT_TYPE_TSQL_TABLE_VALUED_FUNCTION ||
type == OBJECT_TYPE_ASSEMBLY_TABLE_VALUED_FUNCTION)
{
return 1;
}
return 0;
}
static inline int dealwith_type_inlinefunc(int type)
{
* The object should be OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION.
*/
if (type == OBJECT_TYPE_TSQL_INLINE_TABLE_VALUED_FUNCTION)
{
return 1;
}
return 0;
}
static inline int dealwith_type_scalarfunc(int type)
{
* The object should be either OBJECT_TYPE_TSQL_SCALAR_FUNCTION or OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION.
*/
if (type == OBJECT_TYPE_TSQL_SCALAR_FUNCTION || type == OBJECT_TYPE_ASSEMBLY_SCALAR_FUNCTION)
{
return 1;
}
return 0;
}
static inline int dealwith_type_pk(int type)
{
* The object should be a OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT.
*/
if (type == OBJECT_TYPE_PRIMARY_KEY_CONSTRAINT)
{
return 1;
}
return 0;
}
static inline int dealwith_type_indexed(int type, Oid object_id)
{
* Search for object_id in pg_index catalog by indrelid column.
* The object is indexed if the entry exists in pg_index.
*/
Relation indRel;
ScanKeyData key;
SysScanDesc scan;
HeapTuple tup;
if (type != OBJECT_TYPE_TABLE && type != OBJECT_TYPE_MATERIALIZED_VIEW)
return 0;
indRel = table_open(IndexRelationId, RowExclusiveLock);
ScanKeyInit(&key,
Anum_pg_index_indrelid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(object_id));
scan = systable_beginscan(indRel, IndexIndrelidIndexId, true,
NULL, 1, &key);
if (HeapTupleIsValid(tup = systable_getnext(scan)))
{
systable_endscan(scan);
table_close(indRel, RowExclusiveLock);
return 1;
}
systable_endscan(scan);
table_close(indRel, RowExclusiveLock);
return 0;
}
static inline int dealwith_type_trigger(int type)
{
* The type of the object should be OBJECT_TYPE_ASSEMBLY_DML_TRIGGER.
*/
if (type == OBJECT_TYPE_ASSEMBLY_DML_TRIGGER)
{
PG_RETURN_INT32(1);
}
PG_RETURN_INT32(0);
}