2008-09-26 12 views
16

Estaba escribiendo algunas pruebas de Unidad la semana pasada para un fragmento de código que generó algunas sentencias de SQL.Expresión regular para coincidir con la sintaxis SQL común?

Estaba tratando de encontrar una expresión regular que coincida con la sintaxis SELECT, INSERT y UPDATE para poder verificar que mis métodos generaran SQL válido, y después de 3-4 horas de buscar y jugar con varios editores de expresiones regulares me rendí .

Logré obtener coincidencias parciales, pero debido a que una sección entre comillas puede contener cualquier carácter, se expande rápidamente para que coincida con la totalidad de la declaración.

Me agradecería cualquier ayuda, no soy muy bueno con las expresiones regulares, pero me gustaría aprender más sobre ellas.

Por cierto, es C# regex lo que estoy buscando.

Aclaración

no quiero tener acceso a una base de datos ya que esto es parte de una prueba de unidad y no wa no tener que mantener una base de datos para probar mi código. que puede vivir más tiempo que el proyecto.

Respuesta

36

Las expresiones regulares pueden coincidir con los lenguajes, solo un autómata de estado finito puede analizar, lo cual es muy limitado, mientras que SQL es una sintaxis. Se puede demostrar que no se puede validar SQL con una expresión regular. Entonces, puedes dejar de intentarlo.

+0

De acuerdo. Aquí se necesita algún otro enfoque además de regexp. No hay forma de hacer coincidir la sintaxis legal para una instrucción select: http://download.oracle.com/docs/cd/B28359_01/server.111/b28286/statements_10002.htm#SQLRF01702 –

+0

De acuerdo. En realidad, necesitas un analizador SQL. Aquí hay un artículo que muestra cómo hacer una verificación de sintaxis de SQL fuera de línea específica del proveedor con la ayuda del analizador sql general: http://www.dpriver.com/blog/list-of-demos-illustrate-how-to-use-general -sql-parser/vendor-specific-offline-sql-syntax-check/ –

+1

Cualquier gramática libre de contexto se puede analizar mediante expresiones regulares modernas. Las expresiones regulares ya no están restringidas al análisis de idiomas regulares. Si esto fuera cierto, el lenguaje '{a^nb^n}' no sería analizable, sin embargo, esto puede ser analizado por la expresión regular '/^(a (\ 1)? B) $ /'. Consulte https://nikic.github.io/2012/06/15/The-true-power-of-regular-expressions.html para obtener más información. – Jack

0

¿Has probado los selectores perezosos? En lugar de coincidir tanto como sea posible, coinciden lo menos posible, que es probablemente lo que necesita para las comillas.

0

Supongo que hizo algo así como ". *" Intente en su lugar "[^"] * "que le impedirá comer toda la línea. Todavía dará falsos positivos en casos en los que tenga \" dentro de sus cadenas .

+0

No Especifiqué el espacio y el guion y llegué al final de la línea –

1

Fuera de la cabeza: ¿no podría pasar el SQL generado a una base de datos y usar EXPLAIN en ellos y capturar las excepciones que indicarían SQL mal formado?

+0

No es útil para una prueba unitaria donde no necesariamente tengo acceso a una base de datos, que sé que siempre se ejecutará –

+0

Depende de la servidor, por ejemplo, MySQL permite explicar solo en sentencias seleccionadas. – pilsetnieks

0

Para validar las consultas, simplemente ejecútelas con SET NOEXEC ON, así es como lo hace Entreprise Manager cuando analiza una consulta sin ejecutarla.

Además, si usa regex para validar consultas sql, puede estar casi seguro de que perderá algunos casos de esquina, o que la consulta no es válida por otros motivos, incluso si es sintácticamente correcta.

0

Sugiero crear una base de datos con el mismo esquema, posiblemente usando un motor sql incorporado, y pasar el sql a eso.

0

No creo que necesite siquiera tener el esquema creado para poder validar la declaración, porque el sistema no intentará resolver object_name, etc. hasta que haya analizado correctamente la declaración.

Con Oracle como ejemplo, que sin duda obtendrá un error si lo hizo:

select * from non_existant_table; 

En este caso, "ORA-00942: la tabla o vista no existe".

Sin embargo, si se ejecuta:

select * frm non_existant_table; 

entonces obtendrá un error de sintaxis, "ORA-00923: DE palabra clave no encuentra donde se esperaba".

Debería ser posible clasificar los errores en los errores de análisis de sintaxis que indican una sintaxis incorrecta y errores relativos al nombre de tablas y permisos, etc ..

A esto se añade el problema de los RDBMS diferentes e incluso diferentes versiones permitiendo diferentes sintaxis y creo que realmente tienes que ir al motor db para esta tarea.

2

Por lo que sé, esto va más allá de la expresión regular y de su aproximación a las artes oscuras de BnF y los compiladores.

http://savage.net.au/SQL/

mismas cosas sucede a las personas que quieren hacer resaltar la sintaxis correcta. Empiezas a meter cosas en expresiones regulares y luego terminas escribiendo un compilador ...

14

SQL es type-2 grammar, es demasiado poderoso para ser descrito por expresiones regulares. Es lo mismo que si decidiera generar código C# y luego validarlo sin invocar un compilador. El motor de base de datos, en general, es demasiado complejo para ser anulado fácilmente.

Dicho esto, puede probar ANTLR's SQL grammars.

+0

Cualquier gramática libre de contexto se puede analizar mediante expresiones regulares modernas. Las expresiones regulares ya no están restringidas al análisis de idiomas regulares. Si esto fuera cierto, el lenguaje '{a^nb^n}' no sería analizable, sin embargo, esto puede ser analizado por la expresión regular '/^(a (\ 1)? B) $ /'. Consulte https://nikic.github.io/2012/06/15/The-true-power-of-regular-expressions.html para obtener más información. – Jack

+0

@Jack, buen punto! Entonces, ¿cuál sería la regex de C# para ANSI SQL SELECT? – Constantin

0

Hay ANTLR grammars para analizar el SQL. Realmente es una mejor idea usar un in memory database o una base de datos muy liviana como sqlite. Me parece un desperdicio comprobar si el SQL es válido desde el punto de vista del análisis, y mucho más útil para verificar los nombres de tabla y columna y los detalles de su consulta.

1

Tuve el mismo problema: un enfoque que funcionaría para todas las sentencias estándar de sql sería desplegar una base de datos Sqlite en memoria y emitir la consulta en su contra, si vuelve una "tabla no existe" "error, entonces su consulta analizada correctamente.

-1
public bool IsValid(string sql) 
{ 
string pattern = @"SELECT\s.*FROM\s.*WHERE\s.*"; 
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase); 
return rgx.IsMatch(sql); 
} 
+4

Validación de sintaxis muy limitada y sin explicación ... – jessehouwing

+0

Pero el único ACTUAL intenta responder a la pregunta: +1 –

0

La mejor manera es validar los parámetros utilizados para crear la consulta, en lugar de la consulta en sí misma. Una función que recibe las variables puede verificar la longitud de las cadenas, números válidos, correos electrónicos válidos o lo que sea. Puede usar expresiones regulares para hacer estas validaciones.

Cuestiones relacionadas