From 974bce9aeb169b3f8c08924d8afb95bedc4a6c53 Mon Sep 17 00:00:00 2001
From: Kirill Yukhin <kirill.yukhin@gmail.com>
Date: Thu, 29 Jun 2017 21:07:41 +0300
Subject: [PATCH] sql: Limit number of terms in SELECT compoind stmts

Right now SQL query compiler is run on top of fiber's stack,
which is limited to 64KB by default, so maximum
number of entities in compound SELECT statement should be less than
50 (verified by experiment) or stack guard will be triggered.

In future we'll introduce heuristic which should understand that
query is 'complex' and run compilation in separate thread with larger
stack. This will also allow us not to block Tarantool while compiling
the query.

Closes #2548
---
 src/box/sql/sqliteLimit.h              |  6 ++++-
 test/sql/sql-select-compound-limit.lua | 37 ++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 1 deletion(-)
 create mode 100644 test/sql/sql-select-compound-limit.lua

diff --git a/src/box/sql/sqliteLimit.h b/src/box/sql/sqliteLimit.h
index 0554e61581..e04401d305 100644
--- a/src/box/sql/sqliteLimit.h
+++ b/src/box/sql/sqliteLimit.h
@@ -77,9 +77,13 @@
 ** if the number of terms is too large.  In practice, most SQL
 ** never has more than 3 or 4 terms.  Use a value of 0 to disable
 ** any limit on the number of terms in a compount SELECT.
+**
+** Tarantool: gh-2548: Fiber stack is 64KB by default, so maximum
+** number of entities should be less than 50 or stack guard will be
+** triggered.
 */
 #ifndef SQLITE_MAX_COMPOUND_SELECT
-# define SQLITE_MAX_COMPOUND_SELECT 500
+# define SQLITE_MAX_COMPOUND_SELECT 50
 #endif
 
 /*
diff --git a/test/sql/sql-select-compound-limit.lua b/test/sql/sql-select-compound-limit.lua
new file mode 100644
index 0000000000..e33792598f
--- /dev/null
+++ b/test/sql/sql-select-compound-limit.lua
@@ -0,0 +1,37 @@
+
+box.cfg{wal_mode='none'}
+
+table_count = 51
+
+for _, term in ipairs({'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT'}) do 
+    for i = 1,table_count do
+        drop_string = 'DROP TABLE IF EXISTS t' .. i .. ';\n'
+        box.sql.execute(drop_string)
+    end
+
+    for i = 1,table_count do
+        create_string = 'CREATE TABLE t' .. i .. ' (s1 int primary key, s2 int);\n'
+        box.sql.execute(create_string)
+    end
+
+    for i = 1,table_count do
+        insert_string = 'INSERT INTO t' .. i .. ' VALUES (0,' .. i .. ');\n'
+        box.sql.execute(insert_string)
+    end
+
+    select_string = ''
+    for i = 1,table_count-1 do
+        if i > 1 then select_string = select_string .. ' ' .. term .. ' ' end
+        select_string = select_string .. 'SELECT * FROM t' .. i
+    end
+
+    if not pcall(function() box.sql.execute(select_string) end) then
+        print('not ok')
+    end
+
+    select_string = select_string .. ' ' .. term ..' ' .. 'SELECT * FROM t' .. table_count
+    if pcall(function() box.sql.execute(select_string) end) then
+        print('not ok')
+    end
+end
+
-- 
GitLab