Парсинг имен объектов из хранимых процедур с использованием Python - PullRequest
0 голосов
/ 19 ноября 2018

Мне нужно взять хранимую процедуру Teradata и извлечь различные объекты (таблицы, представления, процедуры), используемые в ней. Для этого мне нужно написать синтаксический анализатор для анализа различных запросов SQL, таких как SELECT, MERGE, UPDATE и т. Д. Также не рекомендуется использовать стороннюю библиотеку.

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

  • Я просматривал некоторые существующие ссылки на стек-потоки, и в основном предлагалось использовать pyparsing или Python-sqlparse.
  • Могу ли я написать парсер, используя только регулярные выражения? Я не достаточно уверен, так как есть много способов, которыми можно написать запрос, и может ли регулярное выражение обрабатывать все случаи?
  • Если pyparsing является наиболее предпочтительным решением, насколько сложно понять и определить в нем грамматику sql?

Я взял ссылку с сайта и написал следующий код для разбора запросов SELECT

def tables_in_sel_query(sql_str):

    # Comma shall be prefixed and suffixed with a space
    sql_str = re.sub(r'\s*?,'," , ",sql_str,re.I|re.S)

    #Remove whitespaces after .
    sql_str =  re.sub(r'(.+?)\.\s+?',r'\1.',sql_str,re.I)

    # remove the /* */ comments
    q = re.sub(r"/\*[^*]*\*+(?:[^*/][^*]*\*+)*/", "", sql_str)

    # split on blanks, parens and semicolons
    tokens = re.split(r"[\s)(;]+", q)


    # scan the tokens. if we see a FROM or JOIN, we set the get_next
    # flag, and grab the next one (unless it's another keyword).

    result = []
    get_next = False
    for tok in tokens:
        if get_next:
            if tok.lower() not in 
["","select","order","group","where","inner","left","right","on"]:
                if (tok != ",") and tok.count(".") > 0:
                    result.append(tok.strip(","))
            else:
                get_next = False
            continue
        get_next = tok.lower() in ["from", "join"]

    return result

Хотя это работает нормально, но мне нужно реализовать такую ​​функцию для каждого из типов запросов. Кто-нибудь может предложить наилучший из возможных подходов?

...