-- Deterministic daily-AU lookup for an already resolved game query plan. -- Physical user-master objects are selected only from SG_GAME_CATALOG. -- No game name, alias, prefix, or object name is embedded in this function. CREATE OR REPLACE FUNCTION sg_game_daily_au_lookup( p_query_plan IN CLOB, p_base_date IN DATE DEFAULT NULL ) RETURN CLOB AUTHID DEFINER IS v_plan JSON_OBJECT_T; v_targets JSON_ARRAY_T; v_target JSON_OBJECT_T; v_result JSON_OBJECT_T := JSON_OBJECT_T(); v_items JSON_ARRAY_T := JSON_ARRAY_T(); v_item JSON_OBJECT_T; v_game_key VARCHAR2(128); v_game_id VARCHAR2(128); v_game_name VARCHAR2(512); v_object_name VARCHAR2(128); v_safe_object_name VARCHAR2(128); v_effective_date DATE; v_au_count NUMBER; v_column_count PLS_INTEGER; v_object_count PLS_INTEGER; v_seen SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST(); v_target_count PLS_INTEGER := 0; FUNCTION is_seen(p_game_key IN VARCHAR2) RETURN BOOLEAN IS BEGIN FOR i IN 1 .. v_seen.COUNT LOOP IF v_seen(i) = p_game_key THEN RETURN TRUE; END IF; END LOOP; RETURN FALSE; END; PROCEDURE add_status( p_game_key IN VARCHAR2, p_status IN VARCHAR2, p_reason IN VARCHAR2 ) IS BEGIN v_item := JSON_OBJECT_T(); v_item.put('gameKey', p_game_key); v_item.put('status', p_status); v_item.put('reason', p_reason); v_items.append(v_item); END; BEGIN IF p_query_plan IS NULL THEN RAISE_APPLICATION_ERROR(-20001, 'queryPlan is required'); END IF; v_plan := JSON_OBJECT_T.parse(p_query_plan); v_targets := v_plan.get_array('dataEligibleTargets'); IF v_targets IS NULL THEN v_targets := v_plan.get_array('targets'); END IF; IF v_targets IS NOT NULL AND v_targets.get_size > 0 THEN FOR i IN 0 .. v_targets.get_size - 1 LOOP v_target := TREAT(v_targets.get(i) AS JSON_OBJECT_T); IF v_target IS NULL OR NOT v_target.has('gameKey') THEN CONTINUE; END IF; v_game_key := v_target.get_string('gameKey'); IF v_game_key IS NULL OR is_seen(v_game_key) THEN CONTINUE; END IF; v_seen.EXTEND; v_seen(v_seen.COUNT) := v_game_key; v_target_count := v_target_count + 1; BEGIN SELECT game_id, game_nm, user_master_object_name INTO v_game_id, v_game_name, v_object_name FROM sg_game_catalog WHERE game_key = v_game_key AND active_yn = 'Y'; EXCEPTION WHEN NO_DATA_FOUND THEN add_status(v_game_key, 'UNAVAILABLE', 'Catalog target is not active.'); CONTINUE; END; IF v_object_name IS NULL THEN add_status(v_game_key, 'UNAVAILABLE', 'No approved user-master object is registered.'); CONTINUE; END IF; v_safe_object_name := DBMS_ASSERT.SIMPLE_SQL_NAME(UPPER(v_object_name)); SELECT COUNT(*) INTO v_object_count FROM user_objects WHERE object_name = v_safe_object_name AND object_type IN ('TABLE', 'VIEW', 'MATERIALIZED VIEW') AND status = 'VALID'; SELECT COUNT(*) INTO v_column_count FROM user_tab_columns WHERE table_name = v_safe_object_name AND column_name IN ('GUID', 'BASE_DT', 'AU_FLAG', 'EXPT_USER_YN'); IF v_object_count = 0 OR v_column_count <> 4 THEN add_status(v_game_key, 'UNAVAILABLE', 'Approved user-master object is not query-ready.'); CONTINUE; END IF; IF p_base_date IS NULL THEN EXECUTE IMMEDIATE 'SELECT MAX(BASE_DT) FROM ' || v_safe_object_name INTO v_effective_date; ELSE v_effective_date := TRUNC(p_base_date); END IF; IF v_effective_date IS NULL THEN add_status(v_game_key, 'NO_DATA', 'No available base date in the selected object.'); CONTINUE; END IF; EXECUTE IMMEDIATE 'SELECT COUNT(DISTINCT GUID) FROM ' || v_safe_object_name || ' WHERE BASE_DT = :1 AND AU_FLAG = 1 AND EXPT_USER_YN = ''N''' INTO v_au_count USING v_effective_date; v_item := JSON_OBJECT_T(); v_item.put('gameKey', v_game_key); v_item.put('gameId', v_game_id); v_item.put('gameName', v_game_name); v_item.put('objectName', v_safe_object_name); v_item.put('baseDate', TO_CHAR(v_effective_date, 'YYYY-MM-DD')); v_item.put('auCount', v_au_count); v_item.put('status', 'READY'); v_item.put('sqlTemplate', 'SELECT COUNT(DISTINCT GUID) AS AU_COUNT FROM ' || 'WHERE BASE_DT = :baseDate AND AU_FLAG = 1 AND EXPT_USER_YN = ''N'''); v_items.append(v_item); END LOOP; END IF; v_result.put('status', CASE WHEN v_target_count = 0 THEN 'NO_GAME_TARGET' ELSE 'GAME_AU_LOOKUP' END); v_result.put('targetType', NVL(v_plan.get_string('targetType'), 'NONE')); IF p_base_date IS NULL THEN v_result.put_null('requestedBaseDate'); ELSE v_result.put('requestedBaseDate', TO_CHAR(TRUNC(p_base_date), 'YYYY-MM-DD')); END IF; v_result.put('targetCount', v_target_count); v_result.put('items', v_items); RETURN v_result.to_clob; END; /