Análisis de SQL utilizando pyparsing

Estoy aprendiendo PyParsing en las últimas semanas. Planeo usarlo para obtener nombres de tablas de sentencias de SQL. He miradohttp://pyparsing.wikispaces.com/file/view/simpleSQL.py. Pero tengo la intención de mantener la gramática simple porque no estoy tratando de analizar cada parte de la declaración seleccionada, sino que busco solo nombres de tablas. También es bastante complicado definir la gramática completa para cualquier base de datos moderna disponible comercialmente como Teradata.

#!/usr/bin/env python

from pyparsing import *
import sys

semicolon = Combine(Literal(';') + lineEnd)
comma = Literal(',')
lparen = Literal('(')
rparen = Literal(')')

# Keyword definition
update_kw, volatile_kw, create_kw, table_kw, as_kw, from_kw, \
where_kw, join_kw, left_kw, right_kw, cross_kw, outer_kw, \
on_kw , insert_kw , into_kw= \
    map(lambda x: Keyword(x, caseless=True), \
        ['UPDATE', 'VOLATILE', 'CREATE', 'TABLE', 'AS', 'FROM',
         'WHERE', 'JOIN' , 'LEFT', 'RIGHT' , \
         'CROSS', 'OUTER', 'ON', 'INSERT', 'INTO'])

# Teradata SQL allows SELECT and well as SEL keyword
select_kw = Keyword('SELECT', caseless=True) | Keyword('SEL' , caseless=True)

# list of reserved keywords
reserved_words = (update_kw | volatile_kw | create_kw | table_kw | as_kw |
                  select_kw | from_kw | where_kw | join_kw |
                  left_kw | right_kw | cross_kw | on_kw | insert_kw |
                  into_kw)

# Identifier can be used as table or column names. They can't be reserved words
ident = ~reserved_words + Word(alphas, alphanums + '_')

# Recursive definition for table
table = Forward()
# simple table name can be identifer or qualified identifier e.g. schema.table
simple_table = Combine(Optional(ident + Literal('.')) + ident)
# table name can also a complete select statement used as table
nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \   
               from_kw.suppress() + table + rparen.suppress()
# table can be simple table or nested table
table << (nested_table | simple_table)
# comma delimited list of tables
table_list = delimitedList(table)
# Building from clause only because table name(s) will always appears after that
from_clause = from_kw.suppress() + table_list


txt = """
SELECT p, (SELECT * FROM foo),e FROM a, d, (SELECT * FROM z), b
"""
for token, start, end in from_clause.scanString(txt):
    print token

Una cosa que vale la pena mencionar aquí. Uso "SkipTo (from_kw)" para saltar sobre la lista de columnas en la declaración SQL. Esto se debe principalmente a evitar la definición de la gramática para la lista de columnas, que puede ser una lista de identificadores delimitada por comas, muchos nombres de funciones, funciones analíticas de DW y cuáles no. Con esta gramática puedo analizar la declaración anterior, así como cualquier nivel de anidamiento en la lista de columnas o la lista de tablas de SELECCIONAR.

['foo']
['a', 'd', 'z', 'b']

Estoy enfrentando un problema cuando SELECT tiene donde la cláusula:

nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \   
               from_kw.suppress() + table + rparen.suppress()

Cuando la cláusula WHERE está allí, la misma declaración puede parecer: SELECCIONAR ... DE a, d, (SELECCIONAR * DE z DÓNDE (c1 = 1) y (c2 = 3)), p Pensé en cambiar la definición de "tabla anidada" a:

nested_table = lparen.suppress() + select_kw.suppress() + SkipTo(from_kw).suppress() + \   
               from_kw.suppress() + table + Optional(where_kw + SkipTo(rparen)) + rparen

Pero esto no funciona, ya que coincide con el paréntesis correcto después de "c = 1". Lo que me gustaría saber es cómo saltar al paréntesis derecho que coincida con el paréntesis izquierdo justo antes de "SELECT * FROM z ..." No sé cómo hacerlo usando PyParsing

También en una nota diferente, busco un consejo sobre la mejor manera de obtener nombres de tablas de complejos SQL anidados. Cualquier ayuda es muy apreciada.

Gracias abhijit

Respuestas a la pregunta(1)

Su respuesta a la pregunta