| 160 | } |
| 161 | |
| 162 | void execCommand(client *c) { |
| 163 | int j; |
| 164 | robj **orig_argv; |
| 165 | int orig_argc; |
| 166 | struct redisCommand *orig_cmd; |
| 167 | int was_master = listLength(g_pserver->masters) == 0; |
| 168 | |
| 169 | if (!(c->flags & CLIENT_MULTI)) { |
| 170 | addReplyError(c,"EXEC without MULTI"); |
| 171 | return; |
| 172 | } |
| 173 | |
| 174 | /* EXEC with expired watched key is disallowed*/ |
| 175 | if (isWatchedKeyExpired(c)) { |
| 176 | c->flags |= (CLIENT_DIRTY_CAS); |
| 177 | } |
| 178 | |
| 179 | /* Check if we need to abort the EXEC because: |
| 180 | * 1) Some WATCHed key was touched. |
| 181 | * 2) There was a previous error while queueing commands. |
| 182 | * A failed EXEC in the first case returns a multi bulk nil object |
| 183 | * (technically it is not an error but a special behavior), while |
| 184 | * in the second an EXECABORT error is returned. */ |
| 185 | if (c->flags & (CLIENT_DIRTY_CAS | CLIENT_DIRTY_EXEC)) { |
| 186 | if (c->flags & CLIENT_DIRTY_EXEC) { |
| 187 | addReplyErrorObject(c, shared.execaborterr); |
| 188 | } else { |
| 189 | addReply(c, shared.nullarray[c->resp]); |
| 190 | } |
| 191 | |
| 192 | discardTransaction(c); |
| 193 | return; |
| 194 | } |
| 195 | |
| 196 | uint64_t old_flags = c->flags; |
| 197 | |
| 198 | /* we do not want to allow blocking commands inside multi */ |
| 199 | c->flags |= CLIENT_DENY_BLOCKING; |
| 200 | |
| 201 | /* Exec all the queued commands */ |
| 202 | unwatchAllKeys(c); /* Unwatch ASAP otherwise we'll waste CPU cycles */ |
| 203 | |
| 204 | serverTL->in_exec = 1; |
| 205 | |
| 206 | orig_argv = c->argv; |
| 207 | orig_argc = c->argc; |
| 208 | orig_cmd = c->cmd; |
| 209 | addReplyArrayLen(c,c->mstate.count); |
| 210 | for (j = 0; j < c->mstate.count; j++) { |
| 211 | c->argc = c->mstate.commands[j].argc; |
| 212 | c->argv = c->mstate.commands[j].argv; |
| 213 | c->cmd = c->mstate.commands[j].cmd; |
| 214 | |
| 215 | /* ACL permissions are also checked at the time of execution in case |
| 216 | * they were changed after the commands were queued. */ |
| 217 | int acl_errpos; |
| 218 | int acl_retval = ACLCheckAllPerm(c,&acl_errpos); |
| 219 | if (acl_retval != ACL_OK) { |
nothing calls this directly
no test coverage detected