2016-08-25 42 views
1

首先,我想明確指出問題不在於實例化視圖功能。執行表函數之前動態查詢重寫或評估查詢

假設,我有一個表函數返回一組預定義的列。

當一個函數調用提交的

SELECT col1, col2, col3 
FROM TABLE(my_tfn(:p1)) 
WHERE col4 = 'X'; 

我可以評價參數,選擇要執行的查詢。 我可以打開其中一個預定義的遊標,也可以動態組合我的查詢。

如果不是評估參數,我想評估請求查詢的文本會怎樣?

例如,如果我的函數返回20列但查詢只請求4, 我可以將NULL分配給返回類型的其餘16列,並執行更少的聯接。 或者我可以將篩選器降到我的動態查詢。

有沒有辦法做到這一點? 更一般地說,有沒有辦法在離職之前查看請求查詢?

+0

我不願意支持這樣的事情。如果查詢位於存儲過程中,則可以檢查調用堆棧並使用數據字典查找代碼中的查詢。您可能能夠獲取當前會話的sql_id並查詢查詢文本,但我不會認爲這將適用於各個版本。我認爲如果你想改變行爲,讓函數接受一個額外的參數會更有意義。 –

+1

如果你真的確定了,你可以使用高級重寫來讓一個任意的查詢實際執行一個完全不同的查詢https://oracle-base.com/articles/10g/dbms_advanced_rewrite我會非常明智地做這樣的事情,但是,因爲它使調試系統變得「有趣」。 –

+0

謝謝Justin。這非常有用。唯一的問題是,我似乎必須事先知道請求的查詢是什麼。希望以某種方式查看該查詢的文本。再次感謝。 –

回答

2

沒有可靠的方法來識別調用PL/SQL對象的SQL。

下面是識別調用SQL的不太穩健的方法。我以前使用過這樣的代碼,但只有在我知道PL/SQL永遠不會同時運行的特殊情況下。

這個好像是就好像應該那麼簡單。數據字典跟蹤所有會話並運行SQL。您可以使用sys_context('userenv', 'sid')找到當前會話,將其與GV$SESSION匹配,然後獲得SQL_IDPREV_SQL_ID。但這些都不包含調用SQL。 SYS_CONTEXT中甚至有CURRENT_SQL,但它僅用於細粒度審計。

相反,調用SQL必須通過字符串搜索找到。使用PL/SQL對象的唯一名稱將有助於過濾掉無關的語句。爲防止重新運行舊語句,必須在找到SQL後立即從共享池中單獨清除SQL。這可能會導致競爭條件,所以這種方法只有在從未被同時調用的情況下才有效。

--Create simple test type for function. 
create or replace type clob_table is table of clob; 

--Table function that returns the SQL that called it. 
--This requires elevated privileges to run. 
--To simplify the code, run this as SYS: 
-- "grant execute on sys.dbms_shared_pool to your_user;" 
--(If you don't want to do that, convert this to invoker's rights and use dynamic SQL.) 
create or replace function my_tfn return clob_table is 
    v_my_type clob_table; 
    type string_table is table of varchar2(4000); 
    v_addresses string_table; 
    v_hash_values string_table; 

begin 
    --Get calling SQL based on the SQL text. 
    select sql_fulltext, address, hash_value 
    bulk collect into v_my_type, v_addresses, v_hash_values 
    from gv$sql 
    --Make sure there is something unique in the query. 
    where sql_fulltext like '%my_tfn%' 
     --But don't include this query! 
     --(Normally creating a quine is a challenge, but in V$SQL it's more of 
     -- a challenge to avoid quines.) 
     and sql_fulltext not like '%quine%'; 

    --Flush the SQL statements immediately, so they won't show up in next run. 
    for i in 1 .. v_addresses.count loop 
     sys.dbms_shared_pool.purge(v_addresses(i)||', '||v_hash_values(i), 'C'); 
    end loop; 

    --Return the SQL statement(s). 
    return v_my_type; 
end; 
/

現在查詢像這些將返回自己,表明PL/SQL代碼被讀取調用它的SQL:

SELECT * FROM TABLE(my_tfn) where 1=1; 
SELECT * FROM TABLE(my_tfn) where 2=2; 

但是,即使你要經歷這些麻煩 - 你是什麼去做結果?解析SQL非常困難,除非您可以確保每個人始終遵循嚴格的語法規則。

+0

這太棒了!非常感謝。 –

+0

我該怎麼處理它?我正在研究不同的技術,我可以使用一個單一的TFN來滿足許多不同的要求。 假設返回類型是一個將許多相關表連接在一起的展開數據集。但是,當只需要少數屬性時,我想避免不必要的工作。 不確定我是否可以使用你的技術。併發是一個問題。但是這個東西讓我想想。這是我正在設計的數據虛擬化解決方案。 –