cordas declaração Modificar PL / SQL em C ++
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
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.