openGauss碰到的坑以及解决方法

0
分享 2023-12-27

下载地址以及编译方法
https://gitee.com/opengauss
postgis for opengauss下载地址以及编译方法
openGauss-third_party: openGauss third party libraries - Gitee.com
编译注意的问题
按照官网上步骤安装postgis是可以的,但是装好之后create extension postgis会报autonomous transaction failed to create autonomous session 错误,原因就是默认无法免密登录。
为啥要免密登录呢,主要是opengauss会针对每个创建的plpgsql在plpgsql_validator函数中进行验证的过程中会InsertGsSource,将plpgsql 的源码记录到opengauss的系统表中, 这个过程走的是declare autonomous transaction,因此要走AttachSession函数,后面的就不在描述了。
当然这个InsertGsSource可以通过设置behavior_compat_options= 'skip_insert_gs_source'参数忽略。
1. 由于opengauss只有初始用户并且初始用户名字为运行openguass的操作系统名字才可以免密
控制这个的代码位置在(以3.0.2为例):
hba.cpp的check_hba函数中控制
if (hba->conntype == ctLocal) {
/*
* For initdb user, we should check if the connection request from
* the installation enviroment.
*/
if (roleid == INITIAL_USER_ID) {
uid_t uid = 0;
gid_t gid = 0;
/* get the user id of the system, where client in */
if (getpeereid(port->sock, &uid, &gid) != 0) {
pfree_ext(hba);
/* Provide special error message if getpeereid is a stub */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Could not get user information on this platform")));
}

/*
* For connections from another coordinator, we could not
* get the userid. This case may also exist for other cases,
* like tools. (Usually happed when login with -h localhost
* or 127.0.0.1)
*/
if ((long)uid == USER_NULL_MASK) {
continue;
}
/*
* If the system username equals to the database username, continue
* the authorization without checking the usermap. If not, we should
* pay attentation to 'lateral ultra vires', which means, password is
* needed when login in in the non-installation enviroment under the
* same system user group.
*/
isUsernameSame= IsSysUsernameSameToDB(uid, port->user_name);
if (!isUsernameSame && hba->auth_method == uaTrust) {
hba->auth_method = get_default_auth_method(port->user_name);
}

可以通过注释掉hba->auth_method = get_default_auth_method(port->user_name)来越过这个难问题。
(不加localhost的免密,+localhost或者127.0.0.1也无法免密)
2. localhost或者127.0.0.1 无法免密登录,导致create extension 创建失败,原因是创建扩展的语句会让gaussdb后台调用pqconnect函数链接数据库,失败的位置为
autonomoustransaction.cpp::AttachSession
void AutonomousSession::AttachSession(void)
{
if (m_conn != NULL) { // create session alike singleton
return;
}

/* create a connection info with current database info */
char connInfo[MAX_CONNINFO_SIZE];
char userName[NAMEDATALEN];
const char* dbName = get_database_name(u_sess->proc_cxt.MyDatabaseId);
if (dbName == NULL) {
ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database with OID %u does not exist",
u_sess->proc_cxt.MyDatabaseId)));
}

errno_t ret = snprintf_s(connInfo, sizeof(connInfo), sizeof(connInfo) - 1,
"dbname=%s port=%d host='localhost' application_name='autonomoustransaction' user=%s",
dbName, g_instance.attr.attr_network.PostPortNumber,
(char*)GetSuperUserName((char*)userName));
securec_check_ss_c(ret, "\0", "\0");

/* do the actual create session */
bool old = t_thrd.int_cxt.ImmediateInterruptOK;
t_thrd.int_cxt.ImmediateInterruptOK = true;
/* Allow cancel/die interrupts */
CHECK_FOR_INTERRUPTS();
AddSessionCount();
m_conn = PQconnectdb(connInfo);
PQsetNoticeProcessor(m_conn, ProcessorNotice, NULL);
t_thrd.int_cxt.ImmediateInterruptOK = old;

if (PQstatus(m_conn) != CONNECTION_OK) {
ereport(ERROR, (errcode(ERRCODE_PLPGSQL_ERROR),
errmsg("autonomous transaction failed to create autonomous session"),
errdetail("%s", PQerrorMessage(m_conn))));
}
}

当然可以通过把host='localhost'去掉来越过这个问题。
还有另外一个方法,就是用pgpassword机制来解决免密功能,默认pgpassword使用的是$HOME/.pgpas文件,其内容如下
其格式如下
hostname:port:database:username:password 
localhost:15432:postgres:postgres:Esri@123
其中database地方必须是具体的库名,不支持all写法
但是opengauss3.0.2默认编译还不支持pgpassword 功能,需要启用SUPPORT_PGPASSFILE 预编译条件控制
可以用一下语句把该编译条件打开
./configure --prefix=/home/opengauss_302/opengGauss-server/dest --gcc-version=7.3.0 CC=g++ CFLAS='-O0'  --3rd=/home/opengauss_302/binarylibs --enable-debug   --enable-thread-safety  --without-readline --without-zlib --with-libxml CPPFLAGS="-DSUPPORT_PGPASSFILE"
由于3.0.2可能没有测试这部分代码,这部分代码还有编译错误,位置为

