Pergunta

Este é o meu caso de uso: de entrada é uma string representando um declaração Oracle PL / SQL de complexidade arbitray. Podemos assumir que é uma declaração única (não um script). Agora, vários bits desta cadeia de entrada tem que ser reescrito .

por exemplo. nomes de tabela precisa ser prefixado, funções agregadas na lista de seleção que não utilizam um alias de coluna deve ser atribuído a um padrão:

SELECT SUM(ABS(x.value)), 
TO_CHAR(y.ID,'111,111'),
y.some_col
FROM
tableX x,
(SELECT DISTINCT ID
FROM tableZ z
WHERE ID > 10) y
WHERE
...

se torna

SELECT SUM(ABS(x.value)) COL1, 
TO_CHAR(y.ID,'111,111') COL2,
y.some_col
FROM
pref.tableX x,
(SELECT DISTINCT ID, some_col
FROM pref.tableZ z
WHERE ID > 10) y
WHERE
...

(Disclaimer: apenas para ilustrar a questão, a declaração não faz sentido)

Uma vez que as funções de agregação pode ser aninhado e Subselects são uma b_tch, não me atrevo a usar expressões regulares. Bem, na verdade eu fiz e alcançou 80% de sucesso, mas eu preciso os restantes 20%.

A abordagem certa, presumo, é a utilização de gramáticas e analisadores. Eu brincava ao redor com c ++ ANTLR2 (embora eu não sei muito sobre gramáticas e analisar com a ajuda de tal). Eu não vejo uma maneira fácil de obter os bits de SQL:

list<string> *ssel = theAST.getSubSelectList(); // fantasy land

Alguém poderia talvez fornecer algumas dicas sobre como "profissionais de análise" iria prosseguir esta questão? EDIT:. Eu estou usando Oracle 9i

Foi útil?

Solução

Talvez você possa usar isso, ele muda de uma instrução select em um bloco de xml:

declare
    cl clob;
begin
    dbms_lob.createtemporary (
        cl,
        true
    );
    sys.utl_xml.parsequery (
        user,
        'select e.deptno from emp e where deptno = 10',
        cl
    );
    dbms_output.put_line (cl);
    dbms_lob.freetemporary (cl);
end;
/ 

<QUERY>
  <SELECT>
    <SELECT_LIST>
      <SELECT_LIST_ITEM>
        <COLUMN_REF>
          <SCHEMA>MICHAEL</SCHEMA>
          <TABLE>EMP</TABLE>
          <TABLE_ALIAS>E</TABLE_ALIAS>
          <COLUMN_ALIAS>DEPTNO</COLUMN_ALIAS>
          <COLUMN>DEPTNO</COLUMN>
        </COLUMN_REF>
        ....
        ....
        ....
</QUERY>

Veja aqui: http://forums.oracle.com/forums /thread.jspa?messageID=3693276�

Agora você 'apenas' necessidade de analisar este bloco xml.

Edit1:

Infelizmente eu não compreender totalmente as necessidades do OP mas espero que isso pode ajudar (É outra maneira de perguntar os 'nomes' das colunas para select count(*),max(dummy) from dual exemplo de consulta):

set serveroutput on

DECLARE
 c       NUMBER;
 d       NUMBER;
 col_cnt PLS_INTEGER;
 f       BOOLEAN;
 rec_tab dbms_sql.desc_tab;
 col_num NUMBER;

PROCEDURE print_rec(rec in dbms_sql.desc_rec) IS
BEGIN
  dbms_output.new_line;
  dbms_output.put_line('col_type = ' || rec.col_type);
  dbms_output.put_line('col_maxlen = ' || rec.col_max_len);
  dbms_output.put_line('col_name = ' || rec.col_name);
  dbms_output.put_line('col_name_len = ' || rec.col_name_len);
  dbms_output.put_line('col_schema_name= ' || rec.col_schema_name);
  dbms_output.put_line('col_schema_name_len= ' || rec.col_schema_name_len);
  dbms_output.put_line('col_precision = ' || rec.col_precision);
  dbms_output.put_line('col_scale = ' || rec.col_scale);
  dbms_output.put('col_null_ok = ');

  IF (rec.col_null_ok) THEN
    dbms_output.put_line('True');
  ELSE
    dbms_output.put_line('False');
  END IF;
END;

