diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 798c92a..e99f264 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -2168,7 +2168,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) -1 /* varlena array */ , sizeof(Oid) /* OID's typlen */ , true /* OID's typbyval */ , - 'i' /* OID's typalign */ ); + 'i' /* OID's typalign */ , + false /* no inplace update */ ); } repl_val[Anum_pg_extension_extconfig - 1] = PointerGetDatum(a); repl_repl[Anum_pg_extension_extconfig - 1] = true; @@ -2206,7 +2207,8 @@ pg_extension_config_dump(PG_FUNCTION_ARGS) -1 /* varlena array */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - 'i' /* TEXT's typalign */ ); + 'i' /* TEXT's typalign */ , + false /* no inplace update */ ); } repl_val[Anum_pg_extension_extcondition - 1] = PointerGetDatum(a); repl_repl[Anum_pg_extension_extcondition - 1] = true; diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 90c2753..6d0d590 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -456,7 +456,8 @@ ExecEvalArrayRef(ArrayRefExprState *astate, astate->refattrlength, astate->refelemlength, astate->refelembyval, - astate->refelemalign); + astate->refelemalign, + false); else resultArray = array_set_slice(array_source, i, upper.indx, lower.indx, diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c index 7ce1cce..369ea0a 100644 --- a/src/backend/utils/adt/array_userfuncs.c +++ b/src/backend/utils/adt/array_userfuncs.c @@ -147,7 +147,7 @@ array_push(PG_FUNCTION_ARGS) typalign = my_extra->typalign; result = array_set(v, 1, &indx, newelem, isNull, - -1, typlen, typbyval, typalign); + -1, typlen, typbyval, typalign, false); /* * Readjust result's LB to match the input's. This does nothing in the diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 438c3d0..f0f7071 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -2023,6 +2023,7 @@ array_get_slice(ArrayType *array, * elmlen: pg_type.typlen for the array's element type * elmbyval: pg_type.typbyval for the array's element type * elmalign: pg_type.typalign for the array's element type + * inplace_update: true, when is possible try to direct update * * Result: * A new array is returned, just like the old except for the one @@ -2045,7 +2046,8 @@ array_set(ArrayType *array, int arraytyplen, int elmlen, bool elmbyval, - char elmalign) + char elmalign, + bool inplace_update) { ArrayType *newarray; int i, @@ -2208,11 +2210,22 @@ array_set(ArrayType *array, } else { + bool origin_is_null; + offset = ArrayGetOffset(nSubscripts, dim, lb, indx); elt_ptr = array_seek(ARR_DATA_PTR(array), 0, oldnullbitmap, offset, elmlen, elmbyval, elmalign); + + origin_is_null = array_get_isnull(oldnullbitmap, offset); + + if (inplace_update && !isNull && !origin_is_null) + { + ArrayCastAndSet(dataValue, elmlen, elmbyval, elmalign, elt_ptr); + return array; + } + lenbefore = (int) (elt_ptr - ARR_DATA_PTR(array)); - if (array_get_isnull(oldnullbitmap, offset)) + if (origin_is_null) olditemlen = 0; else { diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c index 3107f9c..0d85953 100644 --- a/src/backend/utils/misc/guc.c +++ b/src/backend/utils/misc/guc.c @@ -7959,7 +7959,8 @@ GUCArrayAdd(ArrayType *array, const char *name, const char *value) -1 /* varlena array */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - 'i' /* TEXT's typalign */ ); + 'i' /* TEXT's typalign */ , + false /* no inplace update */ ); } else a = construct_array(&datum, 1, @@ -8029,7 +8030,8 @@ GUCArrayDelete(ArrayType *array, const char *name) -1 /* varlenarray */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - 'i' /* TEXT's typalign */ ); + 'i' /* TEXT's typalign */ , + false /* no inplace update */ ); else newarray = construct_array(&d, 1, TEXTOID, @@ -8097,7 +8099,8 @@ GUCArrayReset(ArrayType *array) -1 /* varlenarray */ , -1 /* TEXT's typlen */ , false /* TEXT's typbyval */ , - 'i' /* TEXT's typalign */ ); + 'i' /* TEXT's typalign */ , + false /* no inplace update */ ); else newarray = construct_array(&d, 1, TEXTOID, diff --git a/src/include/utils/array.h b/src/include/utils/array.h index 95a9249..fcbf84e 100644 --- a/src/include/utils/array.h +++ b/src/include/utils/array.h @@ -219,7 +219,8 @@ extern Datum array_ref(ArrayType *array, int nSubscripts, int *indx, bool *isNull); extern ArrayType *array_set(ArrayType *array, int nSubscripts, int *indx, Datum dataValue, bool isNull, - int arraytyplen, int elmlen, bool elmbyval, char elmalign); + int arraytyplen, int elmlen, bool elmbyval, char elmalign, + bool inplace_update); extern ArrayType *array_get_slice(ArrayType *array, int nSubscripts, int *upperIndx, int *lowerIndx, int arraytyplen, int elmlen, bool elmbyval, char elmalign); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 3b2919c..fe4b265 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4175,6 +4175,7 @@ exec_assign_value(PLpgSQL_execstate *estate, ArrayType *newarrayval; SPITupleTable *save_eval_tuptable; MemoryContext oldcontext; + bool inplace_update; /* * We need to do subscript evaluation, which might require @@ -4321,6 +4322,14 @@ exec_assign_value(PLpgSQL_execstate *estate, oldarrayval = (ArrayType *) DatumGetPointer(oldarraydatum); /* + * support fast update for array scalar variable is enabled only + * when target is a scalar variable and variable holds a local + * copy of some array. + */ + inplace_update = (((PLpgSQL_datum *) target)->dtype == PLPGSQL_DTYPE_VAR + && ((PLpgSQL_var *) target)->freeval); + + /* * Build the modified array value. */ newarrayval = array_set(oldarrayval, @@ -4331,7 +4340,8 @@ exec_assign_value(PLpgSQL_execstate *estate, arrayelem->arraytyplen, arrayelem->elemtyplen, arrayelem->elemtypbyval, - arrayelem->elemtypalign); + arrayelem->elemtypalign, + inplace_update); MemoryContextSwitchTo(oldcontext); @@ -4340,11 +4350,15 @@ exec_assign_value(PLpgSQL_execstate *estate, * at this point. Note that if the target is a domain, * coercing the base array type back up to the domain will * happen within exec_assign_value. + * + * The newarrayval and oldarrayval can be identitic as result + * of implace_update. */ *isNull = false; - exec_assign_value(estate, target, - PointerGetDatum(newarrayval), - arrayelem->arraytypoid, isNull); + if (newarrayval != oldarrayval) + exec_assign_value(estate, target, + PointerGetDatum(newarrayval), + arrayelem->arraytypoid, isNull); break; }