fe-connect.cpp:getPgPassFilename
static bool getPgPassFilename(char* pgpassfile)
{
char* passfile_env = gs_getenv_r("PGPASSFILE");

if (check_client_env(passfile_env) != NULL
/* use the literal path from the environment, if set */
check_strncpy_s(strncpy_s(pgpassfile, MAXPGPATH, passfile_env, strlen(passfile_env)));
else {
char homedir[MAXPGPATH];

if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
return false;
check_sprintf_s(sprintf_s(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE));
}
return true;
}

修改成

static bool getPgPassFilename(char* pgpassfile)
{
char* passfile_env = gs_getenv_r("PGPASSFILE");

if (check_client_env(passfile_env) != NULL)
{
/* use the literal path from the environment, if set */
check_strncpy_s(strncpy_s(pgpassfile, MAXPGPATH, passfile_env, strlen(passfile_env)));
}
else {
char homedir[MAXPGPATH];

if (!pqGetHomeDirectory(homedir, sizeof(homedir)))
return false;
check_sprintf_s(sprintf_s(pgpassfile, MAXPGPATH, "%s/%s", homedir, PGPASSFILE));
}
return true;
}

否则有编译错误,但是修改后,可以正常运行。
 
编译postgis的坑
为啥初始话用户非要免密登录呢,因为创建function和extension的时候后台会以初始话用户执行AttachSession函数登录后创建,如果不能免密登录,AttachSession会登录失败,然后就没有然后了。
编译postgis基本上按照链接上编译就可以了
但是编译postgis的时候需要将instrument 文件夹拷贝一份到dest/include/postgresql/server目录中一份,要不然会报找不到头文件的错误。
另外编译5.0.0版本上的postgis需要提前安装
yum install libtool-ltdl-devel ,否则编译gdal的时候会提示找不到ltdl.so的错误
坑1:
DECLARE
edit_session_info RECORD;
current_state_id BIGINT;
default_version_set BOOL default FALSE;
C_get_state_id CURSOR FOR
SELECT v.state_id
FROM sde.sde_versions v
WHERE v.name = 'DEFAULT' AND
UPPER(v.owner) = 'SDE';
BEGIN
return 1;
END;

不支持declare cursorname CURSOR FOR|IS 语法(可能是为了兼容oracle吧),其只支持
CURSOR cursorname FOR|IS .  如果要支持上面的语法,需要将/src/common/pl/plpgsql/src/gram.y 中的这部分代码修改成如下内容
坑2:
针对于这种plpgsql会报错
SELECT INTO l_entity (CASE WHEN l_domain_name IS NULL OR
l_domain_name = 'ST_GEOMETRY' THEN 'GEOMETRY'
WHEN l_domain_name = 'ST_GEOMCOLLECTION' THEN 'COLLECTION'
WHEN l_domain_name = 'ST_POINT' THEN 'POINT'
WHEN l_domain_name = 'ST_LINESTRING' THEN 'LINESTRING'
WHEN l_domain_name = 'ST_POLYGON' THEN 'POLYGON'
WHEN l_domain_name = 'ST_MULTIPOINT' THEN 'MULTIPOINT'
WHEN l_domain_name = 'ST_MULTILINESTRING' THEN 'MULTILINESTRING'
WHEN l_domain_name = 'ST_MULTIPOLYGON' THEN 'MULTIPOLYGON'
ELSE NULL
END);
全部函数内容
CREATE OR REPLACE FUNCTION sde.geometry_type(i_schema character varying, i_table_name character varying, i_column_name character varying)
RETURNS text
LANGUAGE plpgsql
AS $function$
DECLARE
l_schema VARCHAR(128) DEFAULT NULL;
l_table VARCHAR(128) DEFAULT NULL;
l_tableName VARCHAR(128) DEFAULT NULL;
l_column VARCHAR(128) DEFAULT NULL;
l_udt_name VARCHAR(128) DEFAULT NULL;
l_domain_name VARCHAR(128) DEFAULT NULL;
l_zm VARCHAR(4) DEFAULT NULL;
l_multi_prefix VARCHAR(6) DEFAULT NULL;
l_result TEXT DEFAULT NULL;
l_entity TEXT DEFAULT NULL;
l_coordDim INTEGER DEFAULT NULL;
l_point BOOL DEFAULT FALSE;
l_line BOOL DEFAULT FALSE;
l_sline BOOL DEFAULT FALSE;
l_poly BOOL DEFAULT FALSE;
l_multi BOOL DEFAULT FALSE;
l_z BOOL DEFAULT FALSE;
l_m BOOL DEFAULT FALSE;
l_has_3d BOOL DEFAULT FALSE;
l_has_measure BOOL DEFAULT FALSE;
l_cad BOOL DEFAULT FALSE;
l_geometry BOOL DEFAULT FALSE;
l_collection BOOL DEFAULT FALSE;
l_is_st_geometry BOOL DEFAULT FALSE;
l_is_pg_geometry BOOL DEFAULT FALSE;
l_is_pg_geography BOOL DEFAULT FALSE;
l_is_empty BOOL DEFAULT FALSE;
SE_OGC_GEOMETRY CONSTANT INTEGER NOT NULL DEFAULT 0;
SE_OGC_POINT CONSTANT INTEGER NOT NULL DEFAULT 1;
SE_OGC_CURVE CONSTANT INTEGER NOT NULL DEFAULT 2;
SE_OGC_LINESTRING CONSTANT INTEGER NOT NULL DEFAULT 3;
SE_OGC_SURFACE CONSTANT INTEGER NOT NULL DEFAULT 4;
SE_OGC_POLYGON CONSTANT INTEGER NOT NULL DEFAULT 5;
SE_OGC_COLLECTION CONSTANT INTEGER NOT NULL DEFAULT 6;
SE_OGC_MULTIPOINT CONSTANT INTEGER NOT NULL DEFAULT 7;
SE_OGC_MULTICURVE CONSTANT INTEGER NOT NULL DEFAULT 8;
SE_OGC_MULTILINESTRING CONSTANT INTEGER NOT NULL DEFAULT 9;
SE_OGC_MULTISURFACE CONSTANT INTEGER NOT NULL DEFAULT 10;
SE_OGC_MULTIPOLYGON CONSTANT INTEGER NOT NULL DEFAULT 11;
BEGIN
IF i_schema IS NULL THEN
l_schema := session_user;
ELSE
l_schema := LOWER(i_schema);
END IF;

l_table := LOWER(i_table_name);
l_column := LOWER(i_column_name);

-- Check if the object is a multiversioned view.

BEGIN
SELECT INTO l_tableName table_name FROM sde.sde_table_registry
WHERE owner = l_schema AND imv_view_name = l_table;
IF FOUND THEN
l_table := l_tableName;
END IF;
EXCEPTION WHEN undefined_table THEN
NULL;
END;

-- Check if the object is registered with geodatabase

BEGIN
SELECT ((a.eflags::bit(32) & (1 << 1)::bit(32)) != 0::bit(32))::BOOL AS has_point,
((a.eflags::bit(32) & (1 << 2)::bit(32)) != 0::bit(32))::BOOL AS has_line,
((a.eflags::bit(32) & (1 << 3)::bit(32)) != 0::bit(32))::BOOL AS has_sline,
((a.eflags::bit(32) & (1 << 4)::bit(32)) != 0::bit(32))::BOOL AS has_poly,
((a.eflags::bit(32) & (1 << 18)::bit(32)) != 0::bit(32))::BOOL AS is_multi,
((a.eflags::bit(32) & (1 << 16)::bit(32)) != 0::bit(32))::BOOL AS is_3d,
((a.eflags::bit(32) & (1 << 19)::bit(32)) != 0::bit(32))::BOOL AS is_measure,
((a.eflags::bit(32) & (1 << 22)::bit(32)) != 0::bit(32))::BOOL AS is_CAD,
((a.eflags::bit(32) & (1 << 26)::bit(32)) != 0::bit(32))::BOOL AS is_ST_Geometry,
((a.eflags::bit(32) & (1 << 27)::bit(32)) != 0::bit(32))::BOOL AS is_PG_Geometry,
((a.eflags::bit(32) & (1 << 15)::bit(32)) != 0::bit(32))::BOOL AS is_PG_Geography
INTO l_point,l_line,l_sline,l_poly,l_multi,l_has_3d,l_has_measure,
l_cad,l_is_st_geometry,l_is_pg_geometry,l_is_pg_geography
FROM sde.sde_layers a
WHERE a.owner = l_schema
AND a.table_name = l_table
AND a.spatial_column = l_column;
EXCEPTION WHEN undefined_table THEN
NULL;
END;
IF FOUND THEN

-- Registered with geodatabase

IF l_is_st_geometry = TRUE THEN
l_udt_name := 'ST_GEOMETRY';
ELSIF l_is_pg_geometry = TRUE THEN
l_udt_name := 'GEOMETRY';
ELSIF l_is_pg_geography = TRUE THEN
l_udt_name := 'GEOGRAPHY';
END IF;

ELSE

-- Not registered with geodatabase

-- Check spatial column storage type

SELECT upper(UDT_NAME), UPPER(DOMAIN_NAME) INTO l_udt_name, l_domain_name
FROM INFORMATION_SCHEMA.COLUMNS
WHERE table_schema = l_schema
AND table_name = l_table
AND column_name = l_column
AND DATA_TYPE = 'USER-DEFINED'
AND (UDT_NAME = 'st_geometry' OR
UDT_NAME = 'geometry' OR
UDT_NAME = 'geography');
IF NOT FOUND THEN
RETURN NULL::TEXT;
END IF;
IF l_udt_name IS NULL THEN
RETURN NULL::TEXT;
END IF;

-- Query column metadata

IF l_udt_name = 'ST_GEOMETRY' THEN

-- Check if column is registered in sde.sde_geometry_columns

SELECT INTO l_entity, l_has_3d, l_has_measure, l_coordDim
(CASE WHEN b.geometry_type = SE_OGC_GEOMETRY THEN 'GEOMETRY'
WHEN b.geometry_type = SE_OGC_COLLECTION THEN 'COLLECTION'
WHEN b.geometry_type = SE_OGC_POINT THEN 'POINT'
WHEN b.geometry_type = SE_OGC_LINESTRING THEN 'LINESTRING'
WHEN b.geometry_type = SE_OGC_POLYGON THEN 'POLYGON'
WHEN b.geometry_type = SE_OGC_MULTIPOINT THEN 'MULTIPOINT'
WHEN b.geometry_type = SE_OGC_MULTILINESTRING THEN 'MULTILINESTRING'
WHEN b.geometry_type = SE_OGC_MULTIPOLYGON THEN 'MULTIPOLYGON'
ELSE NULL
END)::varchar AS geom_type,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.coord_dimension = 3 THEN NULL -- ambiguous Z|M
ELSE FALSE
END)::bool AS is_3d,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.coord_dimension = 3 THEN NULL -- ambiguous Z|M
ELSE FALSE
END)::bool AS is_measure,
coord_dimension
FROM sde.sde_geometry_columns AS b
WHERE f_table_schema = l_schema AND
f_table_name = l_table AND
f_geometry_column = l_column;

