def select_users_txn(txn, now_ms, renew_at):
     txn.execute(
         """
         SELECT user_id, expiration_ts_ms FROM email_account_validity
         WHERE email_sent = ? AND (expiration_ts_ms - ?) <= ?
         """,
         (False, now_ms, renew_at),
     )
     return DatabasePool.cursor_to_dict(txn)
        def populate_table_txn(txn: LoggingTransaction,
                               batch_size: int) -> int:
            # Populate the database with the users that are in the users table but not in
            # the email_account_validity one.
            txn.execute(
                """
                SELECT users.name FROM users
                LEFT JOIN email_account_validity
                    ON (users.name = email_account_validity.user_id)
                WHERE email_account_validity.user_id IS NULL
                LIMIT ?
                """,
                (batch_size, ),
            )

            missing_users = DatabasePool.cursor_to_dict(txn)
            if not missing_users:
                return 0

            # Figure out the state of these users in the account_validity table.
            # Note that at some point we'll want to get rid of the account_validity table
            # and we'll need to get rid of this code as well.
            rows = DatabasePool.simple_select_many_txn(
                txn=txn,
                table="account_validity",
                column="user_id",
                iterable=tuple([user["name"] for user in missing_users]),
                keyvalues={},
                retcols=(
                    "user_id",
                    "expiration_ts_ms",
                    "email_sent",
                    "renewal_token",
                    "token_used_ts_ms",
                ),
            )

            # Turn the results into a dictionary so we can later merge it with the list
            # of registered users on the homeserver.
            users_to_insert = {}
            for row in rows:
                users_to_insert[row["user_id"]] = row

            # Look for users that are registered but don't have a state in the
            # account_validity table, and set a default state for them. This default
            # state includes an expiration timestamp close to now + validity period, but
            # is slightly randomised to avoid sending huge bursts of renewal emails at
            # once.
            default_expiration_ts = self._api.current_time_ms() + self._period
            for user in missing_users:
                if users_to_insert.get(user["name"]) is None:
                    users_to_insert[user["name"]] = {
                        "user_id":
                        user["name"],
                        "expiration_ts_ms":
                        self._rand.randrange(
                            default_expiration_ts -
                            self._expiration_ts_max_delta,
                            default_expiration_ts,
                        ),
                        "email_sent":
                        False,
                        "renewal_token":
                        None,
                        "token_used_ts_ms":
                        None,
                    }

            # Insert the users in the table.
            DatabasePool.simple_insert_many_txn(
                txn=txn,
                table="email_account_validity",
                values=list(users_to_insert.values()),
            )

            return len(missing_users)