private int updateStatusWithTempTable(final ExpressionOperator expression,
                                          final Status currentStatus,
                                          final Status newStatus,
                                          final long statusTime) {
        LOGGER.debug(() ->
                LogUtil.message("updateStatusWithTempTable, expression: {}, currentStatus: {}, " +
                                "newStatus: {}, statusTime: {}",
                        expression, currentStatus, newStatus, LogUtil.instant(statusTime)));

        final byte newStatusId = MetaStatusId.getPrimitiveValue(newStatus);
        final int batchSize = metaServiceConfigProvider.get().getMetaStatusUpdateBatchSize();

        final Table<?> metaWithJoins = buildMeteWithOptionalJoins(expression);
        final Condition conditions = createUpdateStatusCondition(expression, currentStatus, newStatus);
        final Condition statusCondition = getStatusCondition(currentStatus, newStatus);

        final Select<Record1<Long>> select;
        // One big batch should be more efficient as long as it only locks the rows being changed
        // and no others. If it does lock other rows then smaller batches may be needed.
        if (batchSize <= 0) {
            // 0 == one big batch
            select = DSL.selectDistinct(meta.ID)
                    .from(metaWithJoins)
                    .where(conditions);
        } else {
            select = DSL.selectDistinct(meta.ID)
                    .from(metaWithJoins)
                    .where(conditions)
                    .limit(batchSize);
        }

        final Name metaIdsTempTblName = DSL.name("meta_ids_temp");
        final Table<Record> metaIdsTempTbl = DSL.table(metaIdsTempTblName);
        final Name metaIdColName = DSL.name("meta_ids_temp", "id");
        final Field<Long> metaIdColField = DSL.field(metaIdColName, Long.class);

        final AtomicInteger insertCount = new AtomicInteger();
        final AtomicInteger totalUpdateCount = new AtomicInteger();
        final DurationTimer durationTimer = DurationTimer.start();

        // We do this multi-stage deletion to try and avoid next-key or gap locks that end up locking
        // other meta rows and stopping processing. This approach means we update using ID to uniquely
        // access rows.
        do {
            JooqUtil.context(metaDbConnProvider, context -> {
                try {
                    // Temp table of all the IDs we want to update
                    // Need to do it as a create then insert so we get the count
                    context.createTemporaryTable(metaIdsTempTblName)
                            .column(metaIdColField)
                            .execute();

                    final var insert = context.insertInto(metaIdsTempTbl)
                            .select(select);
                    LOGGER.trace("Insert SQL:\n{}", insert);

                    LOGGER.logDurationIfDebugEnabled(
                            () -> insertCount.set(insert.execute()),
                            () -> LogUtil.message("Inserted {} meta ids into temporary table", insertCount));

                    if (insertCount.get() > 0) {
                        final var update = context
                                .update(meta.innerJoin(metaIdsTempTbl)
                                        .on(meta.ID.eq(metaIdColField)))
                                .set(meta.STATUS, newStatusId)
                                .set(meta.STATUS_TIME, statusTime)
                                .where(statusCondition); // Re-use the status condition in case anything changed
                        LOGGER.trace("Update SQL:\n{}", update);

                        final int updateCount = LOGGER.logDurationIfDebugEnabled(
                                update::execute,
                                cnt -> LogUtil.message("Updated {} meta rows to status: {}", cnt, newStatus));
                        totalUpdateCount.addAndGet(updateCount);

                        // Remove all the temp rows
                        LOGGER.logDurationIfDebugEnabled(
                                () -> context.deleteFrom(metaIdsTempTbl)
                                        .execute(),
                                cnt -> LogUtil.message("Deleted {} rows from temp table", cnt));
                    } else {
                        LOGGER.debug("No more records to update, dropping out");
                    }
                } catch (Exception e) {
                    LOGGER.error(LogUtil.message(
                            "Error updating the meta status from {} to {} with expression: {}. {}",
                            currentStatus, newStatus, expression, e.getMessage()), e);
                    throw e;
                } finally {
                    // Temp table lives for the life of the session so if we go round again
                    // or if the session is returned to the pool, make sure it is gone.
                    LOGGER.logDurationIfDebugEnabled(
                            () -> context.dropTableIfExists(metaIdsTempTblName)
                                    .execute(),
                            cnt -> LogUtil.message("Dropped temp table", cnt));
                }
            });
        } while (batchSize > 0 && insertCount.get() >= batchSize);

        LOGGER.debug("Set the status of {} meta rows to {} using batchSize {} in {}. Expression: {}",
                totalUpdateCount, newStatus, batchSize, durationTimer, expression);

        return totalUpdateCount.get();
    }
Method currently only here for test purposes as a means of bulk loading data.
stroom-meta/stroom-meta-impl-db/src/main/java/stroom/meta/impl/db/MetaDaoImpl.java