IF NOT FOUND THEN

-- Table not registered in sde.sde_geometry_columns - use UDT column metadata

-- Unregistered & unpopulated st_geometry - allow ZM

l_coordDim := 4;
l_has_measure := TRUE;
l_has_3d := TRUE;

SELECT INTO l_entity (CASE WHEN l_domain_name IS NULL OR
l_domain_name = 'ST_GEOMETRY' THEN 'GEOMETRY'
WHEN l_domain_name = 'ST_GEOMCOLLECTION' THEN 'COLLECTION'
WHEN l_domain_name = 'ST_POINT' THEN 'POINT'
WHEN l_domain_name = 'ST_LINESTRING' THEN 'LINESTRING'
WHEN l_domain_name = 'ST_POLYGON' THEN 'POLYGON'
WHEN l_domain_name = 'ST_MULTIPOINT' THEN 'MULTIPOINT'
WHEN l_domain_name = 'ST_MULTILINESTRING' THEN 'MULTILINESTRING'
WHEN l_domain_name = 'ST_MULTIPOLYGON' THEN 'MULTIPOLYGON'
ELSE NULL
END);

END IF;

ELSIF l_udt_name = 'GEOMETRY' THEN

SELECT INTO l_entity, l_has_3d, l_has_measure, l_coordDim
(CASE WHEN b.type = 'GEOMETRY' THEN 'GEOMETRY'
WHEN b.type = 'GEOMETRYCOLLECTION' THEN 'COLLECTION'
WHEN b.type = 'POINT' THEN 'POINT'
WHEN b.type = 'LINESTRING' THEN 'LINESTRING'
WHEN b.type = 'POLYGON' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINT' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRING' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGON' THEN 'MULTIPOLYGON'
WHEN b.type = 'GEOMETRYCOLLECTIONM' THEN 'COLLECTION'
WHEN b.type = 'POINTM' THEN 'POINT'
WHEN b.type = 'LINESTRINGM' THEN 'LINESTRING'
WHEN b.type = 'POLYGONM' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINTM' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRINGM' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGONM' THEN 'MULTIPOLYGON'
ELSE NULL
END)::varchar AS geom_type,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.coord_dimension = 3 AND (
b.type = 'GEOMETRY' OR
b.type = 'GEOMETRYCOLLECTION' OR
b.type = 'POINT' OR
b.type = 'LINESTRING' OR
b.type = 'POLYGON' OR
b.type = 'MULTIPOINT' OR
b.type = 'MULTILINESTRING' OR
b.type = 'MULTIPOLYGON'
) THEN TRUE
ELSE FALSE
END)::bool AS is_3d,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.type = 'GEOMETRYCOLLECTIONM' THEN TRUE
WHEN b.type = 'POINTM' THEN TRUE
WHEN b.type = 'LINESTRINGM' THEN TRUE
WHEN b.type = 'POLYGONM' THEN TRUE
WHEN b.type = 'MULTIPOINTM' THEN TRUE
WHEN b.type = 'MULTILINESTRINGM' THEN TRUE
WHEN b.type = 'MULTIPOLYGONM' THEN TRUE
ELSE FALSE
END)::bool AS is_measure,
coord_dimension
FROM geometry_columns AS b
WHERE f_table_schema = l_schema AND
f_table_name = l_table AND
f_geometry_column = l_column;
IF NOT FOUND THEN
-- Table not registered in GEOMETRY_COLUMNS - incomplete type setup

