diff --git a/src/bin/gs_guc/cluster_guc.conf b/src/bin/gs_guc/cluster_guc.conf index fe66424cd..b78b67a19 100755 --- a/src/bin/gs_guc/cluster_guc.conf +++ b/src/bin/gs_guc/cluster_guc.conf @@ -258,6 +258,7 @@ hot_standby_feedback|bool|0,0|NULL|NULL| ident_file|string|0,0|NULL|NULL| ignore_checksum_failure|bool|0,0|NULL|Continues processing after a checksum failure.| ignore_system_indexes|bool|0,0|NULL|When ignore_system_indexes set to on, it is very useful for recovering data from the table which system index is corrupted.| +parctl_min_cost|int|-1,2147483647|NULL|NULL| io_control_unit|int|1000,1000000|NULL|NULL| gin_pending_list_limit|int|64,2147483647|kB|NULL| intervalstyle|enum|postgres,postgres_verbose,sql_standard,iso_8601,a|NULL|NULL| diff --git a/src/common/backend/catalog/builtin_funcs.ini b/src/common/backend/catalog/builtin_funcs.ini index f74579dec..de54ec5f3 100755 --- a/src/common/backend/catalog/builtin_funcs.ini +++ b/src/common/backend/catalog/builtin_funcs.ini @@ -352,6 +352,14 @@ "array_recv", 1, AddBuiltinFunc(_0(2400), _1("array_recv"), _2(3), _3(true), _4(false), _5(array_recv), _6(2277), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(3, 2281, 26, 23), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("array_recv"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("I/O"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "array_remove", 1, + AddBuiltinFunc(_0(6555), _1("array_remove"), _2(2), _3(false), _4(false), _5(array_remove), _6(2277), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2277, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("array_remove"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), + AddFuncGroup( + "array_replace", 1, + AddBuiltinFunc(_0(6556), _1("array_replace"), _2(3), _3(false), _4(false), _5(array_replace), _6(2277), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(3, 2277, 2283,2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("array_replace"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), AddFuncGroup( "array_send", 1, AddBuiltinFunc(_0(2401), _1("array_send"), _2(1), _3(true), _4(false), _5(array_send), _6(17), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 2277), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("array_send"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("I/O"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) @@ -2550,6 +2558,14 @@ "fenced_udf_process", 1, AddBuiltinFunc(_0(4207), _1("fenced_udf_process"), _2(1), _3(true), _4(false), _5(fenced_udf_process), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 23), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("fenced_udf_process"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "first", 1, + AddBuiltinFunc(_0(6560), _1("first"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(2283), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), + AddFuncGroup( + "first_transition", 1, + AddBuiltinFunc(_0(6558), _1("first_transition"), _2(2), _3(true), _4(false), _5(first_transition), _6(2283), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2283, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("first_transition"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), AddFuncGroup( "finish", 1, AddBuiltinFunc(_0(1518), _1("finish"), _2(0), _3(true), _4(true), _5(debug_client_finish), _6(2249), _7(PG_PLDEBUG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(0), _21(4, 26, 25, 23, 25), _22(4, 'o', 'o', 'o', 'o'), _23(4, "funcoid", "funcname", "lineno", "query"), _24(NULL), _25("debug_client_finish"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(false), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) @@ -6025,10 +6041,18 @@ "language_handler_out", 1, AddBuiltinFunc(_0(2303), _1("language_handler_out"), _2(1), _3(true), _4(false), _5(language_handler_out), _6(2275), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2280), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("language_handler_out"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("I/O"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "last", 1, + AddBuiltinFunc(_0(6561), _1("last"), _2(1), _3(false), _4(false), _5(aggregate_dummy), _6(2283), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(true), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("aggregate_dummy"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), AddFuncGroup( "last_day", 1, AddBuiltinFunc(_0(4075), _1("last_day"), _2(1), _3(true), _4(false), _5(last_day), _6(1114), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(1, 1114), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("last_day"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) ), + AddFuncGroup( + "last_transition", 1, + AddBuiltinFunc(_0(6559), _1("last_transition"), _2(2), _3(true), _4(false), _5(last_transition), _6(2283), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('i'), _19(0), _20(2, 2283, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("last_transition"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')) + ), AddFuncGroup( "last_value", 1, AddBuiltinFunc(_0(3113), _1("last_value"), _2(1), _3(true), _4(false), _5(window_last_value), _6(2283), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(true), _16(false), _17(false), _18('i'), _19(0), _20(1, 2283), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("window_last_value"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33("fetch the last row value"), _34('f'), _35(NULL), _36(0), _37(false), _38(NULL), _39(NULL), _40(0)) diff --git a/src/common/backend/parser/gram.y b/src/common/backend/parser/gram.y index cb37e00fc..79fd7ef4e 100644 --- a/src/common/backend/parser/gram.y +++ b/src/common/backend/parser/gram.y @@ -17959,6 +17959,7 @@ upsert_clause: n->targetList = $5; $$ = (Node *) n; } else { +#ifdef ENABLE_MULTIPLE_NODES /* check subquery in set clause*/ ListCell* cell = NULL; ResTarget* res = NULL; @@ -17966,14 +17967,14 @@ upsert_clause: res = (ResTarget*)lfirst(cell); if (IsA(res->val,SubLink)) { const char* message = "Update with subquery is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement."; - InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); + InsertErrorMessage(message, u_sess->plsql_cxt.plpgsql_yylloc); ereport(errstate, (errmodule(MOD_PARSER), errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("Update with subquery is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement."))); } } - +#endif UpsertClause *uc = makeNode(UpsertClause); uc->targetList = $5; uc->location = @1; diff --git a/src/common/backend/utils/adt/Makefile b/src/common/backend/utils/adt/Makefile index 608403ecb..59699cb22 100644 --- a/src/common/backend/utils/adt/Makefile +++ b/src/common/backend/utils/adt/Makefile @@ -39,7 +39,7 @@ OBJS = acl.o arrayfuncs.o array_selfuncs.o array_typanalyze.o \ tsquery_op.o tsquery_rewrite.o tsquery_util.o tsrank.o \ tsvector.o tsvector_op.o tsvector_parser.o \ txid.o uuid.o windowfuncs.o xml.o extended_statistics.o clientlogic_bytea.o clientlogicsettings.o \ - median_aggs.o expr_distinct.o nlssort.o + median_aggs.o expr_distinct.o nlssort.o first_last_agg.o like.o: like.cpp like_match.cpp diff --git a/src/common/backend/utils/adt/arrayfuncs.cpp b/src/common/backend/utils/adt/arrayfuncs.cpp index 621ca0f01..3ec36d6f2 100644 --- a/src/common/backend/utils/adt/arrayfuncs.cpp +++ b/src/common/backend/utils/adt/arrayfuncs.cpp @@ -5531,6 +5531,279 @@ Datum array_unnest(PG_FUNCTION_ARGS) } } +/* + * check if search is same as replace + */ +static bool array_same_replace(FunctionCallInfo locfcinfo, Datum search, bool search_isnull, + Datum replace, bool replace_isnull) +{ + if (search_isnull != replace_isnull) { + return false; + } else if (search_isnull == true) { + Assert(replace_isnull); + return true; + } else { + locfcinfo->arg[0] = search; + locfcinfo->arg[1] = replace; + locfcinfo->argnull[0] = search_isnull; + locfcinfo->argnull[1] = replace_isnull; + locfcinfo->isnull = false; + return DatumGetBool(FunctionCallInvoke(locfcinfo)); + } +} + +/* + * array_replace/array_remove support + * + * Find all array entries matching (not distinct from) search/search_isnull, + * and delete them if remove is true, else replace them with + * replace/replace_isnull. Comparisons are done using the specified + * collation. fcinfo is passed only for caching purposes. + */ +static ArrayType *array_replace_internal(ArrayType *array, Datum search, bool search_isnull, Datum replace, + bool replace_isnull, bool remove, Oid collation, FunctionCallInfo fcinfo) +{ + + ArrayType *result = NULL; + Oid element_type; + Datum *values = NULL; + bool *nulls = NULL; + int *dim = NULL; + int ndim; + int nitems; + int nresult; + int i; + int32 nbytes = 0; + int32 dataoffset; + bool hasnulls = false; + int typlen; + bool typbyval = false; + char typalign; + char *arraydataptr = NULL; + bits8 *bitmap = NULL; + int bitmask; + bool changed = false; + TypeCacheEntry *typentry = NULL; + FunctionCallInfoData locfcinfo; + errno_t rc = EOK; + + element_type = ARR_ELEMTYPE(array); + ndim = ARR_NDIM(array); + dim = ARR_DIMS(array); + nitems = ArrayGetNItems(ndim, dim); + /* Return input array unmodified if it is empty */ + if (nitems <= 0) + return array; + /* + * We can't remove elements from multi-dimensional arrays, since the + * result might not be rectangular. + */ + if (remove && ndim > 1) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("removing elements from multidimensional arrays is not supported"))); + /* + * We arrange to look up the equality function only once per series of + * calls, assuming the element type doesn't change underneath us. + */ + typentry = (TypeCacheEntry *) fcinfo->flinfo->fn_extra; + if (typentry == NULL || typentry->type_id != element_type) { + typentry = lookup_type_cache(element_type, TYPECACHE_EQ_OPR_FINFO); + if (!OidIsValid(typentry->eq_opr_finfo.fn_oid)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("could not identify an equality operator for type %s", + format_type_be(element_type)))); + fcinfo->flinfo->fn_extra = (void *) typentry; + } + typlen = typentry->typlen; + typbyval = typentry->typbyval; + typalign = typentry->typalign; + /* + * Detoast values if they are toasted. The replacement value must be + * detoasted for insertion into the result array, while detoasting the + * search value only once saves cycles. + */ + if (typlen == -1) { + if (!search_isnull) + search = PointerGetDatum(PG_DETOAST_DATUM(search)); + if (!replace_isnull) + replace = PointerGetDatum(PG_DETOAST_DATUM(replace)); + } + /* Prepare to apply the comparison operator */ + InitFunctionCallInfoData(locfcinfo, &typentry->eq_opr_finfo, 2, collation, NULL, NULL); + /* directly return if search is same as replace */ + if (!remove && array_same_replace(&locfcinfo, search, search_isnull, replace, replace_isnull)) { + return array; + } + /* Allocate temporary arrays for new values */ + values = (Datum *) palloc(nitems * sizeof(Datum)); + nulls = (bool *) palloc(nitems * sizeof(bool)); + /* Loop over source data */ + arraydataptr = ARR_DATA_PTR(array); + bitmap = ARR_NULLBITMAP(array); + bitmask = 1; + hasnulls = false; + nresult = 0; + for (i = 0; i < nitems; i++) { + Datum elt; + bool isNull = false; + bool oprresult = false; + bool skip = false; + /* Get source element, checking for NULL */ + if (bitmap && (*bitmap & bitmask) == 0) { + isNull = true; + /* If searching for NULL, we have a match */ + if (search_isnull) { + if (remove) { + skip = true; + changed = true; + } else if (!replace_isnull) { + values[nresult] = replace; + isNull = false; + changed = true; + } + } + } else { + isNull = false; + elt = fetch_att(arraydataptr, typbyval, typlen); + arraydataptr = att_addlength_datum(arraydataptr, typlen, elt); + arraydataptr = (char *) att_align_nominal(arraydataptr, typalign); + if (search_isnull) { + /* no match possible, keep element */ + values[nresult] = elt; + } else { + /* Compare the pair of elements */ + locfcinfo.arg[0] = elt; + locfcinfo.arg[1] = search; + locfcinfo.argnull[0] = false; + locfcinfo.argnull[1] = false; + locfcinfo.isnull = false; + oprresult = DatumGetBool(FunctionCallInvoke(&locfcinfo)); + if (locfcinfo.isnull || !oprresult) { + /* no match, keep element */ + values[nresult] = elt; + } else { + /* match, so replace or delete */ + changed = true; + if (remove) { + skip = true; + } else { + values[nresult] = replace; + isNull = replace_isnull; + } + } + } + } + if (!skip) { + nulls[nresult] = isNull; + if (isNull) { + hasnulls = true; + } else { + /* Update total result size */ + nbytes = att_addlength_datum(nbytes, typlen, values[nresult]); + nbytes = att_align_nominal(nbytes, typalign); + /* check for overflow of total request */ + if (!AllocSizeIsValid(nbytes)) + ereport(ERROR, + (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), + errmsg("array size exceeds the maximum allowed (%d)", + (int) MaxAllocSize))); + } + nresult++; + } + /* advance bitmap pointer if any */ + if (bitmap) { + bitmask <<= 1; + if (bitmask == 0x100) { + bitmap++; + bitmask = 1; + } + } + } + /* + * If not changed just return the original array + */ + if (!changed) { + pfree(values); + pfree(nulls); + return array; + } + /* If all elements were removed return an empty array */ + if (nresult == 0) { + pfree(values); + pfree(nulls); + return construct_empty_array(element_type); + } + /* Allocate and initialize the result array */ + if (hasnulls) { + dataoffset = ARR_OVERHEAD_WITHNULLS(ndim, nresult); + nbytes += dataoffset; + } else { + dataoffset = 0; /* marker for no null bitmap */ + nbytes += ARR_OVERHEAD_NONULLS(ndim); + } + result = (ArrayType *) palloc0(nbytes); + SET_VARSIZE(result, nbytes); + result->ndim = ndim; + result->dataoffset = dataoffset; + result->elemtype = element_type; + rc = memcpy_s(ARR_DIMS(result), nbytes - sizeof(ArrayType), ARR_DIMS(array), ndim * sizeof(int)); + securec_check(rc, "\0", "\0"); + rc = memcpy_s(ARR_LBOUND(result), nbytes - (sizeof(ArrayType) + sizeof(int) * ndim), + ARR_LBOUND(array), ndim * sizeof(int)); + securec_check(rc, "\0", "\0"); + + if (remove) { + /* Adjust the result length */ + ARR_DIMS(result)[0] = nresult; + } + /* Insert data into result array */ + CopyArrayEls(result, values, nulls, nresult, typlen, typbyval, typalign, false); + pfree(values); + pfree(nulls); + return result; +} + +/* + * Remove any occurrences of an element from an array + * + * If used on a multi-dimensional array this will raise an error. + */ +Datum array_remove(PG_FUNCTION_ARGS) +{ + ArrayType *array = NULL; + Datum search = PG_GETARG_DATUM(1); + bool search_isnull = PG_ARGISNULL(1); + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + array = PG_GETARG_ARRAYTYPE_P(0); + array = array_replace_internal(array, search, search_isnull, (Datum) 0, true, true, PG_GET_COLLATION(), fcinfo); + PG_RETURN_ARRAYTYPE_P(array); +} + +/* + * Replace any occurrences of an element in an array + */ +Datum array_replace(PG_FUNCTION_ARGS) +{ + ArrayType *array = NULL; + Datum search = PG_GETARG_DATUM(1); + bool search_isnull = PG_ARGISNULL(1); + Datum replace = PG_GETARG_DATUM(2); + bool replace_isnull = PG_ARGISNULL(2); + + if (PG_ARGISNULL(0)) + PG_RETURN_NULL(); + + array = PG_GETARG_ARRAYTYPE_P(0); + array = array_replace_internal(array, search, search_isnull, replace, replace_isnull, false, PG_GET_COLLATION(), + fcinfo); + PG_RETURN_ARRAYTYPE_P(array); +} + /* * The type, dimension needs to be checked during collection operations. */ diff --git a/src/common/backend/utils/adt/first_last_agg.cpp b/src/common/backend/utils/adt/first_last_agg.cpp index b4f0edeca..0ed8c2ed8 100644 --- a/src/common/backend/utils/adt/first_last_agg.cpp +++ b/src/common/backend/utils/adt/first_last_agg.cpp @@ -32,4 +32,4 @@ Datum first_transition(PG_FUNCTION_ARGS) Datum last_transition(PG_FUNCTION_ARGS) { PG_RETURN_DATUM(PG_GETARG_DATUM(1)); -} \ No newline at end of file +} diff --git a/src/common/backend/utils/adt/ruleutils.cpp b/src/common/backend/utils/adt/ruleutils.cpp index 1ada3a81f..c5c2531c4 100644 --- a/src/common/backend/utils/adt/ruleutils.cpp +++ b/src/common/backend/utils/adt/ruleutils.cpp @@ -4601,10 +4601,12 @@ static void set_deparse_planstate(deparse_namespace* dpns, PlanState* ps) #ifdef ENABLE_MULTIPLE_NODES if (IsA(ps, ModifyTableState)) - dpns->inner_tlist = ((ModifyTableState*)ps)->mt_upsert->us_excludedtlist; - else +#else + if (IsA(ps, ModifyTableState) && ((ModifyTableState*)ps)->mt_upsert != NULL && + ((ModifyTableState*)ps)->mt_upsert->us_action != UPSERT_NONE) #endif - if (dpns->inner_planstate != NULL) + dpns->inner_tlist = ((ModifyTableState*)ps)->mt_upsert->us_excludedtlist; + else if (dpns->inner_planstate != NULL) dpns->inner_tlist = dpns->inner_planstate->plan->targetlist; else dpns->inner_tlist = NIL; diff --git a/src/common/backend/utils/misc/guc/guc_resource.cpp b/src/common/backend/utils/misc/guc/guc_resource.cpp index 50e873a27..a59123308 100644 --- a/src/common/backend/utils/misc/guc/guc_resource.cpp +++ b/src/common/backend/utils/misc/guc/guc_resource.cpp @@ -1006,7 +1006,7 @@ static bool check_cgroup_name(char** newval, void** extra, GucSource source) p = *newval; - if (StringIsValid(p) && IS_PGXC_COORDINATOR && t_thrd.shemem_ptr_cxt.MyBEEntry && + if (StringIsValid(p) && IS_SERVICE_NODE && t_thrd.shemem_ptr_cxt.MyBEEntry && (currentGucContext == PGC_SUSET || currentGucContext == PGC_USERSET)) { if (g_instance.wlm_cxt->gscgroup_init_done == 0) ereport(ERROR, @@ -1035,7 +1035,7 @@ static bool check_cgroup_name(char** newval, void** extra, GucSource source) static void assign_cgroup_name(const char* newval, void* extra) { /* set "control_group" global variable */ - if (IS_PGXC_COORDINATOR && t_thrd.shemem_ptr_cxt.MyBEEntry && newval && *newval) { + if (IS_SERVICE_NODE && t_thrd.shemem_ptr_cxt.MyBEEntry && newval && *newval) { if (g_instance.wlm_cxt->gscgroup_init_done == 0) return; diff --git a/src/gausskernel/cbb/workload/workload.cpp b/src/gausskernel/cbb/workload/workload.cpp index cb655d035..df5118197 100755 --- a/src/gausskernel/cbb/workload/workload.cpp +++ b/src/gausskernel/cbb/workload/workload.cpp @@ -1796,7 +1796,7 @@ bool WLMIsSimpleQuery(const QueryDesc* queryDesc, bool force_control, bool isQue g_wlm_params->use_planA = false; - if (IS_PGXC_DATANODE || (IS_PGXC_COORDINATOR && IsConnFromCoord()) || + if (COORDINATOR_NOT_SINGLE || (IS_SERVICE_NODE && IsConnFromCoord()) || u_sess->attr.attr_resource.parctl_min_cost < 0) { return true; } @@ -1875,7 +1875,7 @@ bool WLMIsSimpleQuery(const QueryDesc* queryDesc, bool force_control, bool isQue */ bool WLMNeedTrackResource(const QueryDesc* queryDesc) { - if ((!(IS_SINGLE_NODE || IS_PGXC_COORDINATOR)) || (IS_PGXC_COORDINATOR && IsConnFromCoord()) || + if (!IS_SERVICE_NODE || (IS_PGXC_COORDINATOR && IsConnFromCoord()) || t_thrd.wlm_cxt.collect_info->sdetail.statement == NULL || !u_sess->attr.attr_resource.enable_resource_track || u_sess->attr.attr_resource.resource_track_cost < 0 || u_sess->attr.attr_sql.enable_cluster_resize || t_thrd.wlm_cxt.parctl_state.special) { @@ -2929,7 +2929,7 @@ void WLMSwitchCGroup(void) } /* simple query will skip the cgroup loading */ - if (IS_PGXC_COORDINATOR && (IsConnFromCoord() || t_thrd.wlm_cxt.parctl_state.simple)) { + if (IS_SERVICE_NODE && (IsConnFromCoord() || t_thrd.wlm_cxt.parctl_state.simple)) { return; } diff --git a/src/gausskernel/optimizer/plan/streamplan_utils.cpp b/src/gausskernel/optimizer/plan/streamplan_utils.cpp index 823fbaf29..50a0a6975 100755 --- a/src/gausskernel/optimizer/plan/streamplan_utils.cpp +++ b/src/gausskernel/optimizer/plan/streamplan_utils.cpp @@ -160,6 +160,12 @@ List* check_op_list_template(Plan* result_plan, List* (*check_eval)(Node*)) res_list = list_concat_unique(res_list, check_eval((Node*)splan->resconstantqual)); } break; + case T_ModifyTable: { + ModifyTable* splan = (ModifyTable*)result_plan; + if (splan->upsertAction == UPSERT_UPDATE && splan->updateTlist != NULL) { + res_list = list_concat_unique(res_list, check_eval((Node*)splan->updateTlist)); + } + } break; default: break; } diff --git a/src/gausskernel/process/tcop/utility.cpp b/src/gausskernel/process/tcop/utility.cpp index 048c79933..c312f8c36 100755 --- a/src/gausskernel/process/tcop/utility.cpp +++ b/src/gausskernel/process/tcop/utility.cpp @@ -6389,9 +6389,6 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi break; case T_CreateResourcePoolStmt: -#ifndef ENABLE_MULTIPLE_NODES - DISTRIBUTED_FEATURE_NOT_SUPPORTED(); -#endif if (IS_PGXC_COORDINATOR && !IsConnFromCoord()) { char* first_exec_node = find_first_exec_cn(); bool is_first_node = (strcmp(first_exec_node, g_instance.attr.attr_common.PGXCNodeName) == 0); @@ -6448,9 +6445,6 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi break; case T_AlterResourcePoolStmt: -#ifndef ENABLE_MULTIPLE_NODES - DISTRIBUTED_FEATURE_NOT_SUPPORTED(); -#endif if (IS_PGXC_COORDINATOR) { char* first_exec_node = find_first_exec_cn(); bool is_first_node = (strcmp(first_exec_node, g_instance.attr.attr_common.PGXCNodeName) == 0); @@ -6471,9 +6465,6 @@ void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamLi break; case T_DropResourcePoolStmt: -#ifndef ENABLE_MULTIPLE_NODES - DISTRIBUTED_FEATURE_NOT_SUPPORTED(); -#endif if (IS_PGXC_COORDINATOR) { char* first_exec_node = find_first_exec_cn(); bool is_first_node = (strcmp(first_exec_node, g_instance.attr.attr_common.PGXCNodeName) == 0); diff --git a/src/gausskernel/runtime/executor/execUtils.cpp b/src/gausskernel/runtime/executor/execUtils.cpp index d1317faf3..3ac236766 100644 --- a/src/gausskernel/runtime/executor/execUtils.cpp +++ b/src/gausskernel/runtime/executor/execUtils.cpp @@ -1565,6 +1565,10 @@ bool ExecCheckIndexConstraints(TupleTableSlot *slot, EState *estate, Relation ta ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("INSERT ON DUPLICATE KEY UPDATE does not support deferrable" " unique constraints/exclusion constraints."))); + /* + * We consider a partitioned table with a global index as a normal table, + * because conflicts can be between multiple partitions. + */ if (isPartitioned && !isgpi) { partitionedindexid = RelationGetRelid(indexRelation); diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h index 99ee00ead..0539ad01c 100644 --- a/src/include/catalog/pg_aggregate.h +++ b/src/include/catalog/pg_aggregate.h @@ -338,6 +338,10 @@ DATA(insert ( 3545 bytea_string_agg_transfn - bytea_string_agg_finalfn 0 2281 _ DATA(insert ( 3124 json_agg_transfn - json_agg_finalfn 0 2281 _null_ _null_ n 0)); DATA(insert ( 3403 json_object_agg_transfn - json_object_agg_finalfn 0 2281 _null_ _null_ n 0)); +/* first last */ +DATA(insert ( 6560 first_transition - - 0 2283 _null_ _null_ n 0)); +DATA(insert ( 6561 last_transition - - 0 2283 _null_ _null_ n 0)); + /* hll distribute agg */ DATA(insert ( 4366 hll_add_trans0 hll_union_collect hll_pack 0 4370 _null_ _null_ n 0)); #define HLL_ADD_TRANS0_OID 4366 diff --git a/src/include/pgxc/pgxc.h b/src/include/pgxc/pgxc.h index 1e63c3008..cfe548770 100644 --- a/src/include/pgxc/pgxc.h +++ b/src/include/pgxc/pgxc.h @@ -45,6 +45,7 @@ typedef enum { #define IS_SINGLE_NODE (g_instance.role == VSINGLENODE) #define REMOTE_CONN_TYPE u_sess->attr.attr_common.remoteConnType #define COORDINATOR_NOT_SINGLE (g_instance.role == VDATANODE && g_instance.role != VSINGLENODE) +#define IS_SERVICE_NODE (g_instance.role == VCOORDINATOR || g_instance.role == VSINGLENODE) #define IsConnFromApp() (u_sess->attr.attr_common.remoteConnType == REMOTE_CONN_APP) #define IsConnFromCoord() (u_sess->attr.attr_common.remoteConnType == REMOTE_CONN_COORD) diff --git a/src/test/regress/expected/first_last_agg.out b/src/test/regress/expected/first_last_agg.out index b9aada2a6..0ed0af23a 100644 --- a/src/test/regress/expected/first_last_agg.out +++ b/src/test/regress/expected/first_last_agg.out @@ -1,10 +1,10 @@ select oid, * from pg_proc where proname in ('first', 'first_transition', 'last', 'last_transition') order by oid; - oid | proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext -------+------------------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+------------------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+--------------------- - 6558 | first_transition | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 2283 | 2283 2283 | | | | | first_transition | | | | | f | | f | f | | 0 | f | | - 6559 | last_transition | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 2283 | 2283 2283 | | | | | last_transition | | | | | f | | f | f | | 0 | f | | - 6560 | first | 11 | 10 | 12 | 1 | 0 | 0 | - | t | f | f | f | f | f | i | 1 | 0 | 2283 | 2283 | | | | | aggregate_dummy | | | | | f | | f | f | | 0 | f | | - 6561 | last | 11 | 10 | 12 | 1 | 0 | 0 | - | t | f | f | f | f | f | i | 1 | 0 | 2283 | 2283 | | | | | aggregate_dummy | | | | | f | | f | f | | 0 | f | | + oid | proname | pronamespace | proowner | prolang | procost | prorows | provariadic | protransform | proisagg | proiswindow | prosecdef | proleakproof | proisstrict | proretset | provolatile | pronargs | pronargdefaults | prorettype | proargtypes | proallargtypes | proargmodes | proargnames | proargdefaults | prosrc | probin | proconfig | proacl | prodefaultargpos | fencedmode | proshippable | propackage | prokind | proargsrc | propackageid | proisprivate | proargtypesext | prodefaultargposext | allargtypes | allargtypesext +------+------------------+--------------+----------+---------+---------+---------+-------------+--------------+----------+-------------+-----------+--------------+-------------+-----------+-------------+----------+-----------------+------------+-------------+----------------+-------------+-------------+----------------+------------------+--------+-----------+--------+------------------+------------+--------------+------------+---------+-----------+--------------+--------------+----------------+---------------------+-------------+---------------- + 6558 | first_transition | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 2283 | 2283 2283 | | | | | first_transition | | | | | f | | f | f | | 0 | f | | | 2283 2283 | + 6559 | last_transition | 11 | 10 | 12 | 1 | 0 | 0 | - | f | f | f | f | t | f | i | 2 | 0 | 2283 | 2283 2283 | | | | | last_transition | | | | | f | | f | f | | 0 | f | | | 2283 2283 | + 6560 | first | 11 | 10 | 12 | 1 | 0 | 0 | - | t | f | f | f | f | f | i | 1 | 0 | 2283 | 2283 | | | | | aggregate_dummy | | | | | f | | f | f | | 0 | f | | | 2283 | + 6561 | last | 11 | 10 | 12 | 1 | 0 | 0 | - | t | f | f | f | f | f | i | 1 | 0 | 2283 | 2283 | | | | | aggregate_dummy | | | | | f | | f | f | | 0 | f | | | 2283 | (4 rows) create table first_last_test(a int, b int, c int, d int); diff --git a/src/test/regress/expected/merge_1.out b/src/test/regress/expected/merge_1.out index 61b5725b5..02e66e9dc 100644 --- a/src/test/regress/expected/merge_1.out +++ b/src/test/regress/expected/merge_1.out @@ -51,6 +51,27 @@ INSERT INTO newproducts_row SELECT * FROM newproducts_base; ANALYZE products_row; ANALYZE newproducts_row; -- explain verbose +EXPLAIN (VERBOSE on, COSTS off) +MERGE INTO products_row p +USING newproducts_row np +ON p.product_id = np.product_id +WHEN MATCHED THEN + UPDATE SET product_name = np.product_name, category = np.category, total = np.total where np.product_id = 5; + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- + Merge on mergeinto_1.products_row p + Update Cond: (p.product_id = 5) + -> Hash Join + Output: np.product_id, np.product_name, np.category, np.total, p.product_id, p.product_name, p.category, p.total, p.ctid, np.ctid + Hash Cond: (p.product_id = np.product_id) + -> Seq Scan on mergeinto_1.products_row p + Output: p.product_id, p.product_name, p.category, p.total, p.ctid + -> Hash + Output: np.product_id, np.product_name, np.category, np.total, np.ctid + -> Seq Scan on mergeinto_1.newproducts_row np + Output: np.product_id, np.product_name, np.category, np.total, np.ctid +(11 rows) + EXPLAIN (VERBOSE on, COSTS off) MERGE INTO products_row p USING newproducts_row np @@ -59,26 +80,19 @@ WHEN MATCHED THEN UPDATE SET product_name = np.product_name, category = np.category, total = np.total WHEN NOT MATCHED THEN INSERT VALUES (np.product_id, np.product_name, np.category, np.total); - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- - Streaming (type: GATHER) - Node/s: All datanodes - -> Merge on mergeinto_1.products_row p - -> Streaming(type: REDISTRIBUTE) - Output: np.product_id, np.product_name, np.category, np.total, p.product_id, p.product_name, p.category, p.total, p.ctid, p.xc_node_id, np.ctid, (CASE WHEN (p.ctid IS NULL) THEN np.product_id ELSE p.product_id END) - Distribute Key: (CASE WHEN (p.ctid IS NULL) THEN np.product_id ELSE p.product_id END) - Spawn on: All datanodes - Consumer Nodes: All datanodes - -> Nested Loop Left Join - Output: np.product_id, np.product_name, np.category, np.total, p.product_id, p.product_name, p.category, p.total, p.ctid, p.xc_node_id, np.ctid, CASE WHEN (p.ctid IS NULL) THEN np.product_id ELSE p.product_id END - Join Filter: (p.product_id = np.product_id) - -> Seq Scan on mergeinto_1.newproducts_row np - Output: np.product_id, np.product_name, np.category, np.total, np.ctid - Distribute Key: np.product_id - -> Seq Scan on mergeinto_1.products_row p - Output: p.product_id, p.product_name, p.category, p.total, p.ctid, p.xc_node_id - Distribute Key: p.product_id -(17 rows) + QUERY PLAN +------------------------------------------------------------------------------------------------------------------------------------------- + Merge on mergeinto_1.products_row p + -> Hash Right Join + Output: np.product_id, np.product_name, np.category, np.total, p.product_id, p.product_name, p.category, p.total, p.ctid, np.ctid + Hash Cond: (p.product_id = np.product_id) + -> Seq Scan on mergeinto_1.products_row p + Output: p.product_id, p.product_name, p.category, p.total, p.ctid + -> Hash + Output: np.product_id, np.product_name, np.category, np.total, np.ctid + -> Seq Scan on mergeinto_1.newproducts_row np + Output: np.product_id, np.product_name, np.category, np.total, np.ctid +(10 rows) -- only MATCHED clause MERGE INTO products_row p diff --git a/src/test/regress/expected/single_node_opr_sanity.out b/src/test/regress/expected/single_node_opr_sanity.out index 9888b3851..06d86be2c 100755 --- a/src/test/regress/expected/single_node_opr_sanity.out +++ b/src/test/regress/expected/single_node_opr_sanity.out @@ -1456,6 +1456,12 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1; 6422 | numeric 6433 | numeric 6434 | numeric_bool + 6555 | array_remove + 6556 | array_replace + 6558 | first_transition + 6559 | last_transition + 6560 | first + 6561 | last 6666 | network_larger 6667 | network_smaller 6668 | max diff --git a/src/test/regress/expected/upsert_prepare.out b/src/test/regress/expected/upsert_prepare.out index 8baa91645..b3217b29d 100644 --- a/src/test/regress/expected/upsert_prepare.out +++ b/src/test/regress/expected/upsert_prepare.out @@ -74,6 +74,8 @@ create table pkt (a int primary key, b int, c int); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "pkt_pkey" for table "pkt" create table fkt (a int primary key, b int references pkt, c int); NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "fkt_pkey" for table "fkt" +create table up_neg_11(c1 int, c2 int) partition by range(c1)(partition p1 values less than(10), partition p2 values less than(maxvalue)); +create unique index index_up_neg_11 on up_neg_11(c2); -- procedure test CREATE SCHEMA upsert_test_procedure; -- explain test diff --git a/src/test/regress/expected/upsert_restriction.out b/src/test/regress/expected/upsert_restriction.out index 5d64ea9c8..0efdbb8fe 100644 --- a/src/test/regress/expected/upsert_restriction.out +++ b/src/test/regress/expected/upsert_restriction.out @@ -32,6 +32,7 @@ insert into up_neg_07 select a,a,a from generate_series(1,20) as a; insert into up_neg_08 select a,a,a from generate_series(1,20) as a; insert into up_neg_09 select a,a,a from generate_series(1,20) as a; insert into up_neg_10 select a,a,a from generate_series(1,20) as a; +insert into up_neg_11 values(1,1),(2,2),(11,11),(12,12); -- table cases ---- col table insert into up_neg_01 values(1,2,3) on duplicate key update c3 = 1; @@ -103,12 +104,6 @@ insert into up_neg_05 values(1,1,1,1,1) on duplicate key update c4 = 1 from up_n ERROR: syntax error at or near "from" LINE 1: ... values(1,1,1,1,1) on duplicate key update c4 = 1 from up_ne... ^ ----- sub query -insert into up_neg_05 values(1,1,1,1,1) on duplicate key update (c2) = (select c2 from up_neg_05); -ERROR: Update with subquery is not yet supported whithin INSERT ON DUPLICATE KEY UPDATE statement. ----- update distribute key -insert into up_neg_06 values(101, 1, 1) on duplicate key update c3=101; -ERROR: INSERT ON DUPLICATE KEY UPDATE don't allow update on primary key or unique key. ---- update partition key insert into up_neg_07 values(101, 1, 300) on duplicate key update c3=101; ERROR: INSERT ON DUPLICATE KEY UPDATE don't allow update on primary key or unique key. @@ -120,6 +115,22 @@ insert into up_neg_09 values(101, 1, 1) on duplicate key update c2=101; ERROR: INSERT ON DUPLICATE KEY UPDATE don't allow update on primary key or unique key. insert into up_neg_09 values(101, 1, 1) on duplicate key update c2 =1,c3=101; ERROR: INSERT ON DUPLICATE KEY UPDATE don't allow update on primary key or unique key. +---- cross-partition upsert +insert into up_neg_11 values(1, 1) on duplicate key update c1 = 15; +select * from up_neg_11 partition(p1); + c1 | c2 +----+---- + 2 | 2 +(1 row) + +select * from up_neg_11 partition(p2); + c1 | c2 +----+---- + 11 | 11 + 12 | 12 + 15 | 1 +(3 rows) + --update unique key mul type plans EXPLAIN (VERBOSE on, COSTS off) insert into up_neg_10 values(101, 1, 300) on duplicate key update c1=101; QUERY PLAN diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 258bcc4af..8f5332c1b 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -14,7 +14,7 @@ test: analyze_commands test: single_node_ddl test: single_node_sqlbypass #test: mediavarchar.cppn -#test: array_funcs first_last_agg +test: array_funcs first_last_agg test: get_instr_unique_sql # run tablespace by itself, and first, because it forces a checkpoint; @@ -165,8 +165,7 @@ test: single_node_sequence # run and check forbidden functions are still forbidden to use in single node test: single_node_forbidden -test: single_node_mergeinto -#test: merge_1 +test: single_node_mergeinto merge_1 # Trigger tests test: single_node_triggers @@ -332,7 +331,7 @@ test: upsert_001 upsert_002 upsert_003 upsert_008 upsert_009 upsert_010 test: upsert_grammer_test_01 upsert_unlog_test upsert_tmp_test test: upsert_grammer_test_02 upsert_restriction upsert_composite test: upsert_trigger_test upsert_explain -#test: upsert_subquery +test: upsert_subquery test: upsert_clean # all pass diff --git a/src/test/regress/pg_regress.cpp b/src/test/regress/pg_regress.cpp index 1843c9d9e..a509766ce 100644 --- a/src/test/regress/pg_regress.cpp +++ b/src/test/regress/pg_regress.cpp @@ -5158,7 +5158,7 @@ static void check_global_variables() } } -#define BASE_PGXC_LIKE_MACRO_NUM 1416 +#define BASE_PGXC_LIKE_MACRO_NUM 1415 static void check_pgxc_like_macros() { #ifdef BUILD_BY_CMAKE diff --git a/src/test/regress/sql/merge_1.sql b/src/test/regress/sql/merge_1.sql index b6e856c4c..51c8349fa 100644 --- a/src/test/regress/sql/merge_1.sql +++ b/src/test/regress/sql/merge_1.sql @@ -64,6 +64,13 @@ ANALYZE products_row; ANALYZE newproducts_row; -- explain verbose +EXPLAIN (VERBOSE on, COSTS off) +MERGE INTO products_row p +USING newproducts_row np +ON p.product_id = np.product_id +WHEN MATCHED THEN + UPDATE SET product_name = np.product_name, category = np.category, total = np.total where np.product_id = 5; + EXPLAIN (VERBOSE on, COSTS off) MERGE INTO products_row p USING newproducts_row np diff --git a/src/test/regress/sql/upsert_prepare.sql b/src/test/regress/sql/upsert_prepare.sql index 72794228a..670668894 100644 --- a/src/test/regress/sql/upsert_prepare.sql +++ b/src/test/regress/sql/upsert_prepare.sql @@ -59,7 +59,8 @@ create view up_view as select *from up_neg_01; create materialized view mat_view as select *from up_neg_01; create table pkt (a int primary key, b int, c int); create table fkt (a int primary key, b int references pkt, c int); - +create table up_neg_11(c1 int, c2 int) partition by range(c1)(partition p1 values less than(10), partition p2 values less than(maxvalue)); +create unique index index_up_neg_11 on up_neg_11(c2); -- procedure test CREATE SCHEMA upsert_test_procedure; diff --git a/src/test/regress/sql/upsert_restriction.sql b/src/test/regress/sql/upsert_restriction.sql index 14a362f4c..cec6a356c 100644 --- a/src/test/regress/sql/upsert_restriction.sql +++ b/src/test/regress/sql/upsert_restriction.sql @@ -33,6 +33,7 @@ insert into up_neg_07 select a,a,a from generate_series(1,20) as a; insert into up_neg_08 select a,a,a from generate_series(1,20) as a; insert into up_neg_09 select a,a,a from generate_series(1,20) as a; insert into up_neg_10 select a,a,a from generate_series(1,20) as a; +insert into up_neg_11 values(1,1),(2,2),(11,11),(12,12); -- table cases ---- col table @@ -86,11 +87,6 @@ insert into up_neg_05 values(1,1,1,1,1) on duplicate key update c1 =1, c2 = 1, c insert into up_neg_05 values(1,1,1,1,1) on duplicate key update c4 = 1 where c1=1; ---- from clause insert into up_neg_05 values(1,1,1,1,1) on duplicate key update c4 = 1 from up_neg_04 where c1=1; ----- sub query -insert into up_neg_05 values(1,1,1,1,1) on duplicate key update (c2) = (select c2 from up_neg_05); - ----- update distribute key -insert into up_neg_06 values(101, 1, 1) on duplicate key update c3=101; ---- update partition key insert into up_neg_07 values(101, 1, 300) on duplicate key update c3=101; insert into up_neg_08 values(101, 1, 300) on duplicate key update c3=101; @@ -98,6 +94,11 @@ insert into up_neg_09 values(101, 1, 1) on duplicate key update c3=101; insert into up_neg_09 values(101, 1, 1) on duplicate key update c2=101; insert into up_neg_09 values(101, 1, 1) on duplicate key update c2 =1,c3=101; +---- cross-partition upsert +insert into up_neg_11 values(1, 1) on duplicate key update c1 = 15; +select * from up_neg_11 partition(p1); +select * from up_neg_11 partition(p2); + --update unique key mul type plans EXPLAIN (VERBOSE on, COSTS off) insert into up_neg_10 values(101, 1, 300) on duplicate key update c1=101; insert into up_neg_10 values(101, 1, 300) on duplicate key update c3=101;