Merge pull request !5763 from 暖阳/gms_lob1
This commit is contained in:
opengauss_bot
2024-10-23 06:32:59 +00:00
committed by Gitee
16 changed files with 3323 additions and 3 deletions

View File

@ -115,6 +115,7 @@ install:
echo "SCWS is not installed, skipping chparser build."; \
fi \
fi
@if test -d contrib/gms_lob; then $(MAKE) -C contrib/gms_lob $@; fi
+@echo "openGauss installation complete."
endif
endif

View File

@ -123,6 +123,8 @@
./share/postgresql/extension/dblink.control
./share/postgresql/extension/gms_output--1.0.sql
./share/postgresql/extension/gms_output.control
./share/postgresql/extension/gms_lob--1.0.sql
./share/postgresql/extension/gms_lob.control
./share/postgresql/extension/gms_stats--1.0.sql
./share/postgresql/extension/gms_stats.control
./share/postgresql/extension/gms_profiler--1.0.sql
@ -827,6 +829,7 @@
./lib/postgresql/pgoutput.so
./lib/postgresql/assessment.so
./lib/postgresql/gms_output.so
./lib/postgresql/gms_lob.so
./lib/postgresql/gms_stats.so
./lib/postgresql/gms_profiler.so
./lib/libpljava.so

View File

@ -111,6 +111,8 @@
./share/postgresql/extension/dblink.control
./share/postgresql/extension/gms_output--1.0.sql
./share/postgresql/extension/gms_output.control
./share/postgresql/extension/gms_lob--1.0.sql
./share/postgresql/extension/gms_lob.control
./share/postgresql/extension/gms_stats--1.0.sql
./share/postgresql/extension/gms_stats.control
./share/postgresql/extension/gms_profiler--1.0.sql
@ -797,6 +799,7 @@
./lib/postgresql/postgres_fdw.so
./lib/postgresql/dblink.so
./lib/postgresql/gms_output.so
./lib/postgresql/gms_lob.so
./lib/postgresql/gms_stats.so
./lib/postgresql/gms_profiler.so
./lib/libpljava.so

View File

@ -123,6 +123,8 @@
./share/postgresql/extension/dblink.control
./share/postgresql/extension/gms_output--1.0.sql
./share/postgresql/extension/gms_output.control
./share/postgresql/extension/gms_lob--1.0.sql
./share/postgresql/extension/gms_lob.control
./share/postgresql/extension/gms_stats--1.0.sql
./share/postgresql/extension/gms_stats.control
./share/postgresql/extension/gms_profiler--1.0.sql
@ -824,6 +826,7 @@
./lib/postgresql/java/pljava.jar
./lib/postgresql/postgres_fdw.so
./lib/postgresql/dblink.so
./lib/postgresql/gms_lob.so
./lib/postgresql/gms_stats.so
./lib/postgresql/pgoutput.so
./lib/postgresql/assessment.so

View File

@ -29,6 +29,7 @@ set(CMAKE_MODULE_PATH
${CMAKE_CURRENT_SOURCE_DIR}/chparser
${CMAKE_CURRENT_SOURCE_DIR}/gms_stats
${CMAKE_CURRENT_SOURCE_DIR}/gms_profiler
${CMAKE_CURRENT_SOURCE_DIR}/gms_lob
)
add_subdirectory(hstore)
@ -62,3 +63,5 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/chparser)
add_subdirectory(chparser)
endif()
add_subdirectory(gms_profiler)
add_subdirectory(gms_lob)

View File

@ -0,0 +1,21 @@
#This is the main CMAKE for build all gms_stats.
# gms_stats
AUX_SOURCE_DIRECTORY(${CMAKE_CURRENT_SOURCE_DIR} TGT_gms_lob_SRC)
set(TGT_gms_lob_INC
${PROJECT_OPENGS_DIR}/contrib/gms_lob
${PROJECT_OPENGS_DIR}/contrib
)
set(gms_lob_DEF_OPTIONS ${MACRO_OPTIONS})
set(gms_lob_COMPILE_OPTIONS ${OPTIMIZE_OPTIONS} ${OS_OPTIONS} ${PROTECT_OPTIONS} ${WARNING_OPTIONS} ${LIB_SECURE_OPTIONS} ${CHECK_OPTIONS})
set(gms_lob_LINK_OPTIONS ${LIB_LINK_OPTIONS})
add_shared_libtarget(gms_lob TGT_gms_lob_SRC TGT_gms_lob_INC "${gms_lob_DEF_OPTIONS}" "${gms_lob_COMPILE_OPTIONS}" "${gms_lob_LINK_OPTIONS}")
set_target_properties(gms_lob PROPERTIES PREFIX "")
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_lob.control
DESTINATION share/postgresql/extension/
)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/gms_lob--1.0.sql
DESTINATION share/postgresql/extension/
)
install(TARGETS gms_lob DESTINATION lib/postgresql)

25
contrib/gms_lob/Makefile Normal file
View File

@ -0,0 +1,25 @@
# contrib/gms_lob/Makefile
MODULE_big = gms_lob
OBJS = gms_lob.o
EXTENSION = gms_lob
DATA = gms_lob--1.0.sql
REGRESS = gms_lob
ifdef USE_PGXS
PG_CONFIG = pg_config
PGXS := $(shell $(PG_CONFIG) --pgxs)
include $(PGXS)
else
subdir = contrib/gms_lob
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
regress_home = $(top_builddir)/src/test/regress
REGRESS_OPTS = -c 0 -d 1 -r 1 -p 25632 --single_node -w --keep_last_data=false \
--regconf=$(regress_home)/regress.conf \
--temp-config=$(regress_home)/make_fastcheck_postgresql.conf
include $(top_srcdir)/contrib/contrib-global.mk
endif
gms_lob.o: gms_lob.cpp

View File