RETURN NULL::TEXT;

END IF;

ELSIF l_udt_name = 'GEOGRAPHY' THEN

SELECT INTO l_entity, l_has_3d, l_has_measure, l_coordDim
(CASE WHEN b.type = 'GEOMETRY' THEN 'GEOMETRY'
WHEN b.type = 'GEOMETRYCOLLECTION' THEN 'COLLECTION'
WHEN b.type = 'POINT' THEN 'POINT'
WHEN b.type = 'LINESTRING' THEN 'LINESTRING'
WHEN b.type = 'POLYGON' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINT' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRING' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGON' THEN 'MULTIPOLYGON'
WHEN b.type = 'GEOMETRYM' THEN 'GEOMETRY'
WHEN b.type = 'GEOMETRYCOLLECTIONM' THEN 'COLLECTION'
WHEN b.type = 'POINTM' THEN 'POINT'
WHEN b.type = 'LINESTRINGM' THEN 'LINESTRING'
WHEN b.type = 'POLYGONM' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINTM' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRINGM' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGONM' THEN 'MULTIPOLYGON'
WHEN b.type = 'POINTZ' THEN 'POINT'
WHEN b.type = 'GEOMETRYZ' THEN 'GEOMETRY'
WHEN b.type = 'GEOMETRYCOLLECTIONZ' THEN 'COLLECTION'
WHEN b.type = 'LINESTRINGZ' THEN 'LINESTRING'
WHEN b.type = 'POLYGONZ' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINTZ' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRINGZ' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGONZ' THEN 'MULTIPOLYGON'
WHEN b.type = 'GEOMETRYZM' THEN 'GEOMETRY'
WHEN b.type = 'GEOMETRYCOLLECTIONZM' THEN 'COLLECTION'
WHEN b.type = 'POINTZM' THEN 'POINT'
WHEN b.type = 'LINESTRINGZM' THEN 'LINESTRING'
WHEN b.type = 'POLYGONZM' THEN 'POLYGON'
WHEN b.type = 'MULTIPOINTZM' THEN 'MULTIPOINT'
WHEN b.type = 'MULTILINESTRINGZM' THEN 'MULTILINESTRING'
WHEN b.type = 'MULTIPOLYGONZM' THEN 'MULTIPOLYGON'
ELSE NULL
END)::varchar AS geom_type,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.coord_dimension = 3 AND (
b.type = 'GEOMETRY' OR
b.type = 'GEOMETRYCOLLECTION' OR
b.type = 'POINT' OR
b.type = 'LINESTRING' OR
b.type = 'POLYGON' OR
b.type = 'MULTIPOINT' OR
b.type = 'MULTILINESTRING' OR
b.type = 'MULTIPOLYGON' OR
b.type = 'GEOMETRYZ' OR
b.type = 'GEOMETRYCOLLECTIONZ' OR
b.type = 'POINTZ' OR
b.type = 'LINESTRINGZ' OR
b.type = 'POLYGONZ' OR
b.type = 'MULTIPOINTZ' OR
b.type = 'MULTILINESTRINGZ' OR
b.type = 'MULTIPOLYGONZ'
) THEN TRUE
ELSE FALSE
END)::bool AS is_3d,
(CASE WHEN b.coord_dimension = 4 THEN TRUE
WHEN b.type = 'GEOMETRYM' THEN TRUE
WHEN b.type = 'GEOMETRYCOLLECTIONM' THEN TRUE
WHEN b.type = 'POINTM' THEN TRUE
WHEN b.type = 'LINESTRINGM' THEN TRUE
WHEN b.type = 'POLYGONM' THEN TRUE
WHEN b.type = 'MULTIPOINTM' THEN TRUE
WHEN b.type = 'MULTILINESTRINGM' THEN TRUE
WHEN b.type = 'MULTIPOLYGONM' THEN TRUE
ELSE FALSE
END)::bool AS is_measure,
b.coord_dimension
FROM ( SELECT UPPER(type) AS type, coord_dimension
FROM geography_columns
WHERE f_table_schema = l_schema AND
f_table_name = l_table AND
f_geography_column = l_column) AS b;
IF NOT FOUND THEN
-- Geography type column does not exist
RETURN NULL::TEXT;
END IF;

