fix clob > 1G unspport error

Offering: openGaussDev

More detail:fix clob > 1G unspport error

Match-id-f3aa081fe8c987e3f540d857a091175c5d28c690
This commit is contained in:
openGaussDev 2022-03-05 15:50:53 +08:00 committed by yanghao
parent 6d95c39328
commit f602677e45
6 changed files with 139 additions and 60 deletions

View File

@ -4596,16 +4596,10 @@ static int exec_stmt_return(PLpgSQL_execstate* estate, PLpgSQL_stmt_return* stmt
case PLPGSQL_DTYPE_VAR: {
PLpgSQL_var* var = (PLpgSQL_var*)retvar;
Datum value = var->value;
if (is_external_clob(var->datatype->typoid, var->isnull, value)) {
bool is_null = false;
bool is_have_huge_clob = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(value));
value = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &is_null, &is_have_huge_clob);
if (is_have_huge_clob) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as return parameter")));
}
if (is_huge_clob(var->datatype->typoid, var->isnull, value)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as return parameter")));
}
if (need_param_seperation) {
estate->paramval = value;
@ -7423,16 +7417,10 @@ void exec_assign_value(PLpgSQL_execstate* estate, PLpgSQL_datum* target, Datum v
MemoryContext oldcontext = NULL;
AttrNumber attrno = ((PLpgSQL_arrayelem*)target)->assignattrno;
if (is_external_clob(valtype, *isNull, value)) {
bool is_null = false;
bool is_have_huge_clob = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(value));
value = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &is_null, &is_have_huge_clob);
if (is_have_huge_clob) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as array element.")));
}
if (is_huge_clob(valtype, *isNull, value)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as array element.")));
}
/*
* We need to do subscript evaluation, which might require
@ -7711,16 +7699,10 @@ void exec_assign_value(PLpgSQL_execstate* estate, PLpgSQL_datum* target, Datum v
MemoryContext oldcontext = NULL;
AttrNumber attrno = ((PLpgSQL_tableelem*)target)->assignattrno;
if (is_external_clob(valtype, *isNull, value)) {
bool is_null = false;
bool is_have_huge_clob = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(value));
value = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &is_null, &is_have_huge_clob);
if (is_have_huge_clob) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as table of element.")));
}
if (is_huge_clob(valtype, *isNull, value)) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as table of element.")));
}
/*
@ -7993,12 +7975,6 @@ void exec_assign_value(PLpgSQL_execstate* estate, PLpgSQL_datum* target, Datum v
/*
* Target has a assign list
*/
if (is_external_clob(valtype, *isNull, value)) {
bool is_null = false;
bool is_have_huge_clob = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(value));
value = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &is_null, &is_have_huge_clob);
}
PLpgSQL_assignlist* assignvar = (PLpgSQL_assignlist*)target;
List* assignlist = assignvar->assignlist;
PLpgSQL_datum* assigntarget = estate->datums[assignvar->targetno];
@ -10794,17 +10770,10 @@ HeapTuple make_tuple_from_row(PLpgSQL_execstate* estate, PLpgSQL_row* row, Tuple
exec_eval_datum(estate, estate->datums[row->varnos[i]], &fieldtypeid, &fieldtypmod, &dvalues[i], &nulls[i]);
}
if (is_external_clob(fieldtypeid, nulls[i], dvalues[i])) {
bool is_null = false;
bool is_have_huge_clob = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(dvalues[i]));
dvalues[i] = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &is_null, &is_have_huge_clob);
if (is_have_huge_clob) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support concat a row")));
}
nulls[i] = is_null;
if (is_huge_clob(fieldtypeid, nulls[i], dvalues[i])) {
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support concat a row")));
}
if (estate->is_exception && fieldtypeid == REFCURSOROID) {

View File

@ -152,6 +152,7 @@ static Datum ExecEvalGroupingIdExpr(
GroupingIdExprState* gstate, ExprContext* econtext, bool* isNull, ExprDoneCond* isDone);
static bool func_has_refcursor_args(Oid Funcid, FunctionCallInfoData* fcinfo);
extern struct varlena *heap_tuple_fetch_and_copy(Relation rel, struct varlena *attr, bool needcheck);
static void check_huge_clob_paramter(FunctionCallInfoData* fcinfo, bool is_have_huge_clob);
THR_LOCAL PLpgSQL_execstate* plpgsql_estate = NULL;
@ -1692,6 +1693,7 @@ static ExprDoneCond ExecEvalFuncArgs(
i = 0;
econtext->is_cursor = false;
u_sess->plsql_cxt.func_tableof_index = NIL;
bool is_have_huge_clob = false;
foreach (arg, argList) {
ExprState* argstate = (ExprState*)lfirst(arg);
ExprDoneCond thisArgIsDone;
@ -1719,6 +1721,9 @@ static ExprDoneCond ExecEvalFuncArgs(
}
fcinfo->argTypes[i] = argstate->resultType;
econtext->is_cursor = false;
if (is_huge_clob(fcinfo->argTypes[i], fcinfo->argnull[i], fcinfo->arg[i])) {
is_have_huge_clob = true;
}
if (thisArgIsDone != ExprSingleResult) {
/*
@ -1734,6 +1739,7 @@ static ExprDoneCond ExecEvalFuncArgs(
}
i++;
}
check_huge_clob_paramter(fcinfo, is_have_huge_clob);
Assert(i == fcinfo->nargs);
@ -2274,6 +2280,7 @@ static Datum ExecMakeFunctionResultNoSets(
bool savedProConfigIsSet = u_sess->SPI_cxt.is_proconfig_set;
bool proIsProcedure = false;
bool supportTranaction = false;
bool is_have_huge_clob = false;
#ifdef ENABLE_MULTIPLE_NODES
if (IS_PGXC_COORDINATOR && (t_thrd.proc->workingVersionNum >= STP_SUPPORT_COMMIT_ROLLBACK)) {
@ -2400,6 +2407,9 @@ static Datum ExecMakeFunctionResultNoSets(
if (has_refcursor && fcinfo->argTypes[i] == REFCURSOROID)
econtext->is_cursor = true;
fcinfo->arg[i] = ExecEvalExpr(argstate, econtext, &fcinfo->argnull[i], NULL);
if (is_huge_clob(fcinfo->argTypes[i], fcinfo->argnull[i], fcinfo->arg[i])) {
is_have_huge_clob = true;
}
ExecTableOfIndexInfo execTableOfIndexInfo;
initExecTableOfIndexInfo(&execTableOfIndexInfo, econtext);
ExecEvalParamExternTableOfIndex((Node*)argstate->expr, &execTableOfIndexInfo);
@ -2452,6 +2462,7 @@ static Datum ExecMakeFunctionResultNoSets(
pgstat_init_function_usage(fcinfo, &fcusage);
fcinfo->isnull = false;
check_huge_clob_paramter(fcinfo, is_have_huge_clob);
if (u_sess->instr_cxt.global_instr != NULL && fcinfo->flinfo->fn_addr == plpgsql_call_handler) {
StreamInstrumentation* save_global_instr = u_sess->instr_cxt.global_instr;
u_sess->instr_cxt.global_instr = NULL;
@ -5991,6 +6002,21 @@ static HeapTuple get_tuple(Relation relation, ItemPointer tid)
return new_tuple;
}
static void check_huge_clob_paramter(FunctionCallInfoData* fcinfo, bool is_have_huge_clob)
{
if (!is_have_huge_clob || IsSystemObjOid(fcinfo->flinfo->fn_oid)) {
return;
}
Oid schema_oid = get_func_namespace(fcinfo->flinfo->fn_oid);
if (IsPackageSchemaOid(schema_oid)) {
return;
}
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("huge clob do not support as function in parameter")));
}
bool is_external_clob(Oid type_oid, bool is_null, Datum value)
{
if (type_oid == CLOBOID && !is_null && VARATT_IS_EXTERNAL_LOB(value)) {
@ -5999,7 +6025,37 @@ bool is_external_clob(Oid type_oid, bool is_null, Datum value)
return false;
}
Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid, bool* is_null, bool* is_huge_clob)
bool is_huge_clob(Oid type_oid, bool is_null, Datum value)
{
if (!is_external_clob(type_oid, is_null, value)) {
return false;
}
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(value));
bool is_huge_clob = false;
/* get relation by relid */
ItemPointerData tuple_ctid;
tuple_ctid.ip_blkid.bi_hi = lob_pointer->bi_hi;
tuple_ctid.ip_blkid.bi_lo = lob_pointer->bi_lo;
tuple_ctid.ip_posid = lob_pointer->ip_posid;
Relation relation = heap_open(lob_pointer->relid, RowExclusiveLock);
HeapTuple origin_tuple = get_tuple(relation, &tuple_ctid);
if (!HeapTupleIsValid(origin_tuple)) {
ereport(ERROR,
(errcode(ERRCODE_CACHE_LOOKUP_FAILED),
errmsg("cache lookup failed for tuple from relation %u", lob_pointer->relid)));
}
bool attr_is_null = false;
Datum attr = fastgetattr(origin_tuple, lob_pointer->columid, relation->rd_att, &attr_is_null);
if (!attr_is_null && VARATT_IS_HUGE_TOAST_POINTER(attr)) {
is_huge_clob = true;
}
heap_close(relation, NoLock);
heap_freetuple(origin_tuple);
return is_huge_clob;
}
Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid, bool* is_null)
{
/* get relation by relid */
ItemPointerData tuple_ctid;
@ -6015,9 +6071,7 @@ Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid
}
Datum attr = fastgetattr(origin_tuple, lob_pointer->columid, relation->rd_att, is_null);
if (!*is_null && VARATT_IS_HUGE_TOAST_POINTER(attr) && is_huge_clob != NULL) {
*is_huge_clob = true;
}
if (!OidIsValid(update_oid)) {
heap_close(relation, NoLock);
@ -6109,7 +6163,7 @@ static bool ExecTargetList(List* targetlist, ExprContext* econtext, Datum* value
bool is_null = false;
Oid update_oid = econtext->ecxt_scantuple != NULL ?
((HeapTuple)(econtext->ecxt_scantuple->tts_tuple))->t_tableOid : InvalidOid;
values[resind] = fetch_lob_value_from_tuple(lob_pointer, update_oid, &is_null, NULL);
values[resind] = fetch_lob_value_from_tuple(lob_pointer, update_oid, &is_null);
isnull[resind] = is_null;
}
}

View File

@ -279,8 +279,7 @@ extern bool create_toast_by_sid(Oid *toastOid);
extern Oid get_toast_oid();
extern varlena* toast_huge_write_datum_slice(struct varlena* attr1, struct varlena* attr2, int64 sliceoffset, int32 length);
extern varlena* toast_pointer_fetch_data(TupleTableSlot* varSlot, Form_pg_attribute attr, int varNumber);
extern Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid,
bool* is_null, bool* is_huge_clob = NULL);
extern Datum fetch_lob_value_from_tuple(varatt_lob_pointer* lob_pointer, Oid update_oid, bool* is_null);
inline Datum fetch_real_lob_if_need(Datum toast_pointer)
{
@ -288,7 +287,7 @@ inline Datum fetch_real_lob_if_need(Datum toast_pointer)
if (VARATT_IS_EXTERNAL_LOB(toast_pointer)) {
bool isNull = false;
struct varatt_lob_pointer* lob_pointer = (varatt_lob_pointer*)(VARDATA_EXTERNAL(toast_pointer));
ret = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &isNull, NULL);
ret = fetch_lob_value_from_tuple(lob_pointer, InvalidOid, &isNull);
if (unlikely(isNull)) {
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("Invalid lob pointer.")));

View File

@ -280,6 +280,7 @@ extern void initExecTableOfIndexInfo(ExecTableOfIndexInfo* execTableOfIndexInfo,
extern bool ExecEvalParamExternTableOfIndexById(ExecTableOfIndexInfo* execTableOfIndexInfo);
extern void ExecEvalParamExternTableOfIndex(Node* node, ExecTableOfIndexInfo* execTableOfIndexInfo);
extern bool is_external_clob(Oid type_oid, bool is_null, Datum value);
extern bool is_huge_clob(Oid type_oid, bool is_null, Datum value);
/*
* prototypes from functions in execTuples.c

View File

@ -67,6 +67,22 @@ ERROR: huge clob do not support as function in parameter
CONTEXT: PL/pgSQL function pro_cb4_031(clob,clob) line 5 at assignment
SQL statement "CALL pro_cb4_031(v1,v2)"
PL/pgSQL function pro_cb4_031_1() line 7 at PERFORM
create or replace procedure pro_cb4_005 is
v1 clob;
v2 clob;
v3 clob;
v4 integer;
begin
execute immediate 'select b from cloblongtbl where a=1' into v1;
dbe_lob.read(v1,10,2,v2);
end;
/
call pro_cb4_005();
pro_cb4_005
-------------
(1 row)
--I2.clob > 1G out
create or replace procedure pro_cb4_031(c1 out clob,c2 out clob)
is
@ -215,7 +231,6 @@ select a,b,length(b),c,length(c) from cloblongtbl where a>5 and a<10 order by 1,
(0 rows)
update cloblongtbl set c='cloblessthan1G';
ERROR: tuple concurrently updated
--I6.record
create or replace procedure pro_cb4_031 is
type ty1 is record(c1 int,c2 clob);
@ -251,8 +266,11 @@ close cor1;
end;
/
call pro_cb4_037();
ERROR: huge clob do not support as record element.
CONTEXT: PL/pgSQL function pro_cb4_037() line 10 at FETCH
pro_cb4_037
-------------
(1 row)
create or replace procedure test_self_update is
v1 clob;
begin
@ -270,11 +288,36 @@ call test_self_update();
(1 row)
create or replace procedure test_update_delete is
v1 clob;
begin
execute immediate 'select b from cloblongtbl where a=1' into v1;
update cloblongtbl set b=v1 where a=1;
rollback;
update cloblongtbl set b=v1 where a=2;
commit;
end;
/
call test_update_delete();
test_update_delete
--------------------
(1 row)
begin;
delete from cloblongtbl where a < 3;
rollback;
begin;
delete from cloblongtbl where a = 1;
delete from cloblongtbl where a = 2;
rollback;
drop table if exists cloblongtbl;
-- clean
drop schema if exists huge_clob cascade;
NOTICE: drop cascades to 4 other objects
DETAIL: drop cascades to function pro_cb4_031_1()
NOTICE: drop cascades to 6 other objects
DETAIL: drop cascades to function pro_cb4_005()
drop cascades to function pro_cb4_031_1()
drop cascades to function pro_cb4_031()
drop cascades to function pro_cb4_037()
drop cascades to function test_self_update()
drop cascades to function test_update_delete()

View File

@ -56,6 +56,19 @@ end;
call pro_cb4_031_1();
create or replace procedure pro_cb4_005 is
v1 clob;
v2 clob;
v3 clob;
v4 integer;
begin
execute immediate 'select b from cloblongtbl where a=1' into v1;
dbe_lob.read(v1,10,2,v2);
end;
/
call pro_cb4_005();
--I2.clob > 1G out
create or replace procedure pro_cb4_031(c1 out clob,c2 out clob)
is