4848#include "pgxc/pgxcnode.h"
4949#include "pgxc/execRemote.h"
5050#include "rewrite/rewriteManip.h"
51+ #include "rewrite/rewriteHandler.h"
5152#include "utils/builtins.h"
5253#include "utils/rel.h"
5354#include "utils/lsyscache.h"
@@ -1073,6 +1074,9 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
10731074 int col_att = 0 ;
10741075 int ctid_param_num ;
10751076 ListCell * lc ;
1077+ bool can_use_pk_for_rep_change = false;
1078+ int16 * indexed_col_numbers = NULL ;
1079+ int index_col_count = 0 ;
10761080
10771081 /* Make sure we are dealing with DMLs */
10781082 if (cmdtype != CMD_UPDATE &&
@@ -1134,6 +1138,28 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
11341138
11351139 query_to_deparse -> jointree = makeNode (FromExpr );
11361140
1141+ can_use_pk_for_rep_change = (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE ) &&
1142+ IsRelationReplicated (GetRelationLocInfo (res_rel -> relid ));
1143+
1144+ if (can_use_pk_for_rep_change )
1145+ {
1146+ index_col_count = pgxc_find_unique_index (res_rel -> relid ,
1147+ & indexed_col_numbers );
1148+ if (index_col_count <= 0 )
1149+ can_use_pk_for_rep_change = false;
1150+
1151+ if (can_use_pk_for_rep_change )
1152+ {
1153+ if (is_pk_being_changed (root -> parse , indexed_col_numbers ,
1154+ index_col_count ))
1155+ {
1156+ can_use_pk_for_rep_change = false;
1157+ }
1158+ }
1159+ }
1160+
1161+ rqplan -> rq_use_pk_for_rep_change = can_use_pk_for_rep_change ;
1162+
11371163 /*
11381164 * Prepare a param list for INSERT queries
11391165 * While doing so note the position of ctid, xc_node_id in source data
@@ -1146,7 +1172,8 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
11461172 col_att ++ ;
11471173
11481174 /* The position of ctid/xc_node_id is not required for INSERT */
1149- if (tle -> resjunk && (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE ))
1175+ if (!can_use_pk_for_rep_change && tle -> resjunk &&
1176+ (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE ))
11501177 {
11511178 Var * v = (Var * )tle -> expr ;
11521179
@@ -1232,42 +1259,89 @@ pgxc_build_dml_statement(PlannerInfo *root, CmdType cmdtype,
12321259 * the n table attributes, followed by ctid and optionally node_id. So
12331260 * we know that the ctid has to be n + 1.
12341261 */
1235- ctid_param_num = natts + 1 ;
1262+ if (!can_use_pk_for_rep_change )
1263+ {
1264+ ctid_param_num = natts + 1 ;
1265+ }
12361266 }
1237- else if (cmdtype == CMD_DELETE )
1267+ if (cmdtype == CMD_DELETE )
12381268 {
1239- /*
1240- * Since there is no data to update, the first param is going to be
1241- * ctid.
1242- */
1243- ctid_param_num = 1 ;
1269+ if (!can_use_pk_for_rep_change )
1270+ {
1271+ /*
1272+ * Since there is no data to update, the first param is going to be
1273+ * ctid.
1274+ */
1275+ ctid_param_num = 1 ;
1276+ }
12441277 }
12451278
12461279 /* Add quals like ctid = $4 AND xc_node_id = $6 to the UPDATE/DELETE query */
12471280 if (cmdtype == CMD_UPDATE || cmdtype == CMD_DELETE )
12481281 {
1249- if (!ctid_found )
1250- elog (ERROR , "Source data plan's target list does not contain ctid colum" );
1251-
12521282 /*
1253- * Beware, the ordering of ctid and node_id is important ! ctid should
1254- * be followed by node_id, not vice-versa, so as to be consistent with
1255- * the data row to be generated while binding the parameters for the
1256- * update statement.
1283+ * If it is not replicated, we can use CTID, otherwise we need
1284+ * to use a defined primary key
12571285 */
1258- pgxc_dml_add_qual_to_query (query_to_deparse , ctid_param_num ,
1259- SelfItemPointerAttributeNumber , resultRelationIndex );
1286+ if (!can_use_pk_for_rep_change )
1287+ {
1288+ if (!ctid_found )
1289+ elog (ERROR , "Source data plan's target list does not contain ctid colum" );
12601290
1261- if (node_id_found )
1291+ /*
1292+ * Beware, the ordering of ctid and node_id is important ! ctid should
1293+ * be followed by node_id, not vice-versa, so as to be consistent with
1294+ * the data row to be generated while binding the parameters for the
1295+ * update statement.
1296+ */
1297+ pgxc_dml_add_qual_to_query (query_to_deparse , ctid_param_num ,
1298+ SelfItemPointerAttributeNumber , resultRelationIndex );
1299+
1300+ if (node_id_found )
1301+ {
1302+ pgxc_dml_add_qual_to_query (query_to_deparse , ctid_param_num + 1 ,
1303+ XC_NodeIdAttributeNumber , resultRelationIndex );
1304+ }
1305+ }
1306+ else
12621307 {
1263- pgxc_dml_add_qual_to_query (query_to_deparse , ctid_param_num + 1 ,
1264- XC_NodeIdAttributeNumber , resultRelationIndex );
1308+ /*
1309+ * Add all the columns of the primary key or unique index
1310+ * in the where clause of update / delete on the replicated table
1311+ */
1312+ int i ;
1313+ for (i = 0 ; i < index_col_count ; i ++ )
1314+ {
1315+ int pkattno = indexed_col_numbers [i ];
12651316
1266- query_to_deparse -> jointree -> quals = (Node * )make_andclause (
1267- (List * )query_to_deparse -> jointree -> quals );
1317+ col_att = 0 ;
1318+ foreach (elt , sourceTargetList )
1319+ {
1320+ TargetEntry * tle = lfirst (elt );
1321+ Var * v ;
1322+
1323+ col_att ++ ;
1324+
1325+ v = (Var * )tle -> expr ;
1326+
1327+ if (v -> varno == resultRelationIndex &&
1328+ v -> varattno == pkattno )
1329+ {
1330+ break ;
1331+ }
1332+ }
1333+
1334+ pgxc_dml_add_qual_to_query (query_to_deparse , col_att ,
1335+ pkattno , resultRelationIndex );
1336+ }
12681337 }
1338+ query_to_deparse -> jointree -> quals = (Node * )make_andclause (
1339+ (List * )query_to_deparse -> jointree -> quals );
12691340 }
12701341
1342+ if (indexed_col_numbers != NULL )
1343+ pfree (indexed_col_numbers );
1344+
12711345 /* pgxc_add_returning_list copied returning list in base_tlist */
12721346 if (rqplan -> base_tlist )
12731347 query_to_deparse -> returningList = list_copy (rqplan -> base_tlist );
0 commit comments