@@ -1190,6 +1190,7 @@ void hsetexCommand(client *c) {
11901190 int changes = 0 ;
11911191 robj * * new_argv = NULL ;
11921192 int new_argc = 0 ;
1193+ int need_rewrite_for_nx_xx_fnx_fxx = 0 ;
11931194
11941195 for (; fields_index < c -> argc - 1 ; fields_index ++ ) {
11951196 if (!strcasecmp (c -> argv [fields_index ]-> ptr , "fields" )) {
@@ -1209,6 +1210,10 @@ void hsetexCommand(client *c) {
12091210 if (checkType (c , o , OBJ_HASH ))
12101211 return ;
12111212
1213+ if (flags & (ARGS_SET_NX | ARGS_SET_XX | ARGS_SET_FNX | ARGS_SET_FXX )) {
1214+ need_rewrite_for_nx_xx_fnx_fxx = 1 ;
1215+ }
1216+
12121217 /* Check NX/XX key-level conditions before creating a new object */
12131218 if (((flags & ARGS_SET_NX ) && o != NULL ) ||
12141219 ((flags & ARGS_SET_XX ) && o == NULL )) {
@@ -1266,6 +1271,28 @@ void hsetexCommand(client *c) {
12661271 incrRefCount (shared .hdel );
12671272 new_argv [new_argc ++ ] = c -> argv [1 ];
12681273 incrRefCount (c -> argv [1 ]);
1274+ } else if (need_rewrite_for_nx_xx_fnx_fxx ) {
1275+ /* We use new_argv for rewrite */
1276+ int rewrite_argc = 2 + (c -> argc - 2 ); // command + key + everything else
1277+ new_argv = zmalloc (sizeof (robj * ) * rewrite_argc );
1278+ int j = 0 ;
1279+ // Command
1280+ new_argv [j ++ ] = c -> argv [0 ];
1281+ incrRefCount (c -> argv [0 ]);
1282+ // Key
1283+ new_argv [j ++ ] = c -> argv [1 ];
1284+ incrRefCount (c -> argv [1 ]);
1285+ // Copy optional args (skip NX/XX/FNX/FXX)
1286+ for (int i = 2 ; i < fields_index ; i ++ ) {
1287+ if (strcmp (c -> argv [i ]-> ptr , "NX" ) &&
1288+ strcmp (c -> argv [i ]-> ptr , "XX" ) &&
1289+ strcmp (c -> argv [i ]-> ptr , "FNX" ) &&
1290+ strcmp (c -> argv [i ]-> ptr , "FXX" )) {
1291+ new_argv [j ++ ] = c -> argv [i ];
1292+ incrRefCount (c -> argv [i ]);
1293+ }
1294+ }
1295+ new_argc = j ;
12691296 }
12701297
12711298 for (i = fields_index ; i < c -> argc ; i += 2 ) {
@@ -1280,6 +1307,10 @@ void hsetexCommand(client *c) {
12801307 } else {
12811308 hashTypeSet (o , c -> argv [i ]-> ptr , c -> argv [i + 1 ]-> ptr , when , set_flags );
12821309 changes ++ ;
1310+ if (need_rewrite_for_nx_xx_fnx_fxx ){
1311+ new_argv [new_argc ++ ] = c -> argv [i ];
1312+ incrRefCount (c -> argv [i ]);
1313+ }
12831314 }
12841315 }
12851316
@@ -1294,6 +1325,7 @@ void hsetexCommand(client *c) {
12941325 notifyKeyspaceEvent (NOTIFY_HASH , "hexpired" , c -> argv [1 ], c -> db -> id );
12951326 } else {
12961327 notifyKeyspaceEvent (NOTIFY_HASH , "hset" , c -> argv [1 ], c -> db -> id );
1328+ replaceClientCommandVector (c , new_argc , new_argv );
12971329 if (expire ) {
12981330 /* Propagate as HSETEX Key Value PXAT millisecond-timestamp if there is
12991331 * EX/PX/EXAT flag. */
@@ -1312,34 +1344,6 @@ void hsetexCommand(client *c) {
13121344 }
13131345 }
13141346
1315- /* --- NX/XX/FNX/FXX rewrite --- */
1316- if (flags & (ARGS_SET_NX | ARGS_SET_XX | ARGS_SET_FNX | ARGS_SET_FXX )) {
1317- /* We use new_argv for rewrite */
1318- if (!new_argv ) {
1319- int rewrite_argc = 2 + num_fields * 2 ;
1320- new_argv = zmalloc (sizeof (robj * ) * rewrite_argc );
1321- int j = 0 ;
1322-
1323- new_argv [j ++ ] = c -> argv [0 ];
1324- incrRefCount (c -> argv [0 ]);
1325-
1326- new_argv [j ++ ] = c -> argv [1 ];
1327- incrRefCount (c -> argv [1 ]);
1328-
1329- for (int i = fields_index ; i < c -> argc ; i ++ ) {
1330- if (strcmp (c -> argv [i ]-> ptr , "NX" ) &&
1331- strcmp (c -> argv [i ]-> ptr , "XX" ) &&
1332- strcmp (c -> argv [i ]-> ptr , "FNX" ) &&
1333- strcmp (c -> argv [i ]-> ptr , "FXX" )) {
1334- new_argv [j ++ ] = c -> argv [i ];
1335- incrRefCount (c -> argv [i ]);
1336- }
1337- }
1338- new_argc = j ;
1339- replaceClientCommandVector (c , new_argc , new_argv );
1340- }
1341- }
1342-
13431347 signalModifiedKey (c , c -> db , c -> argv [1 ]);
13441348 /* Delete the object in case it was left empty */
13451349 if (hashTypeLength (o ) == 0 ) {
0 commit comments