@ -0,0 +1 @@
The openGauss regression needs this file to run.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,139 @@
/* contrib/gms_lob/gms_lob--1.0.sql */
-- complain if script is sourced in psql, rather than via CREATE EXTENSION
\echo Use "CREATE EXTENSION gms_lob" to load this file. \quit
create schema gms_lob;
GRANT USAGE ON SCHEMA gms_lob TO PUBLIC;
-- GMS_LOB Constants - Basic
CREATE OR REPLACE FUNCTION gms_lob."CALL"() returns int
as $$
begin
return 12;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.FILE_READONLY() returns int
as $$
begin
return 0;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.LOB_READONLY() returns BINARY_INTEGER
as $$
begin
return 0;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.LOB_READWRITE() returns BINARY_INTEGER
as $$
begin
return 1;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.LOBMAXSIZE() returns numeric
as $$
begin
return 18446744073709551615;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.SESSION() returns INTEGER
as $$
begin
return 10;
end;
$$ LANGUAGE plpgsql;
CREATE OR REPLACE FUNCTION gms_lob.createtemporary(INOUT lob_loc BLOB, cache boolean, dur INTEGER DEFAULT 10, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_createtemporary'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.createtemporary(INOUT lob_loc CLOB, cache boolean, dur INTEGER DEFAULT 10, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_createtemporary'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.freetemporary(INOUT lob_loc BLOB, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_freetemporary'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.freetemporary(INOUT lob_loc CLOB, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_freetemporary'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.read(lob_loc BLOB, INOUT amount INTEGER, "offset" bigint, INOUT buffer raw, lobname text DEFAULT ':')
RETURNS record
AS 'MODULE_PATHNAME', 'gms_lob_og_read_blob'
LANGUAGE C NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.read(lob_loc CLOB, INOUT amount INTEGER, "offset" bigint, INOUT buffer varchar, lobname text DEFAULT ':')
RETURNS record
AS 'MODULE_PATHNAME', 'gms_lob_og_read_clob'
LANGUAGE C NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.write(INOUT lob_loc BLOB, amount numeric, "offset" numeric, buffer raw, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_write_blob'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.write(INOUT lob_loc CLOB, amount numeric, "offset" numeric, buffer varchar, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_write_clob'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.isopen(lob_loc BLOB, lobname text DEFAULT ':')
RETURNS INTEGER
AS 'MODULE_PATHNAME', 'gms_lob_og_isopen'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.isopen(lob_loc CLOB, lobname text DEFAULT ':')
RETURNS INTEGER
AS 'MODULE_PATHNAME', 'gms_lob_og_isopen'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.open(INOUT lob_loc BLOB, open_mode INTEGER, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_open'
LANGUAGE C NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.open(INOUT lob_loc CLOB, open_mode INTEGER, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_open'
LANGUAGE C NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.append(INOUT dest_lob BLOB, src_lob BLOB, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_append_blob'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.append(INOUT dest_lob CLOB, src_lob CLOB, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_append_clob'
LANGUAGE C IMMUTABLE NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.close(INOUT lob_loc BLOB, lobname text DEFAULT ':')
RETURNS BLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_close'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.close(INOUT lob_loc CLOB, lobname text DEFAULT ':')
RETURNS CLOB
AS 'MODULE_PATHNAME', 'gms_lob_og_close'
LANGUAGE C STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.getlength(lob_loc BLOB, lobname text DEFAULT ':')
RETURNS INTEGER
AS 'MODULE_PATHNAME', 'gms_lob_og_bloblength'
LANGUAGE C IMMUTABLE STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.getlength(lob_loc CLOB, lobname text DEFAULT ':')
RETURNS INTEGER
AS 'MODULE_PATHNAME', 'gms_lob_og_cloblength'
LANGUAGE C IMMUTABLE STRICT NOT FENCED;
CREATE OR REPLACE FUNCTION gms_lob.getlength(lobname text DEFAULT ':')
RETURNS void
AS 'MODULE_PATHNAME', 'gms_lob_og_null'
LANGUAGE C IMMUTABLE STRICT NOT FENCED;

View File

@ -0,0 +1,5 @@
# gms_lob extension
comment = 'collection of stats data for PL/SQL applications'
default_version = '1.0'
module_pathname = '$libdir/gms_lob'
relocatable = true

899
contrib/gms_lob/gms_lob.cpp Normal file
View File

@ -0,0 +1,899 @@
/*------------------------------------------------------------------------------
* gms_lob.cpp
*
* gms_lob内置包的实现
*
* Copyright (c) 2002-2012, PostgreSQL Global Development Group
* Portions Copyright (c) 2021, openGauss Contributors
*
* IDENTIFICATION
* contrib/gms_stats/gms_lob.cpp
*
*------------------------------------------------------------------------------
*/
#include "postgres.h"
#include "knl/knl_session.h"
#include "utils/memutils.h"
#include "catalog/pg_proc.h"
#include "c.h"
#include "miscadmin.h"
#include "access/xact.h"
#include "access/hash.h"
#include "utils/rel.h"
#include "utils/builtins.h"
#include "utils/syscache.h"
#include "access/genam.h"
#include "utils/lsyscache.h"
#include "executor/spi.h"
#include "lib/stringinfo.h"
#include "executor/executor.h"
#include "catalog/storage_gtt.h"
#include "utils/numeric.h"
#include "access/tuptoaster.h"
#include "funcapi.h"
#include "fmgr.h"
#include "catalog/pg_directory.h"
#include "mb/pg_wchar.h"
#include "libpq/pqformat.h"
#include "storage/ipc.h"
#include "utils/acl.h"
#include "utils/bytea.h"
#include "libpq/be-fsstubs.h"
#include "libpq/libpq-fs.h"
#include "commands/extension.h"
#include "gms_lob.h"
#include "utils/palloc.h"
PG_MODULE_MAGIC;
#define NUMLOB 64
static uint32 gmslob_index;
PG_FUNCTION_INFO_V1(gms_lob_og_createtemporary);
PG_FUNCTION_INFO_V1(gms_lob_og_freetemporary);
PG_FUNCTION_INFO_V1(gms_lob_og_read_blob);
PG_FUNCTION_INFO_V1(gms_lob_og_read_clob);
PG_FUNCTION_INFO_V1(gms_lob_og_write_blob);
PG_FUNCTION_INFO_V1(gms_lob_og_write_clob);
PG_FUNCTION_INFO_V1(gms_lob_og_isopen);
PG_FUNCTION_INFO_V1(gms_lob_og_open);
PG_FUNCTION_INFO_V1(gms_lob_og_append_blob);
PG_FUNCTION_INFO_V1(gms_lob_og_append_clob);
PG_FUNCTION_INFO_V1(gms_lob_og_close);
PG_FUNCTION_INFO_V1(gms_lob_og_cloblength);
PG_FUNCTION_INFO_V1(gms_lob_og_bloblength);
PG_FUNCTION_INFO_V1(gms_lob_og_null);
void init_session_vars(void) {
RepallocSessionVarsArrayIfNecessary();
GmsLobContext* psc =
(GmsLobContext*)MemoryContextAllocZero(u_sess->self_mem_cxt, sizeof(GmsLobContext));
u_sess->attr.attr_common.extension_session_vars_array[gmslob_index] = psc;
psc->gmsLobNameHash = NULL;
}
GmsLobContext* get_session_context() {
if (u_sess->attr.attr_common.extension_session_vars_array[gmslob_index] == NULL) {
init_session_vars();
}
return (GmsLobContext*)u_sess->attr.attr_common.extension_session_vars_array[gmslob_index];
}
static int32 getVarSize(varlena* var)
{
if (VARATT_IS_HUGE_TOAST_POINTER(var)) {
struct varatt_lob_external large_toast_pointer;
VARATT_EXTERNAL_GET_HUGE_POINTER(large_toast_pointer, var);
return large_toast_pointer.va_rawsize;
} else {
return VARSIZE_ANY_EXHDR(var);
}
}
/*
* charlen_to_bytelen()
* Compute the number of bytes occupied by n characters starting at *p
*
* It is caller's responsibility that there actually are n characters;
* the string need not be null-terminated.
*/
static int charlen_to_bytelen(const char* p, int n)
{
if (pg_database_encoding_max_length() == 1) {
/* Optimization for single-byte encodings */
return n;
} else {
const char* s = NULL;
for (s = p; n > 0; n--)
s += pg_mblen(s);
return s - p;
}
}
/* numeric 向下取整转成int4 */
int32 numericFloorToInt4(Numeric num)
{
Datum datumnum = DirectFunctionCall1(numeric_floor, NumericGetDatum(num));
return DatumGetInt32(DirectFunctionCall1(numeric_int4, datumnum));
}
/*****************************************************************************
* LOB哈希表相关
*****************************************************************************/
struct GmsLobHashKey {
char* keyvalue;
int length;
};
typedef struct LobHashEnt {
GmsLobHashKey key; /* hash表key值 */
int open_mode; /* 打开方式 */
} LobHashEnt;
/*
* lob数据的hash值生成函数
*/
uint32 lob_hash(const void* key, Size kwysize)
{
const GmsLobHashKey* hash_key = (const GmsLobHashKey*)key;
return DatumGetUInt32(hash_any((const unsigned char*)hash_key->keyvalue, hash_key->length));
}
/*
* lob数据的hash比较函数
*/
int lob_match(const void* key1, const void* key2, Size kwysize)
{
const GmsLobHashKey* k1 = (const GmsLobHashKey*)key1;
const GmsLobHashKey* k2 = (const GmsLobHashKey*)key2;
if (k1->length > k2->length) {
return 1;
} else if (k1->length < k2->length) {
return -1;
}
return strncmp(k1->keyvalue, k2->keyvalue, k1->length);
}
/*
* 创建hash表
*/
static HTAB* createlobHash()
{
HASHCTL hash_ctl;
hash_ctl.keysize = sizeof(GmsLobHashKey);
hash_ctl.entrysize = sizeof(LobHashEnt);
hash_ctl.hash = lob_hash;
hash_ctl.match = lob_match;
return hash_create("Lob hash", NUMLOB, &hash_ctl, HASH_ELEM | HASH_FUNCTION | HASH_COMPARE);
}
/*
* 程序退出时的清理函数
* 作为回调函数添加到proc_exit()调用的函数列表中
*/
static void gms_lob_og_lob_exit(int code, Datum arg)
{
HASH_SEQ_STATUS scan;
LobHashEnt *hentry = NULL;
if (get_session_context()->gmsLobNameHash == NULL) {
return;
}
hash_seq_init(&scan, get_session_context()->gmsLobNameHash);
while ((hentry = (LobHashEnt *)hash_seq_search(&scan))) {
if (hentry->key.keyvalue) {
pfree(hentry->key.keyvalue);
}
}
/* 清理hash表 */
hash_destroy(get_session_context()->gmsLobNameHash);
get_session_context()->gmsLobNameHash = NULL;
}
char* generateLobKey(char* argname)
{
char* key = NULL;
int keylen = 0;
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
TransactionId currentTransactionId = GetCurrentTransactionId();
// TransactionId采用16进制方式打印,逗号末尾结束符各占一个字节
keylen = strlen(argname) + sizeof(TransactionId) * 2 + 1 + 1;
key = (char*)palloc0(keylen);
errno_t errorno = snprintf_s(key, keylen, keylen - 1, "%16x,%s", currentTransactionId, argname);
securec_check_ss(errorno, "\0", "\0");
return key;
}
int searchLob(char* argname, bool* found)
{
LobHashEnt* hentry = NULL;
GmsLobHashKey hash_key;
if (get_session_context()->gmsLobNameHash) {
hash_key.keyvalue = generateLobKey(argname);
hash_key.length = strlen(hash_key.keyvalue) + 1;
hentry = (LobHashEnt*)hash_search(get_session_context()->gmsLobNameHash, &hash_key, HASH_FIND, NULL);
if (hentry) {
*found = true;
return hentry->open_mode;
}
if (hash_key.keyvalue) {
pfree(hash_key.keyvalue);
}
} else {
get_session_context()->gmsLobNameHash = createlobHash();
on_proc_exit(&gms_lob_og_lob_exit, PointerGetDatum(NULL));
}
*found = false;
return -1;
}
static void closeLob(char* argname)
{
bool found;
LobHashEnt* hentry = NULL;
GmsLobHashKey hash_key;
searchLob(argname, &found);
if (found) {
hash_key.keyvalue = generateLobKey(argname);
hash_key.length = strlen(hash_key.keyvalue) + 1;
hentry = (LobHashEnt*)hash_search(get_session_context()->gmsLobNameHash, &hash_key, HASH_REMOVE, NULL);
if (!hentry) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("undefined lob.")));
}
if (hash_key.keyvalue) {
pfree(hash_key.keyvalue);
}
if (hentry->key.keyvalue) {
pfree(hentry->key.keyvalue);
}
}
}
static void openLob(char* argname, int openmode)
{
bool found;
LobHashEnt* hentry = NULL;
GmsLobHashKey hash_key;
hash_key.keyvalue = generateLobKey(argname);
hash_key.length = strlen(hash_key.keyvalue) + 1;
hentry = (LobHashEnt*)hash_search(get_session_context()->gmsLobNameHash, &hash_key, HASH_ENTER, &found);
if (found) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate lob(%s) openned", argname)));
}
hentry->key.keyvalue = (char*)MemoryContextAlloc(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_EXECUTOR), hash_key.length);
int rc = memcpy_s(hentry->key.keyvalue, hash_key.length, hash_key.keyvalue, hash_key.length);
securec_check(rc, "\0", "\0");
hentry->key.length = hash_key.length;
hentry->open_mode = openmode;
if (hash_key.keyvalue) {
pfree(hash_key.keyvalue);
}
}
/*
* GMS_LOB.CREATETEMPORARY (
* lob_loc IN OUT BLOB/CLOB, --blob/clob对象
* cache IN BOOLEAN, --是否将LOB读取到缓冲区(不生效)
* dur IN PLS_INTEGER := GMS_LOB.SESSION); --指定何时清除临时LOB(10/ SESSION:会话结束时;12/ CALL:调用结束时)(不生效
)
*/
Datum gms_lob_og_createtemporary(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(3));
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
varlena* res = NULL;
if (PG_ARGISNULL(0)) {
res = (varlena*)palloc(VARHDRSZ);
SET_VARSIZE(res, VARHDRSZ);
PG_RETURN_POINTER(res);
}
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
/*
* GMS_LOB.FREETEMPORARY (
* lob_loc IN OUT BLOB/CLOB); --blob/clob对象
*/
Datum gms_lob_og_freetemporary(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(1));
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
/* lob如果没关闭,将其关闭 */
closeLob(argname);
/* 返回一个空值的varlena */
varlena* res = (varlena*)palloc0(VARHDRSZ);
SET_VARSIZE(res, VARHDRSZ);
PG_RETURN_DATUM(PointerGetDatum(res));
}
/*
* lob_loc IN BLOB,
* amount IN OUT NOCOPY BINARY_INTEGER,
* offset IN INTEGER,
* buffer INOUT RAW
*/
Datum gms_lob_og_read_blob(PG_FUNCTION_ARGS)
{
if (PG_ARGISNULL(0))
ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("invalid LOB object specified")));
if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("numeric or value error")));
}
bytea *src_lob = PG_GETARG_BYTEA_P(0);
int32 amount = PG_GETARG_INT32(1);
int32 offset = PG_GETARG_INT32(2);
if (amount < 1 || amount > AMOUNT_MAX_SIZE) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("amount is invalid or out of range")));
}
if (offset < 1 || offset > LOBMAXSIZE) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("offset is invalid or out of range")));
}
int32 srclen = VARSIZE(src_lob) - VARHDRSZ;
if (offset > srclen) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("no data found")));
}
int32 srcamount = amount > (srclen - offset + 1) ? (srclen - offset + 1) : amount; //src实际复制的字节数
bytea* res = NULL;
int rc = 0;
res = (bytea*)palloc0(srcamount + VARHDRSZ);
SET_VARSIZE(res, srcamount + VARHDRSZ);
rc = memcpy_s(VARDATA(res), srcamount, VARDATA(src_lob) + offset - 1, srcamount);
securec_check(rc, "\0", "\0");
TupleDesc tupdesc;
Datum result;
HeapTuple tuple;
Datum values[2];
bool nulls[2] = { false, false };
/* 构造返回结果集 */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
elog(ERROR, "return type must be a row type");
}
/*拼接结果*/
values[0] = Int32GetDatum(srcamount);
values[1] = PointerGetDatum(res);
tuple = heap_form_tuple(tupdesc, values, nulls);
result = HeapTupleGetDatum(tuple);
PG_RETURN_DATUM(result);
}
/*
* lob_loc IN CLOB,
* amount IN OUT NOCOPY BINARY_INTEGER,
* offset IN INTEGER,
* buffer INOUT VARCHAR2
*/
Datum gms_lob_og_read_clob(PG_FUNCTION_ARGS)
{
if (PG_ARGISNULL(0))
ereport(ERROR,(errcode(ERRCODE_INVALID_PARAMETER_VALUE),errmsg("invalid LOB object specified")));
if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("numeric or value error")));
}
text* src_lob = PG_GETARG_TEXT_P(0);
int32 amount = PG_GETARG_INT32(1);
int32 offset = PG_GETARG_INT32(2);
if (amount < 1 || amount > AMOUNT_MAX_SIZE) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("amount is invalid or out of range")));
}
if (offset < 1 || offset > LOBMAXSIZE) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("offset is invalid or out of range")));
}
int32 srclen = DirectFunctionCall1(textlen, PointerGetDatum(src_lob));
if (offset > srclen) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("no data found")));
}
int32 srcamount = amount > (srclen - offset + 1) ? (srclen - offset + 1) : amount; //src实际复制的字符数
int32 srcbytestart = charlen_to_bytelen(VARDATA(src_lob), offset - 1); //src复制起点
int32 copybyte = charlen_to_bytelen(VARDATA(src_lob) + srcbytestart, srcamount); //src实际复制的字节数
text* res = NULL;
int rc = 0;
res = (text*)palloc0(copybyte + VARHDRSZ);
SET_VARSIZE(res, copybyte + VARHDRSZ);
rc = memcpy_s(VARDATA(res), copybyte, VARDATA(src_lob) + srcbytestart, copybyte);
securec_check(rc, "\0", "\0");
TupleDesc tupdesc;
Datum result;
HeapTuple tuple;
Datum values[2];
bool nulls[2] = { false, false };
/* 构造返回结果集 */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
elog(ERROR, "return type must be a row type");
}
/*拼接结果*/
values[0] = Int32GetDatum(srcamount);
values[1] = PointerGetDatum(res);
tuple = heap_form_tuple(tupdesc, values, nulls);
result = HeapTupleGetDatum(tuple);
PG_RETURN_DATUM(result);
}
/*
* GMS_LOB.WRITE (
* lob_loc IN OUT NOCOPY BLOB, --目标blob对象
* amount IN INTEGER, --指定的传入字节数
* offset IN INTEGER, --开始读取blob的字节数的偏移量(原点在1)
* buffer IN RAW); --用于写的输入缓冲区
*/
Datum gms_lob_og_write_blob(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(4));
/* check input args */
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
if (PG_ARGISNULL(0)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid LOB object specified")));
}
if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Any of the input parameters are NULL")));
}
bytea* destlob = PG_GETARG_BYTEA_P(0);
int32 amount = numericFloorToInt4(PG_GETARG_NUMERIC(1));
int32 offset = numericFloorToInt4(PG_GETARG_NUMERIC(2));
bytea* buffer = PG_GETARG_BYTEA_P(3);
int32 bufsize = getVarSize(buffer);
if (amount < 1 || amount > 32767 || amount > bufsize) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("amount is invalid or out of range")));
}
if (offset < 1 || offset > LOBMAXSIZE) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Invalid argument value for dest_offset.")));
}
/* check lob's write and read permissions */
bool found;
int32 openmode = searchLob(argname, &found);
if (found && openmode == 0) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("cannot update a LOB opened in read-only mode.")));
}
int32 destlen = getVarSize(destlob);
int destbytestart = (offset - 1) > destlen ? destlen : (offset - 1);
int32 spacecnt = (offset - 1) > destlen ? (offset - destlen - 1) : 0;
int32 appendbyte = amount;
int32 destbyteend = (offset - 1 + appendbyte) > destlen ? destlen : (offset - 1 + appendbyte);
int64 reslen = destbytestart + spacecnt + appendbyte + (destlen - destbyteend);
bytea* res = NULL;
char* resdata = NULL;
int rc = 0;
if (reslen != destlen || buffer == destlob) {
/* dest is lack of space, or displaced copy when
* buffer is the same as destlob, to avoid errors
* in memcpy_s checking, reapply
*/
if (reslen > MAX_TOAST_CHUNK_SIZE - VARHDRSZ) {
#ifdef ENABLE_MULTIPLE_NODES
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Un-support clob/blob type more than 1GB for distributed system")));
#endif
}
res = (bytea*)palloc(reslen + VARHDRSZ);
SET_VARSIZE(res, reslen + VARHDRSZ);
} else {
res = destlob;
}
resdata = VARDATA(res);
if (destbytestart > 0 && res != destlob) {
rc = memcpy_s(resdata, destbytestart, VARDATA(destlob), destbytestart);
securec_check(rc, "\0", "\0");
}
resdata += destbytestart;
if (spacecnt > 0) {
rc = memset_s(resdata, spacecnt, ' ', spacecnt);
securec_check(rc, "\0", "\0");
}
resdata += spacecnt;
if (appendbyte > 0) {
rc = memcpy_s(resdata, appendbyte, VARDATA(buffer), appendbyte);
securec_check(rc, "\0", "\0");
}
resdata += appendbyte;
if (destbyteend < destlen && res != destlob) {
rc = memcpy_s(resdata, destlen - destbyteend, VARDATA(destlob) + destbyteend, destlen - destbyteend);
securec_check(rc, "\0", "\0");
}
PG_RETURN_BYTEA_P(res);
}
/*
* GMS_LOB.WRITE (
* lob_loc IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, --目标clob对象
* amount IN INTEGER, --指定传入的字符数
* offset IN INTEGER, --开始读取blob的字符数的偏移量(原点在1)
* buffer IN VARCHAR2 CHARACTER SET lob_loc%CHARSET); --用于写入的缓冲区
*/
Datum gms_lob_og_write_clob(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(4));
/* check input args */
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
if (PG_ARGISNULL(0)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid LOB object specified")));
}
if (PG_ARGISNULL(1) || PG_ARGISNULL(2)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Any of the input parameters are NULL")));
}
text* destlob = PG_GETARG_TEXT_P(0);
int32 amount = numericFloorToInt4(PG_GETARG_NUMERIC(1));
int32 offset = numericFloorToInt4(PG_GETARG_NUMERIC(2));
text* buffer = PG_GETARG_TEXT_P(3);
int32 bufsize = DirectFunctionCall1(textlen, (Datum)buffer);
if (amount < 1 || amount > 32767 || amount > bufsize) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("amount is invalid or out of range")));
}
if (offset < 1 || offset > LOBMAXSIZE) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Invalid argument value for dest_offset.")));
}
/* check lob's write and read permissions */
bool found;
int32 openmode = searchLob(argname, &found);
if (found && openmode == 0) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("cannot update a LOB opened in read-only mode.")));
}
int32 destlen = DirectFunctionCall1(textlen, (Datum)destlob);
int32 srcamount = amount;
int32 destbytestart = 0;
int32 spacecnt = 0;
int32 appendbyte = charlen_to_bytelen(VARDATA(buffer), srcamount);
int32 destamount = 0;
int32 destbyteend = 0;
int32 destbytecnt = VARSIZE(destlob) - VARHDRSZ;
int64 reslen = 0;
text* res = NULL;
char* resdata = NULL;
int rc = 0;
if (destlen < offset - 1) {
destamount = destlen;
spacecnt = offset - 1 - destamount;
destbytestart = destbytecnt;
destbyteend = destbytecnt;
} else {
destamount = srcamount > (destlen - offset + 1) ? (destlen - offset + 1) : srcamount;
destbytestart = charlen_to_bytelen(VARDATA(destlob), offset - 1);
destbyteend = charlen_to_bytelen(VARDATA(destlob) + destbytestart, destamount) + destbytestart;
}
reslen = destbytestart + spacecnt + appendbyte + (destbytecnt - destbyteend);
if (reslen != destbytecnt || buffer == destlob) {
/* dest is lack of space, or displaced copy when
* buffer is the same as destlob, to avoid errors
* in memcpy_s checking, reapply
*/
if (reslen > MAX_TOAST_CHUNK_SIZE - VARHDRSZ) {
#ifdef ENABLE_MULTIPLE_NODES
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("Un-support clob/blob type more than 1GB for distributed system")));
#endif
}
res = (text*)palloc(reslen + VARHDRSZ);
SET_VARSIZE(res, reslen + VARHDRSZ);
} else {
res = destlob;
}
resdata = VARDATA(res);
if (destbytestart > 0 && res != destlob) {
rc = memcpy_s(resdata, destbytestart, VARDATA(destlob), destbytestart);
securec_check(rc, "\0", "\0");
}
resdata += destbytestart;
if (spacecnt > 0) {
rc = memset_s(resdata, spacecnt, ' ', spacecnt);
securec_check(rc, "\0", "\0");
}
resdata += spacecnt;
if (appendbyte > 0) {
rc = memcpy_s(resdata, appendbyte, VARDATA(buffer), appendbyte);
securec_check(rc, "\0", "\0");
}
resdata += appendbyte;
if (destbyteend < destbytecnt && res != destlob) {
rc = memcpy_s(resdata, destbytecnt - destbyteend, VARDATA(destlob) + destbyteend, destbytecnt - destbyteend);
securec_check(rc, "\0", "\0");
}
PG_RETURN_TEXT_P(res);
}
/*
* GMS_LOB.ISOPEN (
* lob_loc IN OUT BLOB/CLOB); --blob/clob对象
*/
Datum gms_lob_og_isopen(PG_FUNCTION_ARGS)
{
bool found;
char* argname = text_to_cstring(PG_GETARG_TEXT_P(1));
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
searchLob(argname, &found);
if (found) {
PG_RETURN_UINT8(1);
} else {
PG_RETURN_UINT8(0);
}
}
/*
* GMS_LOB.OPEN (
* lob_loc IN OUT BLOB/CLOB,
* open_mode IN BINARY_INTEGER);
*/
Datum gms_lob_og_open(PG_FUNCTION_ARGS)
{
if PG_ARGISNULL(0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid LOB object specified")));
}
bool found;
int openmode = PG_GETARG_INT32(1);
if (openmode != 0 && openmode != 1) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid open_mode")));
}
char* argname = text_to_cstring(PG_GETARG_TEXT_P(2));
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
searchLob(argname, &found);
if (found) {
ereport(NOTICE, (errmsg("Lob(%s) already opened in the same transaction", argname)));
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
openLob(argname, openmode);
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
/*
GMS_LOB.APPEND (
dest_lob IN OUT NOCOPY BLOB, --目标blob对象
src_lob IN BLOB); --源blob对象
*/
Datum gms_lob_og_append_blob(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(2));
/* check input args */
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid LOB object specified")));
}
/* check lob's write and read permissions */
bool found;
int32 openmode = searchLob(argname, &found);
if (found && openmode == 0) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("cannot update a LOB opened in read-only mode.")));
}
Datum destlob = PG_GETARG_DATUM(0);
Datum srclob = PG_GETARG_DATUM(1);
Datum result = DirectFunctionCall2(byteacat, destlob, srclob);
PG_RETURN_BYTEA_P(DatumGetPointer(result));
}
/*
GMS_LOB.APPEND (
dest_lob IN OUT NOCOPY CLOB CHARACTER SET ANY_CS, --目标clob对象
src_lob IN CLOB CHARACTER SET dest_lob%CHARSET); --源clob对象
*/
Datum gms_lob_og_append_clob(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(2));
/* check input args */
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
if (PG_ARGISNULL(0) || PG_ARGISNULL(1)) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid LOB object specified")));
}
/* check lob's write and read permissions */
bool found;
int32 openmode = searchLob(argname, &found);
if (found && openmode == 0) {
closeLob(argname);
ereport(ERROR,
(errcode(ERRCODE_INVALID_OPERATION),
errmsg("cannot update a LOB opened in read-only mode.")));
}
Datum destlob = PG_GETARG_DATUM(0);
Datum srclob = PG_GETARG_DATUM(1);
Datum result = DirectFunctionCall2(textcat, destlob, srclob);
PG_RETURN_TEXT_P(DatumGetPointer(result));
}
/*
* GMS_LOB.CLOSE (
* lob_loc IN OUT BLOB/CLOB); --blob/clob对象
*/
Datum gms_lob_og_close(PG_FUNCTION_ARGS)
{
char* argname = text_to_cstring(PG_GETARG_TEXT_P(1));
if (strcmp(argname, ":") == 0) {
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output parameter not a bind variable")));
}
bool found;
searchLob(argname, &found);
if (!found) {
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("cannot perform operation on an unopened file or LOB")));
}
closeLob(argname);
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
/*
* GMS_LOB.getlength (
* lob_loc IN OUT CLOB); --clob对象
*/
Datum gms_lob_og_cloblength(PG_FUNCTION_ARGS)
{
Datum data = PG_GETARG_DATUM(0);
int datalen = 0;
datalen = DirectFunctionCall1(textlen, data);
PG_RETURN_INT32(datalen);
}
/*
* GMS_LOB.getlength (
* lob_loc IN OUT BLOB); --blob对象
*/
Datum gms_lob_og_bloblength(PG_FUNCTION_ARGS)
{
bytea* data = PG_GETARG_BYTEA_P(0);
int datalen = 0;
datalen = VARSIZE(data) - VARHDRSZ;
PG_RETURN_INT32(datalen);
}
/*
* GMS_LOB.getlength (); --NULL对象
*/
Datum gms_lob_og_null(PG_FUNCTION_ARGS)
{
PG_RETURN_VOID();
}

