DECLARE
   FUNCTION random_question (user_id_in     IN INTEGER,
                             domain_id_in   IN INTEGER DEFAULT NULL,
                             topic_id_in    IN INTEGER DEFAULT NULL)
      RETURN INTEGER
   IS
      /* If domain set, convert to root topic and use that.
         If topic is set, ignore domain.
         If neither is set, then filter by user domains.
      */
      l_query          qdb_config.maxvarchar2
         := 'SELECT question_id FROM (SELECT question_id FROM dg_training_questions_v tq';
      l_domain_count   INTEGER;
      l_cur            SYS_REFCURSOR;
      l_selected       INTEGER;
   BEGIN
      SELECT COUNT (*)
        INTO l_domain_count
        FROM qdb_user_domains
       WHERE user_id = user_id_in;
      l_query :=
            l_query
         || CASE
               WHEN domain_id_in IS NULL AND topic_id_in IS NULL
               THEN
                  CASE
                     WHEN l_domain_count > 0
                     THEN
                           ' WHERE domain_id IN (SELECT domain_id FROM qdb_user_domains WHERE user_id = '
                        || user_id_in
                        || ')'
                  END
               WHEN topic_id_in IS NOT NULL
               THEN
                     ' WHERE tq.topic_id IN (SELECT t2.topic_id from qdb_topics t2'
                  || ' CONNECT BY prior t2.topic_id = t2.parent_topic_id START WITH t2.topic_id = '
                  || topic_id_in
                  || ')'
               WHEN domain_id_in IS NOT NULL
               THEN
                  ' WHERE domain_id = ' || domain_id_in
            END;
      /* First check for unplayed quizzes */
      OPEN l_cur FOR
            l_query
         || ' MINUS SELECT z.question_id FROM qdb_quizzes z, qdb_compev_answers a'
         || ' WHERE a.user_id = '
         || user_id_in
         || ' AND z.comp_event_id = a.comp_event_id'
         || ' ) ORDER BY DBMS_RANDOM.VALUE ()';
      FETCH l_cur INTO l_selected;
      CLOSE l_cur;
      IF l_selected IS NULL
      THEN
         /* Try again without restriction on already played. */
         OPEN l_cur FOR l_query || ') ORDER BY DBMS_RANDOM.VALUE ()';
         FETCH l_cur INTO l_selected;
         CLOSE l_cur;
      END IF;
      RETURN l_selected;
   END;
BEGIN
   NULL;
END;