END IF;

END IF;

-- Assemble type string

IF l_entity = 'GEOMETRY' THEN
l_geometry := TRUE;
ELSIF l_entity = 'COLLECTION' THEN
l_collection := TRUE;
ELSIF l_entity = 'POINT' THEN
l_point := TRUE;
ELSIF l_entity = 'LINESTRING' THEN
l_line := TRUE;
ELSIF l_entity = 'POLYGON' THEN
l_poly := TRUE;
ELSIF l_entity = 'MULTIPOINT' THEN
l_multi := TRUE;
l_point := TRUE;
ELSIF l_entity = 'MULTILINESTRING' THEN
l_multi := TRUE;
l_line := TRUE;
ELSIF l_entity = 'MULTIPOLYGON' THEN
l_multi := TRUE;
l_poly := TRUE;
END IF;

IF l_point = FALSE AND l_poly = FALSE AND l_line = FALSE AND l_sline = FALSE THEN
l_is_empty := TRUE;
END IF;

IF l_coordDim = 3 THEN
IF l_has_measure IS NULL AND l_has_3d IS NULL THEN
-- st_geometry 3d coord_dimension without any other context is ambiguous - for now, assume Z
l_zm := ' Z ';
ELSIF l_has_measure THEN
l_zm := ' M ';
ELSIF l_has_3d THEN
l_zm := ' Z ';
END IF;
ELSIF l_coordDim = 4 THEN
l_zm := ' ZM ';
ELSE
l_zm := ' ';
END IF;

