Skip to content

Commit

Permalink
Fix invalid UPDATE stmt when none of the columns change
Browse files Browse the repository at this point in the history
We need at least two columns to be able to skip a column
if the value is the same in the old and new rows.

Otherwise, we would end up with an invalid UPDATE statement
like below:
```
UPDATE table SET WHERE "id" = 1;
```

Usually, the above could happen when REPLICA IDENTITY is set
to FULL, and the UPDATE statement executed with the same
values as the old ones.
For e.g.
```
UPDATE table SET "id" = 1 WHERE "id" = 1;
```

Solution: Skip the update when all columns in SET clause is equal to the WHERE clause.

Signed-off-by: Arunprasad Rajkumar <[email protected]>
  • Loading branch information
arajkumar committed Oct 4, 2024
1 parent 9031626 commit 50af2d3
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 128 deletions.
34 changes: 33 additions & 1 deletion src/bin/pgcopydb/ld_transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -2227,12 +2227,15 @@ stream_write_update(FILE *out, LogicalMessageUpdate *update)
update->table.relname);
int pos = 0;

int skipColumnCount = 0;

for (int r = 0; r < new->values.count; r++)
{
LogicalMessageValues *values = &(new->values.array[r]);

bool first = true;


/* now loop over column values for this VALUES row */
for (int v = 0; v < values->cols; v++)
{
Expand Down Expand Up @@ -2273,7 +2276,11 @@ stream_write_update(FILE *out, LogicalMessageUpdate *update)
}
}

if (!skip)
if (skip)
{
++skipColumnCount;
}
else
{
if (attr->isgenerated)
{
Expand Down Expand Up @@ -2360,6 +2367,31 @@ stream_write_update(FILE *out, LogicalMessageUpdate *update)
return false;
}

/*
* When all column values in the SET clause are equal to those in the
* WHERE clause, we remove all columns from the SET clause. This results
* in an invalid UPDATE statement like the one shown below:
*
* UPDATE table SET WHERE "id" = 1;
*
* Usually, the above could happen when REPLICA IDENTITY is set to FULL,
* and the UPDATE statement executed with the same values as the old ones.
* For e.g.
* UPDATE table SET "id" = 1 WHERE "id" = 1;
*
* Skip the UPDATE statement in such cases.
*/
bool skipUpdate = (skipColumnCount == new->attributes.count);

if (skipUpdate)
{
log_warn("Skipping UPDATE statement as all columns are "
"the same as the old");

destroyPQExpBuffer(buf);
return true;
}

uint32_t hash = hashlittle(buf->data, buf->len, 5381);

FFORMAT(out, "PREPARE %x AS %s;\n", hash, buf->data);
Expand Down
Loading

0 comments on commit 50af2d3

Please sign in to comment.