Изменить строки оператора PL / SQL в C ++ - PullRequest
2 голосов
/ 23 октября 2009

Это мой вариант использования: ввод - это строка, представляющая оператор Oracle PL / SQL произвольной сложности. Мы можем предположить, что это одно утверждение (не сценарий). Теперь, несколько битов этой входной строки должны быть переписаны .

например. Имена таблиц должны иметь префикс, агрегатные функции в списке выбора, которые не используют псевдоним столбца, должны быть назначены по умолчанию:

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
...

становится

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
...

(Отказ от ответственности: просто чтобы проиллюстрировать проблему, утверждение не имеет смысла)

Поскольку агрегатные функции могут быть вложенными, а subSELECTs - это b_tch, я не смею использовать регулярные выражения. Ну, на самом деле я добился и достиг 80% успеха, но мне нужны оставшиеся 20%.

Правильный подход, я полагаю, заключается в использовании грамматик и синтаксических анализаторов. Я возился с c ++ ANTLR2 (хотя я не очень разбираюсь в грамматике и разборе с помощью таких). Я не вижу простой способ получить биты SQL:

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

Может быть, кто-нибудь может дать некоторые советы о том, как "профессионалы разбора" будут решать эту проблему? РЕДАКТИРОВАТЬ: я использую Oracle 9i .

Ответы [ 2 ]

2 голосов
/ 23 октября 2009

Может быть, вы можете использовать это, он изменяет оператор выбора в блок 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>

Смотрите здесь: http://forums.oracle.com/forums/thread.jspa?messageID=3693276&#3693276

Теперь вам нужно «только» проанализировать этот блок xml.

Редактировать1:

К сожалению, я не до конца понимаю потребности ОП, но я надеюсь, что это может помочь (это еще один способ задать «имена» столбцов, например, запроса select count(*),max(dummy) from dual):

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;
/

(Подробнее см. Здесь: http://www.psoug.org/reference/dbms_sql.html)

ОП также хочет иметь возможность изменять имя схемы таблицы в запросе. Я думаю, что проще всего добиться этого - запросить имена таблиц из user_tables и выполнить поиск в операторах sql этих имен таблиц и добавить их префикс или сделать 'alter session set current_schema = ....'.

1 голос
/ 26 октября 2009

Если источником строк оператора SQL являются другие кодировщики, вы можете просто настаивать на том, что части, которые необходимо изменить, просто помечаются специальными условными обозначениями, например, пишите $ TABLE вместо имени таблицы или $ TABLEPREFIX, где один необходимо. Затем можно найти места, которые необходимо исправить, с помощью поиска и замены подстроки.

Если у вас действительно есть произвольные строки SQL, и вы не можете их правильно пометить, вам нужно как-то проанализировать строку SQL, как вы заметили. XML-решение, безусловно, является одним из возможных способов.

Другой способ - использовать систему программной трансформации . Такой инструмент может анализировать строку для экземпляра языка, создавать AST, выполнять анализ и преобразование AST, а затем выплевывать исправленную строку.

Набор реинжиниринга программного обеспечения DMS - это такая система. Он имеет синтаксический анализатор PLSQL. И он может использовать шаблонно-ориентированные преобразования для выполнения переписываний, которые вам нужны. Для вашего примера, включающего выбор предметов:

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

Чтобы прочитать правило, вы должны понимать, что содержимое внутри кавычек представляет собой абстрактные деревья в каком-либо компьютерном языке, которым мы хотим манипулировать. Фраза «доменный PLSQL» гласит: «используйте анализатор PLSQL» для обработки содержимого строки в кавычках, как он это знает. (У DMS есть много синтаксических анализаторов на выбор). Условия «expression» и «select_item» являются грамматическими конструкциями на интересующем языке, например, PLSQL в этом случае. Смотрите железнодорожные схемы в вашем справочном руководстве по PLSQL. Обратная косая черта представляет escape-/ мета-информацию, а не целевой синтаксис языка.

Правило гласит: преобразуйте те проанализированные элементы, которые являются select_item s. которые состоят исключительно из выражения \ e путем преобразования его в select_item , состоящий из того же выражения \ e и соответствующего столбец ( \ column (\ e) ), предположительно основанный на положении в списке элементов выбора для конкретной таблицы. Вам нужно будет реализовать функцию column , которая может определить соответствующее имя с позиции выбранного элемента. В этом примере я решил определить функцию столбца, чтобы принять выражение интереса в качестве аргумента; выражение фактически передается как совпавшее дерево, и, таким образом, функция столбца может определить, где оно находится в списке select_items , пройдя вверх по дереву абстрактного синтаксиса.

Это правило обрабатывает только выбранные элементы. Вы бы добавили больше правил, чтобы справиться с другими интересующими вас случаями.

Что система преобразования делает для вас:

  • разбирать интересующий фрагмент языка
  • построить AST
  • позволяет вам сопоставлять шаблоны для достопримечательностей (путем сопоставления шаблонов AST) но с использованием поверхностного синтаксиса целевого языка
  • заменить совмещенные рисунки другими рисунками
  • вычислить произвольные замены (как ASTs)
  • восстановить исходный текст из модифицированных AST.

Хотя написание правил не всегда тривиально, это то, что необходимо, если ваша проблема указано как изложенное.

Предлагаемое в XML решение - это еще один способ создания таких AST. Он не имеет хороших свойств сопоставления с образцом, хотя вы можете многое получить от XSLT. Что я не знаю, так это то, что у XML есть дерево разбора во всех деталях; синтаксический анализатор DMS обеспечивает это по своему замыслу, так как это необходимо, если вы хотите выполнить произвольный анализ и преобразование.

...