2016-02-22 20 views
1

在源代碼中,如果我想找出某些內容,請說明特定列的更新位置。我正在使用下面的查詢來查找表(LEA_AGREEMENT_DTL)的列(BUCKET)正在更新的位置。搜索特定模式的源代碼(PL/SQL)

select * from user_source where upper(text) like '%UPDATE%LEA_AGREEMENT_DTL%BUCKET%'; 

現在,如果在paticular舍姆源被寫成我下面的查詢會告訴我在哪個過程的代碼寫的是:

Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE, bucket=V_bucket 
    where ProposalID = T_ProposalID; 

但如果代碼被寫成我下面的查詢將不給任何結果:

Update Lea_agreement_dtl 
    Set Dpd = No_Days_OverDuE, 
    bucket=V_bucket 
    where ProposalID = T_ProposalID; 

我的問題是我應該怎麼修改我的查詢在特定模式/用戶的源代碼搜索,使我獲得成功的結果在這兩種情況下。基本上我想找到該列在該特定模式下得到更新的所有過程/對象。

根據我的分析,如果整個查詢寫在一行,那麼我能夠搜索它,否則它不工作。

+1

在'USER_SOURCE'中,每行代碼存儲在一個單獨的行中。所以你必須遍歷每一行。 – Nitish

回答

0

主要有3種方法解決這個問題:

  1. 哈克一些與字符串函數和正則表達式一起。這是最常見的解決方案,但也充滿了漏洞。根據您搜索代碼的原因,這些漏洞可能無關緊要。這足以找到從哪裏開始編碼,但可能不足以向某人證明代碼已被覆蓋。
  2. 令牌輸入並通過令牌循環查找模式。詞法分析器可以處理單個正則表達式不容易處理的一些問題,如註釋和備選引用語法。通過對Oracle語法的深入瞭解,可以構建高度精確的解決方案。它仍然會錯過非常破碎的代碼(例如,可以使用UPDATE作爲變量創建代碼),動態SQL以及通過同義詞和視圖進行遞歸引用。
  3. 解析輸入並遍歷抽象語法樹以查找模式。這將是一個很好的100%準確的解決方案。不幸的是,在PL/SQL中沒有可用的高質量PL/SQL解析器。

下面的解決方案使用我創建的open-source PL/SQL lexer來解決這樣的問題。

示例過程

的字符串模式,UPDATE-LEA_AGREEMENT_DTL桶時,發生下面的三倍。但只有第4行的第一個UPDATE確實滿足條件。 (在Stackoverflow語法高亮顯示中,第三個更新可能看起來很奇怪,但在真正的PL/SQL中,第二個引號不會關閉該字符串。)

create or replace procedure search_test is 
begin 
    --Real match. 
    Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE, 
    bucket=V_bucket 
    where ProposalID = T_ProposalID; 

    --Exclude - ignore comments. 
    /*Update Lea_agreement_dtl Set Dpd = No_Days_OverDuE, bucket=V_bucket 
    where ProposalID = T_ProposalID;*/ 

    --Exclude - watch out for alternative quoting syntax. 
    Update Lea_agreement_dtl Set Dpd = q'[No_Days_OverDuE', bucket=V_bucket ]' 
    where ProposalID = T_ProposalID; 
end; 
/

匿名塊查找線路

--Find lines that update LEA_AGREEMENT_DTL.BUCKET. 
--Does not search dynamic SQL and does not recurse through view or synonyms. 
declare 
    v_tokens token_table; 

    v_update_line_number number; 
    v_has_update boolean := false; 
    v_has_table boolean := false; 
    v_has_column boolean := false; 
begin 
    --Get source and tokenize it. 
    v_tokens := tokenizer.tokenize(dbms_metadata.get_ddl('PROCEDURE', 'SEARCH_TEST')); 

    --Loop through tokens and look for UPDATE/LEA_AGREEMENT_DTL/BUCKET between semicolons. 
    for i in 1 .. v_tokens.count loop 
     --Reset if a semicolon is found. 
     if v_tokens(i).value = ';' then 
      v_has_update := false; 
      v_has_table := false; 
      v_has_column := false; 
     --Look for relevant tokens, in order. 
     elsif upper(v_tokens(i).value) = 'UPDATE' then 
      v_update_line_number := v_tokens(i).line_number; 
      v_has_update := true; 
     elsif v_has_update and upper(v_tokens(i).value) = 'LEA_AGREEMENT_DTL' then 
      v_has_table := true; 
     elsif v_has_table and upper(v_tokens(i).value) = 'BUCKET' then 
      v_has_column := true; 
     end if; 

     --Success if all conditions are met. 
     if v_has_update and v_has_table and v_has_column then 
      --Subtract 1 because DBMS_METADATA put a blank line at the beginning. 
      dbms_output.put_line('Found on line '||to_char(v_update_line_number-1)); 
      v_has_update := false; 
      v_has_table := false; 
      v_has_column := false; 
     end if; 

    end loop; 
end; 
/

結果

Found on line 4 
0

您可以使用此view

CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS 
SELECT TYPE, 
      NAME, 
      line, 
      LISTAGG(regexp_replace(text,'[[:space:]]',' '), ' ') WITHIN GROUP(ORDER BY norder) text 
     FROM (SELECT a.TYPE, 
        a.NAME, 
        a.line, 
        b.text, 
        b.line norder 
       FROM (SELECT line, 
          TYPE, 
          NAME, 
          text 
         FROM user_source 
        WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a, 
        user_source b 
      WHERE a.type = b.TYPE 
       AND a.name = b.name 
       AND b.line BETWEEN a.line AND (SELECT MIN(g.line) 
               FROM user_source g 
               WHERE regexp_like(g.TEXT, ';', 'i') 
               AND g.TYPE = a.TYPE 
               AND g.NAME = a.name 
               AND g.line >= a.line) 
      ORDER BY b.TYPE, 
         b.NAME, 
         b.line) c 
    GROUP BY TYPE, 
       NAME, 
       line 

LISTAGG使用Oracle 11g或更高版本。 如果您在使用以前版本的Oracle,你需要這個view

CREATE OR REPLACE VIEW V_UPDATE_USER_SOURCE AS 
SELECT TYPE, 
     NAME, 
     line, 
     XMLAGG(XMLELEMENT(E, regexp_replace(text, '[[:space:]]', ' ') || ' ')).EXTRACT('//text()') text 
FROM (SELECT a.TYPE, 
         a.NAME, 
         a.line, 
         b.text, 
         b.line norder 
       FROM (SELECT line, 
             TYPE, 
             NAME, 
             text 
           FROM user_source 
          WHERE regexp_like(text, '[[:space:]]update[[:space:]]', 'i')) a, 
         user_source b 
      WHERE a.type = b.TYPE 
       AND a.name = b.name 
       AND b.line BETWEEN a.line AND (SELECT MIN(g.line) 
                        FROM user_source g 
                       WHERE regexp_like(g.TEXT, ';', 'i') 
                        AND g.TYPE = a.TYPE 
                        AND g.NAME = a.name 
                        AND g.line >= a.line) 
      ORDER BY b.TYPE, 
           b.NAME, 
           b.line) 
     GROUP BY TYPE, 
       NAME, 
       line; 

它返回的數據集,其中包含所有update與多家,其中update開始行。

View可以regexp_like使用:

select * from V_UPDATE_USER_SOURCE t where regexp_like(text,'clients.*STATE','i') 

說明:

  • 客戶 - 表。
  • STATE - 更新列。