diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/access/common/heaptuple.c | 66 | ||||
-rw-r--r-- | src/backend/utils/adt/tsvector_op.c | 16 | ||||
-rw-r--r-- | src/include/access/htup_details.h | 6 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 57 | ||||
-rw-r--r-- | src/test/regress/regress.c | 11 |
5 files changed, 101 insertions, 55 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 6d0f3f37673..e27ec78b714 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -847,6 +847,72 @@ heap_modify_tuple(HeapTuple tuple, } /* + * heap_modify_tuple_by_cols + * form a new tuple from an old tuple and a set of replacement values. + * + * This is like heap_modify_tuple, except that instead of specifying which + * column(s) to replace by a boolean map, an array of target column numbers + * is used. This is often more convenient when a fixed number of columns + * are to be replaced. The replCols, replValues, and replIsnull arrays must + * be of length nCols. Target column numbers are indexed from 1. + * + * The result is allocated in the current memory context. + */ +HeapTuple +heap_modify_tuple_by_cols(HeapTuple tuple, + TupleDesc tupleDesc, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull) +{ + int numberOfAttributes = tupleDesc->natts; + Datum *values; + bool *isnull; + HeapTuple newTuple; + int i; + + /* + * allocate and fill values and isnull arrays from the tuple, then replace + * selected columns from the input arrays. + */ + values = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); + isnull = (bool *) palloc(numberOfAttributes * sizeof(bool)); + + heap_deform_tuple(tuple, tupleDesc, values, isnull); + + for (i = 0; i < nCols; i++) + { + int attnum = replCols[i]; + + if (attnum <= 0 || attnum > numberOfAttributes) + elog(ERROR, "invalid column number %d", attnum); + values[attnum - 1] = replValues[i]; + isnull[attnum - 1] = replIsnull[i]; + } + + /* + * create a new tuple from the values and isnull arrays + */ + newTuple = heap_form_tuple(tupleDesc, values, isnull); + + pfree(values); + pfree(isnull); + + /* + * copy the identification info of the old tuple: t_ctid, t_self, and OID + * (if any) + */ + newTuple->t_data->t_ctid = tuple->t_data->t_ctid; + newTuple->t_self = tuple->t_self; + newTuple->t_tableOid = tuple->t_tableOid; + if (tupleDesc->tdhasoid) + HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); + + return newTuple; +} + +/* * heap_deform_tuple * Given a tuple, extract data into values/isnull arrays; this is * the inverse of heap_form_tuple. diff --git a/src/backend/utils/adt/tsvector_op.c b/src/backend/utils/adt/tsvector_op.c index 0e9ae5ff9cf..c9d5060f2c7 100644 --- a/src/backend/utils/adt/tsvector_op.c +++ b/src/backend/utils/adt/tsvector_op.c @@ -2329,8 +2329,10 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) if (prs.curwords) { datum = PointerGetDatum(make_tsvector(&prs)); - rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num, - &datum, NULL); + isnull = false; + rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + 1, &tsvector_attr_num, + &datum, &isnull); pfree(DatumGetPointer(datum)); } else @@ -2340,14 +2342,12 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column) SET_VARSIZE(out, CALCDATASIZE(0, 0)); out->size = 0; datum = PointerGetDatum(out); - rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num, - &datum, NULL); + isnull = false; + rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att, + 1, &tsvector_attr_num, + &datum, &isnull); pfree(prs.words); } - if (rettuple == NULL) /* internal error */ - elog(ERROR, "tsvector_update_trigger: %d returned by SPI_modifytuple", - SPI_result); - return PointerGetDatum(rettuple); } diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index d7e5fad11e5..8fb1f6ddea1 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -805,6 +805,12 @@ extern HeapTuple heap_modify_tuple(HeapTuple tuple, Datum *replValues, bool *replIsnull, bool *doReplace); +extern HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, + TupleDesc tupleDesc, + int nCols, + int *replCols, + Datum *replValues, + bool *replIsnull); extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull); extern void heap_freetuple(HeapTuple htup); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 042b31fd77f..91e1f8dd3fd 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -4562,10 +4562,9 @@ exec_assign_value(PLpgSQL_execstate *estate, PLpgSQL_rec *rec; int fno; HeapTuple newtup; - int natts; - Datum *values; - bool *nulls; - bool *replaces; + int colnums[1]; + Datum values[1]; + bool nulls[1]; Oid atttype; int32 atttypmod; @@ -4584,9 +4583,8 @@ exec_assign_value(PLpgSQL_execstate *estate, errdetail("The tuple structure of a not-yet-assigned record is indeterminate."))); /* - * Get the number of the records field to change and the - * number of attributes in the tuple. Note: disallow system - * column names because the code below won't cope. + * Get the number of the record field to change. Disallow + * system columns because the code below won't cope. */ fno = SPI_fnumber(rec->tupdesc, recfield->fieldname); if (fno <= 0) @@ -4594,42 +4592,25 @@ exec_assign_value(PLpgSQL_execstate *estate, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("record \"%s\" has no field \"%s\"", rec->refname, recfield->fieldname))); - fno--; - natts = rec->tupdesc->natts; - - /* - * Set up values/control arrays for heap_modify_tuple. For all - * the attributes except the one we want to replace, use the - * value that's in the old tuple. - */ - values = eval_mcontext_alloc(estate, sizeof(Datum) * natts); - nulls = eval_mcontext_alloc(estate, sizeof(bool) * natts); - replaces = eval_mcontext_alloc(estate, sizeof(bool) * natts); - - memset(replaces, false, sizeof(bool) * natts); - replaces[fno] = true; + colnums[0] = fno; /* * Now insert the new value, being careful to cast it to the * right type. */ - atttype = rec->tupdesc->attrs[fno]->atttypid; - atttypmod = rec->tupdesc->attrs[fno]->atttypmod; - values[fno] = exec_cast_value(estate, - value, - &isNull, - valtype, - valtypmod, - atttype, - atttypmod); - nulls[fno] = isNull; - - /* - * Now call heap_modify_tuple() to create a new tuple that - * replaces the old one in the record. - */ - newtup = heap_modify_tuple(rec->tup, rec->tupdesc, - values, nulls, replaces); + atttype = rec->tupdesc->attrs[fno - 1]->atttypid; + atttypmod = rec->tupdesc->attrs[fno - 1]->atttypmod; + values[0] = exec_cast_value(estate, + value, + &isNull, + valtype, + valtypmod, + atttype, + atttypmod); + nulls[0] = isNull; + + newtup = heap_modify_tuple_by_cols(rec->tup, rec->tupdesc, + 1, colnums, values, nulls); if (rec->freetup) heap_freetuple(rec->tup); diff --git a/src/test/regress/regress.c b/src/test/regress/regress.c index 119a59ab073..32703fcdcf9 100644 --- a/src/test/regress/regress.c +++ b/src/test/regress/regress.c @@ -639,15 +639,8 @@ ttdummy(PG_FUNCTION_ARGS) /* Tuple to return to upper Executor ... */ if (newtuple) /* UPDATE */ - { - HeapTuple tmptuple; - - tmptuple = SPI_copytuple(trigtuple); - rettuple = SPI_modifytuple(rel, tmptuple, 1, &(attnum[1]), &newoff, NULL); - SPI_freetuple(tmptuple); - } - else - /* DELETE */ + rettuple = SPI_modifytuple(rel, trigtuple, 1, &(attnum[1]), &newoff, NULL); + else /* DELETE */ rettuple = trigtuple; SPI_finish(); /* don't forget say Bye to SPI mgr */ |