BEGIN
  c := dbms_sql.open_cursor; 
  dbms_sql.parse(c,'select count(*),max(dummy) from dual ',dbms_sql.NATIVE); 
  dbms_sql.describe_columns(c, col_cnt, rec_tab);

  for i in rec_tab.first..rec_tab.last loop
    print_rec(rec_tab(i));
  end loop;

  dbms_sql.close_cursor(c);
END;
/

(Veja aqui para mais informações: http://www.psoug.org/reference/ dbms_sql.html )

O OP também quero ser capaz de mudar o nome do esquema da tabela em uma consulta. Eu acho que a palavra mais fácil de conseguir isso é para consultar os nomes de tabela a partir user_tables e pesquisar na instrução SQL para esses nomes de tabela e prefixo-los ou fazer uma 'alter session set current_schema = ....'.

Outras dicas

Se a fonte das cordas instrução SQL são outros programadores, você poderia simplesmente insistir em que as partes que precisam mudar simplesmente são marcados por convenções escape especiais, por exemplo, write $ mesa em vez do nome da tabela, ou US $ TABLEPREFIX onde se está necessário. Em seguida, encontrar os lugares que precisam de correção pode ser realizado com uma pesquisa substring e substituição.

Se você realmente tem strings SQL arbitrários e não pode obtê-los muito bem marcado, você precisa analisar alguma forma a string SQL como você observou. A solução XML certamente é uma maneira possível.

Outra maneira é usar um programa de sistema de transformação . Essa ferramenta pode analisar uma string para uma instância de linguagem, ASTs construir, realizar análises e transformação em ASTs, e depois cuspir uma corda revista.

O DMS Software Reengineering Toolkit é tal sistema a. Tem PLSQL analisador extremidade dianteira. E pode usar transformações dirigida-padrão para realizar as regravações você parece precisar. Para o seu exemplo envolvendo selecionar itens:

domain PLSQL.
rule use_explicit_column(e: expression):select_item -> select_item
   "\e" -> "\e \column\(\e\)".

Para ler a regra, você precisa entender que o material dentro aspas representa árvores abstratas em alguns langauge computador que deseja manipular. O que a frase "PLSQL domínio" diz é, "usar o analisador PLSQL" para processar o conteúdo string, que é como ele sabe. (DMS tem muitos analisadores langauge para escolher). Os termos "Expressão" e "select_item" são construções gramaticais da linguagem do interesse, por exemplo, PLSQL neste caso. Veja os diagramas de estrada de ferro no seu manual de referência PLSQL. A barra invertida representa fuga de informação / meta em vez de sintaxe alvo langauge.

O que a regra diz que é, transformar esses elementos processadas que são que são select_item s que são compostos apenas por um expressão \ e , convertendo-a em um select_item consistindo de uma mesma expressão \ e e o correspondente coluna ( \ coluna (\ e) ), presumivelmente com base na posição na lista de itens de selecção para a tabela específica. Você teria que implementar uma coluna de função que pode determinar o nome correspondente da posição do item de seleção. Neste exemplo, eu escolhi para definir a função de coluna para aceitar a manifestação de interesse como argumento; a expressão é, na verdade, passado como a árvore correspondente, e, portanto, a função de coluna pode determinar onde ele está no select_items lista por percorrer a árvore de sintaxe abstrata.

Esta regra lida com apenas os itens selecionados. Você gostaria de acrescentar mais regras para lidar com os outros casos de seu interesse.

O que o sistema de transformação faz para você é:

  • analisar o fragmento de linguagem do interesse
  • construir um AST
  • deixá-lo correspondência de padrões para os locais de interesse (fazendo AST correspondência de padrão) mas usando a sintaxe superfície do langauge alvo
  • substituir padrões correspondidos por outros padrões
  • substituições aritrary de computação (como ASTs)
  • texto de origem regenerado dos ASTs modificados.

Ao escrever as regras nem sempre é trivial, é o que é necessário se o seu problema é indicado como colocada.

A solução XML sugerido é outra maneira de construir tais ASTs. Ele não tem as propriedades agradáveis ??padrão de correspondência, embora você pode ser capaz de obter um lote de XSLT. O que eu não sei é se o XML tem a árvore de análise em detalhe completo; o analisador DMS não fornecer este por design, pois é necessário se você quiser fazer uma análise e transformação arbitrária.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top