37
contrib/gms_lob/gms_lob.h Normal file
View File

@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------*
* gms_lob.h
*
* Definition about gms_lob package.
*
* IDENTIFICATION
* contrib/gms_stats/gms_lob.h
*
* ---------------------------------------------------------------------------------------
*/
#ifndef GMS_LOB_H
#define GMS_LOB_H
/* blob/clob最大存储长度1G*/
#define LOBMAXSIZE (int64)0x3fffffff
#define AMOUNT_MAX_SIZE 32767
typedef struct GmsLobContext {
struct HTAB* gmsLobNameHash;
} GmsLobContext;
extern "C" Datum gms_lob_og_createtemporary(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_freetemporary(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_read_blob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_read_clob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_write_blob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_write_clob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_isopen(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_open(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_append_blob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_append_clob(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_close(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_cloblength(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_bloblength(PG_FUNCTION_ARGS);
extern "C" Datum gms_lob_og_null(PG_FUNCTION_ARGS);
extern "C" void set_extension_index(uint32 index);
extern "C" void init_session_vars(void);
extern "C" GmsLobContext* get_session_context();
#endif

View File

@ -0,0 +1,990 @@
drop database if exists testlob;
create database testlob;
\c testlob
create extension gms_lob;
create extension gms_output;
select gms_output.enable(4000);
create or replace function cast_to_raw(strdata varchar2) returns raw
as 'select encode(cast($1 as bytea), ''hex'')::raw;'LANGUAGE SQL;
--blob类型长度
CREATE TABLE testblob(id INT, b BLOB);
--cast_to_raw
INSERT INTO testblob VALUES(1, cast_to_raw('Blob'));
INSERT INTO testblob VALUES(2, cast_to_raw('中文测试'));
INSERT INTO testblob VALUES(3, cast_to_raw(''));
INSERT INTO testblob VALUES(4, cast_to_raw('test
test'));
SELECT id, gms_lob.getlength(b) FROM testblob;
DROP TABLE testblob;
--clob类型的长度
CREATE TABLE testclob(id INT, b CLOB);
INSERT INTO testclob VALUES(1, ('Blob'));
INSERT INTO testclob VALUES(2, ('中文测试'));
INSERT INTO testclob VALUES(3, (''));
INSERT INTO testclob VALUES(4, ('test
test'));
SELECT *,gms_lob.getlength(b) FROM testclob;
DROP TABLE testclob;
--
CREATE OR REPLACE FUNCTION fun_blob() RETURNS INTEGER LANGUAGE plpgsql AS $$
DECLARE
lob_object BLOB := cast_to_raw('中文1');
offset INTEGER;
BEGIN
RETURN gms_lob.getlength(lob_object);
END;
$$;
SELECT fun_blob();
CREATE OR REPLACE FUNCTION fun_clob() RETURNS INTEGER LANGUAGE plpgsql AS $$
DECLARE
lob_object CLOB := ('中文1');
offset INTEGER;
BEGIN
RETURN gms_lob.getlength(lob_object);
END;
$$;
SELECT fun_clob();
CREATE OR REPLACE FUNCTION fun_null() RETURNS INTEGER LANGUAGE plpgsql AS $$
DECLARE
lob_object CLOB;
offset INTEGER;
BEGIN
RETURN gms_lob.getlength(lob_object);
END;
$$;
SELECT fun_null();
DROP FUNCTION fun_blob;
DROP FUNCTION fun_clob;
DROP FUNCTION fun_null;
--
SELECT gms_lob.getlength();
create table tbl_testlob(id int, c_lob clob, b_lob blob);
insert into tbl_testlob values(1, 'clob', cast_to_raw('blob'));
insert into tbl_testlob values(2, '中文clobobject测试', cast_to_raw('中文blobobject测试'));
create or replace function func_clob() returns void
AS $$
DECLARE
v_clob1 clob;
v_clob2 clob;
v_clob3 clob;
len1 int;
len3 int;
BEGIN
select c_lob into v_clob1 from tbl_testlob where id = 1;
gms_lob.open(v_clob1, gms_lob.LOB_READWRITE);
gms_lob.append(v_clob1, ' test');
len1 := gms_lob.getlength(v_clob1);
gms_output.put_line('clob2:' || v_clob2);
gms_lob.read(v_clob1, len1, 1, v_clob2);
gms_output.put_line('clob1:' || v_clob1);
gms_output.put_line('clob2:' || v_clob2);
select c_lob into v_clob3 from tbl_testlob where id = 2;
len3 := gms_lob.getlength(v_clob3);
gms_output.put_line('clob3:' || v_clob3);
--open函数
gms_lob.write(v_clob3, len1, len3, v_clob1);
gms_output.put_line('clob3:' || v_clob3);
gms_lob.close(v_clob1);
gms_lob.freetemporary(v_clob2);
END;
$$LANGUAGE plpgsql;
create or replace function func_blob() returns void
AS $$
DECLARE
v_blob1 blob;
v_blob2 blob;
v_blob3 blob;
len1 int;
len3 int;
BEGIN
select b_lob into v_blob1 from tbl_testlob where id = 1;
gms_lob.open(v_blob1, gms_lob.LOB_READWRITE);
len1 := gms_lob.getlength(v_blob1);
gms_output.put_line('blob1:' || v_blob1::text);
gms_output.put_line('blob2:' || v_blob2::text);
gms_lob.read(v_blob1, len1, 1, v_blob2);
gms_output.put_line('blob1:' || v_blob1::text);
gms_output.put_line('blob2:' || v_blob2::text);
select b_lob into v_blob3 from tbl_testlob where id = 2;
len3 := gms_lob.getlength(v_blob3);
--open函数
gms_output.put_line('blob3:' || v_blob3::text);
gms_lob.write(v_blob3, len1, len3, v_blob1);
gms_output.put_line('blob3:' || v_blob3::text);
gms_lob.close(v_blob1);
gms_lob.freetemporary(v_blob2);
END;
$$LANGUAGE plpgsql;
select func_clob();
select func_blob();
----------open函数-----------
--(1)打开无效的lob
DECLARE
v_clob clob;
BEGIN
gms_lob.open(v_clob, gms_lob.LOB_READWRITE);
gms_lob.close(v_clob);
END;
/
--2open_mode为数值
DECLARE
v_clob clob;
BEGIN
gms_lob.createtemporary(v_clob, false, 10);
gms_lob.open(v_clob, 1);
gms_lob.close(v_clob);
gms_lob.freetemporary(v_clob);
END;
/
--3open_mode为其他值
DECLARE
v_clob clob;
BEGIN
gms_lob.createtemporary(v_clob, false);
gms_lob.open(v_clob, 100);
gms_lob.close(v_clob);
gms_lob.freetemporary(v_clob);
END;
/
--
DECLARE
v_clob clob;
BEGIN
gms_lob.createtemporary(v_clob, false);
gms_lob.open(v_clob, gms_lob.LOB_READONLY);
gms_lob.open(v_clob, gms_lob.LOB_READWRITE);
gms_lob.close(v_clob);
gms_lob.freetemporary(v_clob);
END;
/
-- 大写名称
declare
"MYLOB" CLOB;
begin
gms_lob.createtemporary("MYLOB",true);
gms_lob.open("MYLOB",gms_lob.lob_readwrite);
"MYLOB":='foo';
raise notice '%',"MYLOB";
end;
/
----------isopen函数-----------
DECLARE
v_clob clob;
BEGIN
gms_lob.createtemporary(v_clob, false);
gms_lob.open(v_clob, gms_lob.LOB_READWRITE);
gms_output.put_line('isopen: ' || gms_lob.isopen(v_clob));
gms_lob.close(v_clob);
gms_output.put_line('isopen: ' || gms_lob.isopen(v_clob));
gms_lob.freetemporary(v_clob);
END;
/
-----------freetemporary函数-----------
DECLARE
v_clob CLOB;
v_char VARCHAR2(100);
BEGIN
v_char := 'Chinese中国人';
gms_lob.createtemporary(v_clob,TRUE,12);
gms_lob.append(v_clob,v_char);
gms_output.put_line(v_clob||' 字符长度:'||gms_lob.getlength(v_clob));
gms_lob.freetemporary(v_clob);
gms_output.put_line(' 释放后再输出:'||v_clob);
END;
/
drop table tbl_testlob;
drop function func_clob;
drop function func_blob;
declare
lob1 clob := '123';
lob2 clob := '456';
lob3 clob := '789';
begin
gms_lob.open (lob_loc => lob1,open_mode => 1);
gms_lob.open (lob_loc => lob2,open_mode => gms_lob.lob_readwrite);
gms_lob.open (lob_loc => lob3,open_mode => gms_lob.lob_readonly);
raise notice '%,%,%',lob1,lob2,lob3;
end;
/
-- 支持GMS_LOB.WRITE/READ/APPEND函数
-----------read函数-----------
--gms_lob.gms_lob_read_blob
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
-- float
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount float :=3.2;
off_set float :=2.1;
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount float :=3.8;
off_set float :=2.9;
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount float :=3.8;
off_set float :=2.9;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=8;
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=20;
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_lob.read(b1, amount, off_set, b2);
gms_output.put_line(r1::text);
end;
/
--VALUEERROR
--lob为空
declare
b1 blob;
amount INTEGER :=3;
off_set INTEGER :=2;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
end;
/
--amount为空
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER;
off_set INTEGER :=9;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
end;
/
--offset为空
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=3;
off_set INTEGER;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
end;
/
--lob无效
declare
amount INTEGER :=3;
off_set INTEGER :=2;
r1 raw;
begin
gms_lob.read(cast_to_raw('111111'), amount, off_set, r1);
end;
/
--amount大于buffer大小
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=15;
off_set INTEGER :=2;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
end;
/
--offset超出范围
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=3;
off_set INTEGER :=30;
r1 raw;
begin
gms_lob.read(b1, amount, off_set, r1);
end;
/
--lob只读
declare
b1 blob :=cast_to_raw('1111');
amount INTEGER :=2;
off_set INTEGER :=2;
r1 raw;
begin
gms_lob.open(b1, gms_lob.LOB_READONLY);
gms_lob.read(b1, amount, off_set, r1);
gms_output.put_line(r1::text);
end;
/
--gms_lob.gms_lob_read_clob
declare
c1 clob :='abcdefgh';
amount INTEGER :=3;
off_set INTEGER :=1;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
declare
c1 clob :='abcdefgh';
amount INTEGER :=3;
off_set INTEGER :=9;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
declare
c1 clob :='abcdefgh';
amount INTEGER :=10;
off_set INTEGER :=2;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--VALUEERROR
--lob为空
declare
c1 clob;
amount INTEGER :=3;
off_set INTEGER :=2;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--amount为空
declare
c1 clob :='abcdefgh';
amount INTEGER;
off_set INTEGER :=1;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--offset为空
declare
c1 clob :='abcdefgh';
amount INTEGER :=3;
off_set INTEGER;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--lob无效
declare
c1 clob;
amount INTEGER :=3;
off_set INTEGER :=2;
var_buf varchar2(10);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--amount大于buffer大小
declare
c1 clob :='abcdefgh';
amount INTEGER :=6;
off_set INTEGER :=2;
var_buf varchar2(3);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--offset超出范围
declare
c1 clob :='abcdefgh';
amount INTEGER :=2;
off_set INTEGER :=0;
var_buf varchar2(3);
begin
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
--lob只读
declare
c1 clob :='1111';
amount INTEGER :=2;
off_set INTEGER :=2;
var_buf varchar2(10);
begin
gms_lob.open(c1, gms_lob.LOB_READONLY);
gms_lob.read(c1, amount, off_set, var_buf);
gms_output.put_line('clob read: ' || var_buf::text);
end;
/
-----------write函数-----------
--gms_lob.gms_lob_write_blob
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('abc');
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=8;
b2 blob :=cast_to_raw('abc');
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=3;
off_set INTEGER :=20;
b2 blob :=cast_to_raw('abc');
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
--buffer等于destlob
declare
b1 blob :=cast_to_raw('1234');
amount INTEGER :=2;
off_set INTEGER :=2;
begin
gms_lob.write(b1, amount, off_set, b1);
gms_output.put_line(b1::text);
end;
/
--VALUEERROR
--lob为空
declare
b1 blob;
amount INTEGER :=3;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(b1, amount, off_set, b2);
end;
/
--amount为空
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER;
off_set INTEGER :=9;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(b1, amount, off_set, b2);
end;
/
--amount,offset向下取整
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount float :=3.9; -- 3
off_set float :=5.6; -- 5
b2 blob :=cast_to_raw('abc');
r1 raw;
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount float :=2.2; -- 2
off_set float :=5.1; -- 5
b2 blob :=cast_to_raw('abc');
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
declare
b1 blob :=cast_to_raw('ABCDEFGH');
amount INTEGER :=4;
off_set INTEGER :=8;
b2 blob :=cast_to_raw('abc');
begin
gms_lob.write(b1, amount, off_set, b2);
gms_output.put_line(b1::text);
end;
/
--offset为空
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=3;
off_set INTEGER;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(b1, amount, off_set, b2);
end;
/
--lob无效
declare
amount INTEGER :=3;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(cast_to_raw('111111'), amount, off_set, b2);
end;
/
--amount大于buffer大小
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=5;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(b1, amount, off_set, b2);
end;
/
--offset超出范围
declare
b1 blob :=cast_to_raw('11111111');
amount INTEGER :=3;
off_set INTEGER :=0;
b2 blob :=cast_to_raw('222');
begin
gms_lob.write(b1, amount, off_set, b2);
end;
/
--lob只读
declare
b1 blob :=cast_to_raw('1111');
amount INTEGER :=2;
off_set INTEGER :=2;
b2 blob :=cast_to_raw('222');
begin
gms_lob.open(b1, gms_lob.LOB_READONLY);
gms_lob.write(b1, amount, off_set, b2);
end;
/
--gms_lob.gms_lob_write_clob
declare
c1 clob :='11111111';
amount INTEGER :=3;
off_set INTEGER :=1;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
-- amount, off_set 不向下取整
declare
c1 clob :='11111111';
amount INTEGER :=3.9;
off_set INTEGER :=1.8;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
declare
c1 clob :='11111111';
amount INTEGER :=3;
off_set INTEGER :=1.8;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
declare
c1 clob :='11111111';
amount INTEGER :=3;
off_set INTEGER :=9;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
declare
c1 clob :='11111111';
amount INTEGER :=3;
off_set INTEGER :=10;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
--buffer等于destlob
declare
c1 clob :='1234';
amount INTEGER :=2;
off_set INTEGER :=2;
begin
gms_lob.write(c1, amount, off_set, c1);
gms_output.put_line(c1::text);
end;
/
--VALUEERROR
--lob为空
declare
c1 clob;
amount INTEGER :=3;
off_set INTEGER :=2;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
end;
/
--amount为空
declare
c1 clob :='11111111';
amount INTEGER;
off_set INTEGER :=10;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
end;
/
--offset为空
declare
c1 clob :='11111111';
amount INTEGER :=3;
off_set INTEGER;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
end;
/
--lob无效
declare
amount INTEGER :=3;
off_set INTEGER :=2;
c2 clob :='222';
begin
gms_lob.write('11111111', amount, off_set, c2);
end;
/
--amount大于buffer大小
declare
c1 clob :='11111111';
amount INTEGER :=5;
off_set INTEGER :=2;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
end;
/
--offset超出范围
declare
c1 clob :='11111111';
amount INTEGER :=2;
off_set INTEGER :=0;
c2 clob :='222';
begin
gms_lob.write(c1, amount, off_set, c2);
end;
/
--lob只读
declare
c1 clob :='1111';
amount INTEGER :=2;
off_set INTEGER :=2;
c2 clob :='222';
begin
gms_lob.open(c1, gms_lob.LOB_READONLY);
gms_lob.write(c1, amount, off_set, c2);
end;
/
-----------append函数-----------
--gms_lob.gms_lob_append_blob
declare
b1 blob :=cast_to_raw('11111111');
b2 blob :=cast_to_raw('222');
begin
gms_lob.append(b1, b2);
gms_output.put_line(b1::text);
end;
/
--VALUEERROR
--destlob为空
declare
b1 blob;
b2 blob :=cast_to_raw('222');
begin
gms_lob.append(b1, b2);
end;
/
--srclob为空
declare
b1 blob :=cast_to_raw('11111111');
b2 blob;
begin
gms_lob.append(b1, b2);
end;
/
--lob无效
declare
b2 blob :=cast_to_raw('222');
begin
gms_lob.append(cast_to_raw('1111'), b2);
end;
/
--lob只读
declare
b1 blob :=cast_to_raw('1111');
b2 blob :=cast_to_raw('222');
begin
gms_lob.open(b1, gms_lob.LOB_READONLY);
gms_lob.append(b1, b2);
end;
/
--gms_lob.gms_lob_append_clob
declare
c1 clob :='11111111';
c2 clob :='222';
begin
gms_lob.append(c1, c2);
gms_output.put_line(c1::text);
end;
/
--VALUEERROR
--destlob为空
declare
c1 clob;
c2 clob :='222';
begin
gms_lob.append(c1, c2);
end;
/
--srclob为空
declare
c1 clob :='11111111';
c2 clob;
begin
gms_lob.append(c1, c2);
end;
/
--lob无效
declare
c2 clob :='222';
begin
gms_lob.append('1111', c2);
end;
/
--lob只读
declare
c1 clob :='1111';
c2 clob :='222';
begin
gms_lob.open(c1, gms_lob.LOB_READONLY);
gms_lob.append(c1, c2);
end;
/
declare
b1 blob :=cast_to_raw('ABC123');
amount INTEGER :=3;
off_set INTEGER :=100;
b2 blob :=cast_to_raw('abc');
c1 int;
BEGIN
gms_lob.write(b1,amount,off_set,b2);
gms_output.put_line(b1::text);
c1:=gms_lob.getlength(b1);
gms_output.put_line(c1);
end;
/
declare
c1 clob :='ABC123';
amount INTEGER :=3;
off_set INTEGER :=100;
c2 clob :='abc';
begin
gms_lob.write(c1, amount, off_set, c2);
gms_output.put_line(c1::text);
end;
/
declare
b1 blob :=null;
b2 blob :=cast_to_raw('abc');
BEGIN
gms_lob.append(b1,b2);
gms_output.put_line(b1::text);
end;
/
drop table if exists lob_mvcc;
create table lob_mvcc(id int, c_lob clob, b_lob blob);
insert into lob_mvcc values(1, 'clob', cast_to_raw('blob'));
insert into lob_mvcc values(2, '中文clobobject测试', cast_to_raw('中文blobobject测试'));
select * from lob_mvcc order by id;
declare
c1 clob;
c2 clob :='222test';
begin
select c_lob into c1 from lob_mvcc where id=1 for update;
gms_lob.append(c1, c2);
end;
/
select * from lob_mvcc order by id;
drop table lob_mvcc;
create or replace procedure proc_1034970
as
b1 clob :='测试';
b2 clob :='测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试测试';
begin
gms_lob.open(b1,gms_lob.lob_readwrite);
for i in 1..100 loop
gms_lob.append(b1,b2);
end loop;
end;
/
call proc_1034970();
drop procedure proc_1034970;
\c contrib_regression
drop database if exists testlob;

View File

@ -16327,6 +16327,39 @@ CallFuncStmt: CALL func_name '(' ')'
}
| CALL func_name '(' callfunc_args ')'
{
ListCell* l = list_head($2);
Node* name = (Node*)lfirst(l);
if (IsA(name, String) && (strcmp(strVal(name), "gms_lob") == 0)) {
ListCell* lc = list_head($4);
Node* n1 = (Node*)lfirst(lc);
if (IsA(n1, ColumnRef)) {
char* lobname = strVal(linitial(((ColumnRef*)n1)->fields));
Node* funcname = (Node*)lfirst(list_tail($2));
if (strcmp(strVal(funcname), "createtemporary") == 0) {
if (list_length($4) == 2) {
$4 = lappend($4, makeIntConst(10, -1));
}
}
$4 = lappend($4, makeStringConst(lobname, -1));
} else if (IsA(n1, NamedArgExpr)) {
Node* n2 = ((Node*)((NamedArgExpr*)n1)->arg);
if (IsA(n2, ColumnRef)) {
char* lobname = strVal(linitial(((ColumnRef*)n2)->fields));
Node* funcname = (Node*)lfirst(list_tail($2));
if (strcmp(strVal(funcname), "createtemporary") == 0) {
if (list_length($4) == 2) {
$4 = lappend($4, makeIntConst(10, -1));
}
}
NamedArgExpr *na = makeNode(NamedArgExpr);
na->name = pstrdup("lobname");
na->arg = (Expr *)makeStringConst(lobname, -1);
na->argnumber = -1; /* until determined */
na->location = @1;
$4 = lappend($4, (Node *) na);
}
}
}
#ifndef ENABLE_MULTIPLE_NODES
$$ = makeCallFuncStmt($2, $4, enable_out_param_override());
#else
@ -28745,6 +28778,7 @@ func_expr: func_application within_group_clause filter_clause over_clause
func_application: func_name '(' func_arg_list opt_sort_clause ')'
{
FuncCall *n = makeNode(FuncCall);
ListCell* l = list_head($1);
n->funcname = $1;
n->args = $3;
n->agg_order = $4;
@ -28754,6 +28788,38 @@ func_application: func_name '(' func_arg_list opt_sort_clause ')'
n->over = NULL;
n->location = @1;
n->call_func = false;
Node* name = (Node*)lfirst(l);
if (IsA(name, String) && (strcmp(strVal(name), "gms_lob") == 0)) {
ListCell* lc = list_head($3);
Node* n1 = (Node*)lfirst(lc);
if (IsA(n1, ColumnRef)) {
char* lobname = lobname = strVal(linitial(((ColumnRef*)n1)->fields));
Node* funcname = (Node*)lfirst(list_tail($1));
if (strcmp(strVal(funcname), "createtemporary") == 0) {
if (list_length($4) == 2) {
n->args = lappend(n->args, makeIntConst(10, -1));
};
}
n->args = lappend(n->args, makeStringConst(lobname, -1));
} else if (IsA(n1, NamedArgExpr)) {
Node* n2 = ((Node*)((NamedArgExpr*)n1)->arg);
if (IsA(n2, ColumnRef)) {
char* lobname = strVal(linitial(((ColumnRef*)$1)->fields));
Node* funcname = (Node*)lfirst(list_tail($1));
if (strcmp(strVal(funcname), "createtemporary") == 0) {
if (list_length(n->args) == 2) {
n->args = lappend(n->args, makeIntConst(10, -1));
}
}
NamedArgExpr *na = makeNode(NamedArgExpr);
na->name = pstrdup("lobname");
na->arg = (Expr *)makeStringConst(lobname, -1);
na->argnumber = -1; /* until determined */
na->location = @1;
n->args = lappend(n->args, (Node *) na);
}
}
}
$$ = (Node *)n;
}
| func_application_special { $$ = $1; }
@ -33171,7 +33237,8 @@ makeCallFuncStmt(List* funcname,List* parameters, bool is_call)
if (clist->next)
{
has_overload_func = true;
if (IsPackageFunction(funcname) == false && IsPackageSchemaOid(SchemaNameGetSchemaOid(schemaname, true)) == false)
if (IsPackageFunction(funcname) == false && IsPackageSchemaOid(SchemaNameGetSchemaOid(schemaname, true)) == false &&
(schemaname == NULL || strncmp(schemaname, "gms_lob", strlen("gms_lob"))))
{
const char* message = "function isn't exclusive ";
InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc);
@ -33280,7 +33347,6 @@ makeCallFuncStmt(List* funcname,List* parameters, bool is_call)
}
}
}
i++;
}

View File

@ -7560,7 +7560,8 @@ make_callfunc_stmt(const char *sqlstart, int location, bool is_assign, bool eate
} else {
DeconstructQualifiedName(funcname, &schemaname, &funcStrName, &pkgname);
}
if (IsPackageFunction(funcname) == false && IsPackageSchemaOid(SchemaNameGetSchemaOid(schemaname, true)) == false)
if (IsPackageFunction(funcname) == false && IsPackageSchemaOid(SchemaNameGetSchemaOid(schemaname, true)) == false &&
(schemaname == NULL || strncmp(schemaname, "gms_lob", strlen("gms_lob"))))
{
const char* message = "function is not exclusive";
InsertErrorMessage(message, plpgsql_yylloc);