捕获无效更新 - Regexp_LIKE

时间:2015-04-23 17:44:36

标签: sql regex oracle oracle-sqldeveloper

我想要捕获没有WHERE子句的更新语句。如果用户更新table1,则必须有where子句。

模式1:格式错误

UPDATE table1 SET column1 = 'Test'

模式1:格式正确

UPDATE table1 SET column1 = 'Test' WHERE ... col1 = ...

而......意味着介于两者之间。

模式2:格式错误

UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1)

模式2:格式正确

UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1) WHERE ... col1 = ...

由于内部查询调用table2,因此WHERE子句不是必需的。

模式3:格式错误

UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1)

模式3:格式正确

UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1 WHERE ... col1 = ...) WHERE ... col1 = ...

模式4:正确的格式;不需要where子句

UPDATE table2 SET columnA = (SELECT columnB FROM table3 WHERE rownum = 1)

我打算编写一个程序来捕获错误的更新格式。但是,我必须首先弄清楚regexp_like语法。

我尝试了很多方法,但无法真正抓住每一种模式。以下是我正在尝试的模板查询:

WITH tbl AS
(
  SELECT 'UPDATE table1 SET column1 = 999 WHERE col1 = 111' as col1 FROM DUAL
  UNION
  SELECT 'UPDATE table1 SET column1 = (SELECT columnA FROM table2 WHERE rownum = 1) WHERE col1 = 111' FROM DUAL
  UNION
  SELECT 'UPDATE table1 SET column1 = (SELECT column2 FROM table1 WHERE rownum = 1 WHERE col1 = 111) WHERE col1 = 111' FROM DUAL
  UNION
  SELECT 'UPDATE table2 SET columnA = (SELECT columnB FROM table3 WHERE rownum = 1)' FROM DUAL
)
SELECT col1, 'pattern 1' FROM tbl WHERE  REGEXP_LIKE (upper(col1), 'UPDATE.*TABLE1.*SET.*WHERE.*col1.*=.*')
UNION ALL
SELECT col1, 'pattern 2' FROM tbl WHERE  REGEXP_LIKE (upper(col1), '') -- ???
UNION ALL
SELECT col1, 'pattern 3' FROM tbl WHERE  REGEXP_LIKE (upper(col1), '') -- ???
UNION ALL
SELECT col1, 'pattern 4' FROM tbl WHERE  REGEXP_LIKE (upper(col1), '') -- ???

假设我只是想搜索一个字符串。该查询将作为字符串参数传递给存储过程。

我正在使用Oracle SQL Developer。

感谢任何帮助。

3 个答案:

答案 0 :(得分:0)

您可以使用以下内容:

^UPDATE\s*table1\s*SET\s*\w+\s*=\s*(.+?)\s*WHERE[^\)]*$|^UPDATE\s*((?!table1).)*$
  • 匹配table1
  • 以外的表格上的所有更新语句
  • 仅使用" where子句匹配更新语句"在table1

注意:如果与g,i and m修饰符一起使用,则效果最佳。

请参阅DEMO and Explanation

答案 1 :(得分:0)

如果您的系统是开放式的,用户可以传入任意选择或更新语句,那么捕获缺少的where子句并不能真正解决真正的问题。但假设您必须拥有此功能,那么在执行它之前,可能会在每个语句上运行解释计划,然后检查成本或路径选项。例如:

EXPLAIN PLAN
    SET STATEMENT_ID = 'BAD1' FOR
SELECT * from big_table;

输出:

STATEMENT_ID    OPERATION   OPTIONS OPTIMIZER   COST    CARDINALITY
BAD1    SELECT STATEMENT        ALL_ROWS    344119  40523300
BAD1    TABLE ACCESS    FULL    ANALYZED    344119  40523300

" Good"语句(使用索引)可能如下所示:

EXPLAIN PLAN
    SET STATEMENT_ID = 'GOOD1' FOR
SELECT * from big_table where colA=123;

输出:

STATEMENT_ID    OPERATION   OPTIONS OPTIMIZER   COST    CARDINALITY
GOOD1   SELECT STATEMENT        ALL_ROWS    3   1
GOOD1   TABLE ACCESS    BY INDEX ROWID  ANALYZED    3   1
GOOD1   INDEX   UNIQUE SCAN ANALYZED    2   1

请注意表格访问权限的差异,高成本与低成本的索引扫描。

无论如何,也不完美,但可能比一些正则表达式更好。

答案 2 :(得分:0)

我认为你不应该这样做。即使您信任您的用户,也无法区分“好”查询和“错误”查询(尤其是正则表达式)。 让用户直接操作数据库可能会破坏系统的商业规则(错误或自愿)

如果可以限制用例,可能更安全的替代方法是让用户从列表中选择参数化更新查询,并输入参数。我觉得你不能或不想给他们一个合适的用户界面。