Commit Diff


commit - 95733c361de3a318d33765e17d336fbbcdce0d58
commit + be73d93515f41de7263d2803f28aa0fcae6fe3a4
blob - /dev/null
blob + cc92932dc7dfda8779ef4019f49a44ec5ff11180 (mode 644)
--- /dev/null
+++ tests/tarantool_box_execute-mutator.lua
@@ -0,0 +1,243 @@
+--[[
+-- TODO:
+-- https://in2test.lsi.uniovi.es/sqlmutation/
+-- https://cosette.cs.washington.edu/
+-- https://www.cs.cmu.edu/~15811/papers/db.pdf
+-- https://github.com/uwdb/Cosette
+-- https://github.com/sqlancer/sqlancer
+-- https://github.com/Practical-Formal-Methods/queryFuzz
+-- https://github.com/PSU-Security-Universe/sqlright
+--
+-- https://github.com/PingCAP-QE/go-sqlancer/tree/master/pkg
+-- https://github.com/tarantool/sqlparser
+--
+-- Corpus:
+--   - https://github.com/PSU-Security-Universe/sqlright/tree/main/SQLite/docker/fuzz_root/inputs
+--
+-- Automatic Test Generation for Mutation Testing on Database Applications
+--
+-- Sqlsmith
+--
+-- An Experimental Case Study to Applying Mutation Analysis for SQL Queries
+--
+-- SQLMutation - Generation of mutants for testing SQL database queries
+--
+-- Generating test data for killing SQL mutants: A constraint-based approach
+--
+]]
+
+local lpeg = require("lpeg")
+local locale = lpeg.locale
+local P = lpeg.P
+--local R = lpeg.R
+--local S = lpeg.S
+local V = lpeg.V
+local C = lpeg.C
+--local Cb = lpeg.Cb
+--local Cc = lpeg.Cc
+--local Cf = lpeg.Cf
+--local Cg = lpeg.Cg
+--local Cp = lpeg.Cp
+--local Cs = lpeg.Cs
+--local Ct = lpeg.Ct
+--local Cmt = lpeg.Cmt
+
+---
+-- Returns a pattern which matches the literal string caselessly.
+--
+-- @param literal A literal string to match case-insensitively.
+-- @return An LPeg pattern.
+--
+local function caseless(literal)
+    local caseless = lpeg.Cf((lpeg.P(1) / function (a)
+            return lpeg.S(a:lower() .. a:upper())
+        end)^1, function (a, b)
+            return a * b
+        end)
+    return assert(caseless:match(literal))
+end
+
+local K = caseless
+
+--- Simple printf-style function.
+local function printf(...)
+    print(string.format(...))
+end
+
+---
+-- Adds hooks to a grammar to print debugging information.
+--
+-- Debugging LPeg grammars can be difficult. Calling this function on your
+-- grammmar will cause it to print ENTER and LEAVE statements for each rule, as
+-- well as position and subject after each successful rule match.
+--
+-- For convenience, the modified grammar is returned; a copy is not made
+-- though, and the original grammar is modified as well.
+--
+-- Credits: http://lua-users.org/lists/lua-l/2009-10/msg00774.html
+--
+-- @param grammar The LPeg grammar to modify
+-- @param printer A printf-style formatting printer function to use.
+--                Default: stdnse.debug1
+-- @return The modified grammar.
+--
+local function debug(grammar, printer)
+    printer = printer or printf
+    for k, p in pairs(grammar) do
+        local enter = lpeg.Cmt(lpeg.P(true), function(s, p, ...)
+            printer("ENTER %s", k)
+            return p
+        end)
+        local leave = lpeg.Cmt(lpeg.P(true), function(s, p, ...)
+            printer("LEAVE %s", k)
+            return p
+        end) * (lpeg.P("k") - lpeg.P "k")
+        grammar[k] = lpeg.Cmt(enter * p + leave, function(s, p, ...)
+            printer("---%s---", k)
+            printer("pos: %d, [%s]", p, s:sub(1, p-1))
+            return p
+        end)
+    end
+
+    return grammar
+end
+
+local mysql = locale {
+
+  V "sql_stmt",
+
+  sql_stmt = V "space"^0 * (
+                V "select_stmt" +
+                V "update_stmt") *
+             V "space"^0 * (
+                P ";" + -1),
+
+  select_stmt = K "SELECT" *
+                V "space"^0 *
+                V "select_expr_list" *
+                V "space"^0 *
+                V "from_clause"^-1,
+
+  from_clause = K "FROM" *
+                V "space"^0 *
+                V "table_references" *
+                V "space"^0 *
+                V "where_clause"^-1,
+
+  where_clause = K "WHERE" *
+                 V "space"^0 *
+                 V "where_condition",
+
+  update_stmt = K "UPDATE" *
+                V "space"^0 *
+                P "t set id = 1", -- TODO
+
+  select_expr_list = V "select_expr" *
+                     V "space"^0 *
+                     (P "," *
+                      V "space"^0 *
+                      V "select_expr")^0,
+
+  select_expr = P "*" + (
+                    V "table_name" *
+                    P "." *
+                    P "*") +
+                V "column_item",  -- TODO sql function
+
+  -- TODO
+  table_references = P "table1",
+
+  where_condition = V "expr",
+
+  column_item = (V "expr" *
+                 V "space"^0 *
+                 K "AS" *
+                 V "space"^0 *
+                 V "column_alias" +
+                 V "expr" *
+                 V "space"^0 *
+                 V "column_alias" +
+                 V "expr"),
+
+  -- See expr in http://www.sqlite.org/lang_select.html
+  -- See http://dev.mysql.com/doc/refman/5.5/en/expressions.html
+  expr = (V "atomic_expr" * (V "space"^0 *
+              V "binary_operator" *
+              V "space"^0 *
+              V "expr"
+          )^-1),
+
+  atomic_expr = (V "literal_value" +
+                 V "variable" +
+                 V "column_expr" +
+                 V "unary_operator" *
+                 V "space"^0 *
+                 V "expr"),
+
+  column_expr = (V "schema_name" *
+                 P "." *
+                 V "table_name" *
+                 P "." *
+                 V "column_name" +
+                 V "table_name" *
+                 P "." *
+                 V "column_name" +
+                 V "column_name"),
+
+  schema_name = V "name",
+  column_alias = V "name",
+  column_name = V "name",
+  table_name = V "name",
+
+  binary_operator = (K "OR" +
+                     P "||" +
+                     K "XOR" +
+                     K "AND" +
+                     P "&&"
+                     ) + V "comparison_operator",
+
+  comparison_operator = (P "=" +
+                         P ">=" +
+                         P ">" +
+                         P "<=" +
+                         P "<" +
+                         P "<>" +
+                         P "!="),
+
+  unary_operator = (K "NOT" +
+                    P "!"),
+
+  variable = V "name",
+
+  literal_value = V "numeric_literal" +
+                  V "string_literal" +
+                  P "NULL" +
+                  P "CURRENT_TIME" +
+                  P "CURRENT_DATE" +
+                  P "CURRENT_TIMESTAMP",  -- see http://dev.mysql.com/doc/refman/5.5/en/literals.html
+
+  -- not enough, see http://dev.mysql.com/doc/refman/5.5/en/number-literals.html
+  numeric_literal = V "digit"^1,
+
+  string_literal = (P "_" *
+                    V "charset_name" +
+                    caseless "n")^-1 * V "real_string_literal",
+
+  -- not enough, see http://dev.mysql.com/doc/refman/5.5/en/string-literals.html
+  real_string_literal = P '"' * (1 - P '"')^0 * P '"' + P "'" * (1 - P "'")^0 * P "'",
+
+  charset_name = V "name",
+
+  name = P "`"^-1 * ( V "alnum" + P "_" )^1 * P "`"^-1,
+}
+
+local mysql_grammar = P(C(mysql))
+
+local res = mysql_grammar:match("SELECT * FROM table1 WHERE a = 1")
+if res then
+    print(res)
+else
+    local mysql_grammar_debug = P(debug(mysql))
+    res = mysql_grammar_debug:match("SELECT * FROM table1 WHERE a = 1")
+    print(res)
+end