Deshabilite las confirmaciones explícitas en JDBC, detecte en SQL o coloque la base de datos en un estado de solo lectura


12

Antecedentes : estoy trabajando en http://sqlfiddle.com (mi sitio) y estoy tratando de evitar una posible vía de abuso allí. Espero que al preguntar sobre un problema que estoy abordando actualmente, sin querer empeore el posible abuso, pero ¿qué puede hacer? Confío en ustedes amigos.

Me gustaría evitar que cualquier usuario emita llamadas explícitas de 'confirmación' dentro de un bloque de transacciones dado. Desde el contexto de SQL Fiddle, el bloque de transacción es el código que se ejecuta en el panel del lado derecho. Básicamente, estoy repitiendo y ejecutando una lista de comandos SQL de texto sin formato, y quiero asegurarme de que todos los cambios que realicen se revertirán al final del lote. Normalmente, sus cambios se revierten, pero a veces hay una declaración explícita de 'confirmación' dentro del texto, por lo que, por supuesto, mi reversión no funcionará. Es muy probable que esta confirmación explícita de un usuario que intente romper el esquema en SQL Fiddle, por lo que otras personas que trabajen en ella verán errores.

Resultado deseado principal : Me gustaría deshabilitar confirmaciones explícitas en el nivel JDBC, si es posible. Esto se debe a que tengo que admitir múltiples proveedores de back-end de bases de datos y, por supuesto, cada uno tiene sus peculiaridades en el nivel bajo.

Opción alternativa : si no es posible configurar JDBC para deshabilitar confirmaciones explícitas, entonces estaría abierto a soluciones para detectar confirmaciones explícitas mientras se procesa un lote para cada uno de los siguientes backends: SQL Server, Oracle, MySQL y PostgreSQL.

Para SQL Server, pensé en esta solución: analizar el plan de consulta XML para la instrucción antes de ejecutarla y verificar la presencia de una entrada que coincida con esta XPath:

//*[@StatementType="COMMIT TRANSACTION"]

Creo que esto funcionaría bastante bien para SQL Server. Sin embargo, este enfoque no funciona para los otros tipos de bases de datos. La salida del plan de ejecución XML de Oracle para confirmaciones explícitas no hace referencia al hecho de que está ejecutando una declaración de confirmación (sino que simplemente repite la salida del plan de ejecución de las consultas que está confirmando). PostgreSQL y MySQL no proporcionan ningún resultado del plan de ejecución (XML o de otro tipo) para confirmaciones explícitas.

Eso me deja con verificar la declaración real de la palabra "commit". Esto funcionaría, excepto que puede haber todo tipo de variaciones posibles:

declare @sql varchar(50)
set @sql = 'com' + 'mit'
exec(@sql);

Lo anterior es un ejemplo para SQL Server (que podría solucionar), pero supongo que cosas similares serían posibles para Oracle, MySQL y PostgreSQL. ¿Estoy equivocado en esa suposición? ¿Quizás no permitirían declaraciones de compromiso "dinámicas"? Siéntase libre de usar SQL Fiddle (preferiblemente no el esquema de muestra o alguien con quien probablemente esté trabajando) para ver si puede hacer que ocurra algo similar en Oracle, MySQL y PostgreSQL. Si no, tal vez la simple detección de cadenas podría funcionar para ellos.

Otra posibilidad

Se me ocurrió otra opción: si conoces una forma de configurar cualquiera de estas bases de datos en modo de solo lectura, por ejemplo, mientras que en ese modo no se puede comprometer nada, eso también podría funcionar. Todavía tendría que permitir que se inicien las transacciones y que se ejecute el código dentro de ellas, siempre y cuando no se pueda confirmar nada en ese modo. ¿Es eso posible?

Actualizar

Lo que aprendí recientemente: esto en realidad no es un problema con PostgreSQL. Aparentemente, las confirmaciones emitidas dentro de un bloque de transacción no se aplicarán si ese mismo bloque finalmente se revierte (en Postgres). ¡Así que hurra por Postgres!

Gracias al enlace de Phil a la publicación SO, creo que puedo usar el hack DEFERRABLE INICIALMENTE DEFERIDO para que Oracle logre lo que busco (se generará un error si se emite un commit, pero puedo solucionarlo). Esto debería abordar Oracle. (Pensé por un momento que las transacciones anidadas podrían funcionar aquí, pero ¿no parece que Oracle admite transacciones anidadas? De todos modos, no pude encontrar nada que funcionara de esta manera).

Realmente todavía no tengo una solución para MySQL. Intenté usar transacciones anidadas, pero eso no parece funcionar. Estoy pensando seriamente en enfoques más drásticos para MySQL, como no permitir nada más que SELECCIONAR en el lado derecho o soltar / recrear la base de datos después de cada consulta. Sin embargo, ninguno de los dos suena bien.

Resolución

Entonces, he implementado las soluciones descritas para SQL Server y Oracle, y como mencioné, esto no es realmente un problema para PostgreSQL. Para MySQL, he tomado el paso algo desafortunado de restringir el panel de consulta para que solo seleccione declaraciones. DDL y DML para MySQL simplemente deberán ingresarse en el panel de esquema (el lado izquierdo). Espero que esto no rompa muchos viejos violines, pero creo que simplemente es lo que hay que hacer para garantizar la coherencia de los datos. ¡Gracias!


Vale la pena mencionar que también investigué mucho sobre los desencadenantes de "precompromiso". Parece que no existen, así que desafortunadamente esa tampoco es una opción.
Jake Feasel

2
Para Oracle, esto parece una buena forma astuta de atrapar COMMIT: stackoverflow.com/a/6463800/790702 Lo que él no menciona es que usted también debería ser capaz de detectar la violación de restricciones en su código, para detener la segunda situación ocurriendo
Philᵀᴹ

@Phil el único problema es que no tengo (y realmente no quiero) control sobre la definición de cada una de las tablas (las que están definidas en el panel izquierdo). De modo que la cláusula DEFERRABLE INICIALMENTE DIFERIDA no estaría allí (a menos que haya alguna forma de hacerlo automáticamente para todas las tablas, por ejemplo, ¿a través de un disparador del sistema que responda para crear declaraciones de tabla? Ugh)
Jake Feasel

1
@ NickChammas Necesito deshabilitar las confirmaciones para poder mantener el esquema (como se define en el panel lateral izquierdo) en un estado fijo. Podría haber cualquier cantidad de personas escribiendo consultas contra el mismo esquema tratando de resolver el mismo problema. Para evitar que interfieran entre sí, debo asegurarme de evitar que la estructura y los datos cambien. Esto se logra mediante transacciones revertidas, pero eso no sucede si se confirma el código del lado derecho.
Jake Feasel

2
@RickJames DDL crea confirmaciones implícitas en MySQL y Oracle, pero no en PostgreSQL o SQL Server. Los mecanismos que he implementado después de esta publicación manejan esa preocupación. En cuanto a ingresar SQL arbitrario, ¡ese es el punto!
Jake Feasel

Respuestas:


3

Para Oracle, esto parece una buena forma furtiva de atrapar COMPROMISOS:

/programming//a/6463800/790702

Lo que no menciona es que también debería poder detectar la violación de restricción en su código, para evitar que ocurra la segunda situación.


Genial, gracias de nuevo Phil. He podido hacer un buen uso de esta técnica para Oracle. Me hace desear que otras bases de datos admitan restricciones diferidas.
Jake Feasel

Sin preocupaciones. Entra en el chat y saluda :)
Philᵀᴹ
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.