IF l_multi = TRUE THEN
l_multi_prefix := 'MULTI';
ELSE
l_multi_prefix := '';
END IF;

IF l_is_empty = TRUE THEN
-- Registered with geodatabase, but no layer type eflags
l_result := 'EMPTY';
ELSIF l_collection = TRUE THEN
l_result := 'COLLECTION' || l_zm;
ELSIF l_geometry = TRUE THEN
-- Return all types
l_result := 'POINT' || l_zm;
l_result := l_result || 'LINESTRING' || l_zm;
l_result := l_result || 'POLYGON' || l_zm;
l_result := l_result || 'MULTIPOINT' || l_zm;
l_result := l_result || 'MULTILINESTRING' || l_zm;
l_result := l_result || 'MULTIPOLYGON' || l_zm;
ELSE
l_result := '';
IF l_point THEN
l_result := l_result || l_multi_prefix || 'POINT' || l_zm;
END IF;
IF l_sline OR l_line THEN
l_result := l_result || l_multi_prefix || 'LINESTRING' || l_zm;
END IF;
IF l_poly THEN
l_result := l_result || l_multi_prefix || 'POLYGON' || l_zm;
END IF;
END IF;

RETURN trim(both l_result);
END;
$function$

openGauss会把l_entity ( 当成array类型的var进行处理,然后把后面的所有内容当成array var消耗掉 
opengauss的plpgsql的gram.y中的read_into_array_table_scalar_list函数会到else分支,因此报错
read_into_array_table_scalar_list(char *initial_name,
PLpgSQL_datum *initial_datum,
int initial_dno,
int initial_location,
bool bulk_collect)
{
int nfields = 0;
char *fieldnames[1024] = {NULL};
int varnos[1024] = {0};
PLpgSQL_row *row;
int tok;
int toktmp = 0;
int tmpdno = 0;
int type_flag = -1;
bool isarrayelem = false;
char* nextname = NULL;

check_assignable(initial_datum, initial_location);

tmpdno = initial_dno;
tok = yylex();
get_datum_tok_type(initial_datum, &type_flag);

if (type_flag == PLPGSQL_TOK_TABLE_VAR) {
isarrayelem = read_into_using_add_tableelem(fieldnames, varnos, &nfields, tmpdno, &tok);
} else{
isarrayelem = read_into_using_add_arrayelem(fieldnames, varnos, &nfields, tmpdno, &tok);
}
.......
}
需要修改成如下内容
read_into_array_table_scalar_list(char *initial_name,
PLpgSQL_datum *initial_datum,
int initial_dno,
int initial_location,
bool bulk_collect)
{
int nfields = 0;
char *fieldnames[1024] = {NULL};
int varnos[1024] = {0};
PLpgSQL_row *row;
int tok;
int toktmp = 0;
int tmpdno = 0;
int type_flag = -1;
bool isarrayelem = false;
char* nextname = NULL;

check_assignable(initial_datum, initial_location);

tmpdno = initial_dno;
tok = yylex();
get_datum_tok_type(initial_datum, &type_flag);

if (type_flag == PLPGSQL_TOK_TABLE_VAR) {
isarrayelem = read_into_using_add_tableelem(fieldnames, varnos, &nfields, tmpdno, &tok);
} else if(type_flag == PLPGSQL_TOK_VARRAY_VAR) {
isarrayelem = read_into_using_add_arrayelem(fieldnames, varnos, &nfields, tmpdno, &tok);
}
else
{
}
 坑3:

存储过程执行报return no rows错误

具体测试过程如下:
CREATE TABLE sde.sde_states (
state_id serial NOT NULL,
owner character varying(128) NOT NULL,
creation_time timestamp without time zone NOT NULL,
closing_time timestamp without time zone,
parent_state_id bigint NOT NULL,
lineage_name bigint NOT NULL
);

CREATE TABLE sde.sde_versions (
name character varying(64) NOT NULL,
owner character varying(128) NOT NULL,
version_id integer NOT NULL,
status integer NOT NULL,
state_id bigint NOT NULL,
description character varying(65),
parent_name character varying(64),
parent_owner character varying(128),
parent_version_id integer,
creation_time timestamp without time zone NOT NULL
);

CREATE TABLE sde.sde_state_lineages (
lineage_name bigint NOT NULL,
lineage_id bigint NOT NULL
);

CREATE OR REPLACE FUNCTION sde.sde_state_def_insert(stateidval bigint, schemaval character varying, pstateidval bigint, plineagenameval bigint, sdeidval integer, openorcloseval integer)
RETURNS bigint
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
DECLARE
newStateIdVal BIGINT;
selStateIdVal BIGINT;
new_lineage_name BIGINT;
crTimeVal TIMESTAMP;
clTimeVal TIMESTAMP;
BEGIN
new_lineage_name := pLineageNameVal;
Select to_char(CURRENT_TIMESTAMP,'YYYY-MM-DD HH24:MI:SS') INTO crTimeVal;
-- close state
IF OpenOrCloseVal = 2 THEN
clTimeVal := crTimeVal;
ELSE
clTimeVal := NULL;
END IF;

-- Generate next state_id.
SELECT INTO newStateIdVal nextval('sde.sde_states_state_id_seq');

-- Check to see if we need to create a new lineage.
SELECT INTO selStateIdVal state_id FROM sde.sde_states
WHERE parent_state_id = pStateIdVal
AND lineage_name = pLineageNameVal;
IF NOT FOUND THEN
-- Insert new state into existing lineage.

INSERT INTO sde.sde_states (state_id, owner, creation_time,
closing_time, parent_state_id, lineage_name)
VALUES (newStateIdVal, LOWER(schemaVal), crTimeVal,
clTimeVal, pStateIdVal, pLineageNameVal);
ELSE
-- Parent state & lineage exist - split off a new lineage.

new_lineage_name := newStateIdVal;
INSERT INTO sde.sde_states (state_id, owner, creation_time,
closing_time, parent_state_id, lineage_name)
VALUES (newStateIdVal, LOWER(schemaVal), crTimeVal,
clTimeVal, pStateIdVal, new_lineage_name);
END IF;

-- If we created a new lineage, insert it into the STATE_LINEAGE
-- table in normalized form.
IF new_lineage_name != pLineageNameVal THEN
INSERT INTO sde.sde_state_lineages
SELECT new_lineage_name, l.lineage_id FROM sde.sde_state_lineages l
WHERE l.lineage_name = pLineageNameVal
AND l.lineage_id <= pStateIdVal;
END IF;

-- We also insert a row for this state, as if it were in its own
-- state lineage.

INSERT INTO sde.sde_state_lineages (lineage_name, lineage_id)
VALUES (new_lineage_name, newStateIdVal);

-- Place a mark on the new state so that it does not get cleaned up
-- by compress. Do it before the commit so it will never be both
-- visible and unmarked at the same time.

PERFORM sde.SDE_state_lock_def_insert(sdeIdVal, newStateIdVal, 'Y', 'M');

RETURN newStateIdVal;
END;
$function$

Select sde_state_def_insert(0,’sde’,1,1,15,1);

原因:
gram.y
read_into_target(PLpgSQL_variable **target, bool *strict)
{
int tok;

/* Set default results */
*target = NULL;
if (strict)
*strict = false;

tok = yylex();
if (strict && tok == K_STRICT)
{
*strict = true;
tok = yylex();
}

该函数默认将strict设置为true,这点跟PostgreSQL不一样。需要和PostgreSQL一致,修改成false

这么为啥这么设计,那还要select into strict 语法干啥呢。。。。
pl_exec.cpp
make_execsql_stmt
if (stmt->into) {
if (!stmt->mod_stmt & !stmt->bulk_collect) {
stmt->strict = true;
}

if (stmt->bulk_collect) {
tcount = 0;
} else if (stmt->strict || stmt->mod_stmt) {
tcount = 2;
} else {
tcount = 1;
}
} else {
tcount = 0;
}

上述代码默认将select into 设置成strict=true了,也需要修改过来

该问题在openGauss5.0通过behavior_compat_options=‘select_into_return_null' 参数进行修复,具体可以查看
增加select_into_return_null选项,在存储过程的select into场景,没有行的时候返回NULL · Pull Request !3071 · openGauss/openGauss-server - Gitee.com
坑4:
WHERE CURRENT OF clause not yet supported
"UPDATE sde.i8 SET base_id = base_id + 400, last_id = 1 WHERE CURRENT OF
这部分代码在
src/gausskernel/runtime/executor/nodeTidscan.cpp

static TupleTableSlot* TidFetchTuple(TidScanState* node, bool b_backward, Relation heap_relation)
{
int num_tids = node->tss_NumTids;
ItemPointerData* tid_list = node->tss_TidList;
Snapshot scanSnap;
TupleTableSlot* slot = node->ss.ss_ScanTupleSlot;

/*
* Choose user-specified snapshot if TimeCapsule clause exists, otherwise
* estate->es_snapshot instead.
*/
scanSnap = TvChooseScanSnap(heap_relation, (Scan *)node->ss.ps.plan, &node->ss);

InitTidPtr(node, b_backward);
while (node->tss_TidPtr >= 0 && node->tss_TidPtr < num_tids) {
ItemPointerData tid = tid_list[node->tss_TidPtr];

/* WHERE CURRENT OF is disabled at transformCurrentOfExpr, so no need to support it here. */
Assert (node->tss_isCurrentOf == false);
if (node->tss_isCurrentOf) {
ereport(ERROR, (errcode(ERRCODE_STATEMENT_TOO_COMPLEX),
(errmsg("WHERE CURRENT OF clause not yet supported"))));
}

if (tableam_tops_tuple_fetch_row_version(node, heap_relation, &tid, scanSnap, slot)) {
return slot;
}

/* Bad TID or failed snapshot qual; try next */
Move
}


src/common/backend/parser/parse_expr.cpp

static Node* transformCurrentOfExpr(ParseState* pstate, CurrentOfExpr* cexpr)
{
int sublevels_up;

#ifdef PGXC
ereport(ERROR, (errcode(ERRCODE_STATEMENT_TOO_COMPLEX), (errmsg("WHERE CURRENT OF clause not yet supported"))));
#endif

/* CURRENT OF can only appear at top level of UPDATE/DELETE */
AssertEreport(pstate->p_target_rangetblentry != NULL, MOD_OPT, "");
cexpr->cvarno = RTERangeTablePosn(pstate, pstate->p_target_rangetblentry, &sublevels_up);
AssertEreport(sublevels_up == 0, MOD_OPT, "");
。。。。
}
坑5:

存储过程中调用过程中找不到public下的sequence

脚本如下:

CREATE TABLE public.sde_spatial_references (
srid integer NOT NULL,
sr_name character varying(128),
description character varying(256),
falsex numeric NOT NULL,
falsey numeric NOT NULL,
xyunits numeric NOT NULL,
falsez numeric NOT NULL,
zunits numeric NOT NULL,
falsem numeric NOT NULL,
munits numeric NOT NULL,
xycluster_tol numeric,
zcluster_tol numeric,
mcluster_tol numeric,
object_flags integer DEFAULT 1 NOT NULL,
srtext character varying(1024) NOT NULL,
min_x numeric,
min_y numeric,
min_z numeric,
min_m numeric,
max_x numeric,
max_y numeric,
max_z numeric,
max_m numeric,
cs_id integer,
cs_name character varying(128),
cs_type character varying(128),
organization character varying(128),
org_coordsys_id integer,
CONSTRAINT spatial_ref_xyunits CHECK ((xyunits >= (1)::numeric)),
CONSTRAINT spatial_ref_zunits CHECK ((zunits >= (1)::numeric))
);


ALTER TABLE public.sde_spatial_references OWNER TO sde;

CREATE SEQUENCE public.sde_spatial_references_srid_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;


ALTER TABLE public.sde_spatial_references_srid_seq OWNER TO sde;

CREATE OR REPLACE FUNCTION sde.sde_sref_def_insert(i_srid integer, i_falsex numeric, i_falsey numeric, i_xyunits numeric, i_falsez numeric, i_zunits numeric, i_falsem numeric, i_munits numeric, i_srtext character varying, i_description character varying, i_organization character varying, i_cs_id integer, i_object_flags integer, i_xycluster_tol numeric, i_zcluster_tol numeric, i_mcluster_tol numeric)
RETURNS integer
LANGUAGE plpgsql
SECURITY DEFINER
AS $function$
DECLARE
sql_code INTEGER;
srid_val INTEGER;
BEGIN
sql_code := -1;
IF i_srid = 0 THEN
SELECT nextval(‘sde_spatial_references_srid_seq') into srid_val;
ELSE IF i_srid = -1 THEN
srid_val = 0;
ELSE
srid_val = i_srid;
END IF;
END IF;
INSERT INTO public.sde_spatial_references (srid, falsex, falsey, xyunits,
falsez, zunits, falsem, munits,
srtext, description, organization,
cs_id, object_flags,
xycluster_tol, zcluster_tol, mcluster_tol)
VALUES (srid_val, i_falsex, i_falsey, i_xyunits,
i_falsez, i_zunits, i_falsem, i_munits,
i_srtext, i_description, i_organization,
i_cs_id, i_object_flags,
i_xycluster_tol, i_zcluster_tol, i_mcluster_tol);
IF NOT FOUND THEN
RAISE EXCEPTION 'Could not insert Spatial Reference entry.';
END IF;
sql_code := srid_val;
RETURN sql_code;
END;
$function$
SELECT sde.SDE_sref_def_insert ('0', '-400'::numeric, '-400'::numeric, '1111948722.222220000000000000000'::numeric, '0'::numeric, '1'::numeric, '0'::numeric, '1'::numeric, 'GEOGCS[""GCS_WGS_1984"",DATUM[""D_WGS_1984"",SPHEROID[""WGS_1984"",6378137.0,298.257223563]],PRIMEM[""Greenwich"",0.0],UNIT[""Degree"",0.0174532925199433]]', NULL, 'EPSG', '4326', '1', '.00000000898315284119522000000000'::numeric, '.00100000000000000000000000000000'::numeric, '.00100000000000000000000000000000'::numeric);
执行结果如下
 
 
解决方法:

通过设置下面的参数解决

behavior_compat_options='bind_procedure_searchpath'
 
 

 
 
 


 
 
 
 

0 个评论

要回复文章请先登录注册