* DeleteOneInternal deletes a single row with a specific shard key value filter. * * Returns 1 if a row was deleted, and 0 if No rows were found matching the provided query. */
| 1222 | * Returns 1 if a row was deleted, and 0 if No rows were found matching the provided query. |
| 1223 | */ |
| 1224 | static void |
| 1225 | DeleteOneInternal(MongoCollection *collection, DeleteOneParams *deleteOneParams, |
| 1226 | int64 shardKeyHash, DeleteOneResult *result) |
| 1227 | { |
| 1228 | uint64 planId = QUERY_DELETE_ONE; |
| 1229 | bool applyCollation = IsCollationApplicable(deleteOneParams->collationString); |
| 1230 | |
| 1231 | List *sortFieldDocuments = deleteOneParams->sort == NULL ? NIL : |
| 1232 | BsonValueDocumentDecomposeFields(deleteOneParams->sort); |
| 1233 | int sortFieldDocumentsLength = list_length(sortFieldDocuments); |
| 1234 | |
| 1235 | int argCount = sortFieldDocumentsLength; |
| 1236 | |
| 1237 | bool queryHasNonIdFilters = false; |
| 1238 | bool isIdFilterCollationAware = false; |
| 1239 | pgbson *objectIdFilter = |
| 1240 | GetObjectIdFilterFromQueryDocumentValue(deleteOneParams->query, |
| 1241 | &queryHasNonIdFilters, |
| 1242 | &isIdFilterCollationAware); |
| 1243 | |
| 1244 | bool applyObjectIdFilter = objectIdFilter != NULL; |
| 1245 | if (applyObjectIdFilter && applyCollation) |
| 1246 | { |
| 1247 | /* if the _id filter value is collation-sensitive, we will omit */ |
| 1248 | /* filtering by _id in the WHERE clause. */ |
| 1249 | applyObjectIdFilter = !isIdFilterCollationAware; |
| 1250 | } |
| 1251 | |
| 1252 | argCount += applyObjectIdFilter ? 1 : 0; |
| 1253 | |
| 1254 | int nextSqlArgIndex = 1; |
| 1255 | MemoryContext outerContext = CurrentMemoryContext; |
| 1256 | |
| 1257 | SPI_connect(); |
| 1258 | |
| 1259 | /* |
| 1260 | * We construct a query that the distribution layer can route to a single shard, which |
| 1261 | * also allows us to use LIMIT 1 and FOR UPDATE in a subquery. |
| 1262 | * |
| 1263 | * The LIMIT 1 ensures we only delete a single row even if there are many |
| 1264 | * that match the query. |
| 1265 | * |
| 1266 | * The FOR UPDATE ensures that the matching row does not change or disappear |
| 1267 | * concurrently. Otherwise, the DELETE might incorrectly become a noop. |
| 1268 | * |
| 1269 | * Note that we cannot directly place the SELECT query into the USING clause |
| 1270 | * due to the reason discussed in the pgsql-bug thread: |
| 1271 | * https://www.postgresql.org/message-id/3798786.1655133396%40sss.pgh.pa.us. |
| 1272 | * For this reason, here we use a materialized cte to compute the ctid of the |
| 1273 | * tuple that needs to be deleted. |
| 1274 | */ |
| 1275 | StringInfoData selectQuery; |
| 1276 | initStringInfo(&selectQuery); |
| 1277 | appendStringInfo(&selectQuery, "WITH s AS MATERIALIZED (SELECT ctid FROM "); |
| 1278 | |
| 1279 | if (collection->shardTableName[0] != '\0') |
| 1280 | { |
| 1281 | appendStringInfo(&selectQuery, " %s.%s", ApiDataSchemaName, |
no test coverage detected