Tarantool development patches archive
 help / color / mirror / Atom feed
* [tarantool-patches] [PATCH 0/3] Rework VIEW processing
@ 2018-04-03 14:54 Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives Nikita Pettik
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Nikita Pettik @ 2018-04-03 14:54 UTC (permalink / raw)
  To: tarantool-patches; +Cc: v.shpilevoy, Nikita Pettik

Branch: https://github.com/tarantool/tarantool/tree/np/gh-3300-parse-load-view
Issue: https://github.com/tarantool/tarantool/issues/3300

First patch of the series is about refactoring: as far as VIEWs
are always enabled, there is no need in OMIT_VIEW directive.
Alongside with this macros, several others are also removed.

Second patch adds to space format VIEW column's aliases:
'CREATE VIEW v(a, b) AS SELECT ...' -- in this case, space format will
consist from two named fields 'a' and 'b'.

Finally, last patch introduces simple lever to fetch SELECT from
'CREATE VIEW AS SELECT ...' statement and load it into internal struct.
Also, routine which is connected with views have been refactored,
in order to use this facility, instead of relying on struct Table.
Alongside with this change, fix codestyle and added doxygen style comments.

Nikita Pettik (3):
  sql: remove usless #ifdef directives
  sql: add view column aliases to space format
  sql: load SELECT from 'CREATE VIEW ...' string

 src/box/sql.c              |  22 +-
 src/box/sql/CMakeLists.txt |   1 -
 src/box/sql/alter.c        |   2 -
 src/box/sql/attach.c       |   6 -
 src/box/sql/build.c        | 231 ++++++++++--------
 src/box/sql/complete.c     | 333 --------------------------
 src/box/sql/delete.c       |  20 +-
 src/box/sql/expr.c         |   5 +-
 src/box/sql/fkey.c         |   8 -
 src/box/sql/insert.c       |  17 +-
 src/box/sql/parse.c        | 570 +++++++++++++++++++++++----------------------
 src/box/sql/parse.y        |  13 +-
 src/box/sql/pragma.c       |  10 +-
 src/box/sql/pragma.h       |   8 -
 src/box/sql/resolve.c      |   3 -
 src/box/sql/select.c       | 180 +++++++-------
 src/box/sql/sqliteInt.h    |  56 ++---
 src/box/sql/tarantoolInt.h |   2 +-
 src/box/sql/tokenize.c     |  30 ++-
 src/box/sql/treeview.c     |   2 -
 src/box/sql/trigger.c      |   3 -
 src/box/sql/update.c       |  17 +-
 src/box/sql/vdbe.c         |   5 -
 src/box/sql/vdbe.h         |   2 -
 src/box/sql/vdbeInt.h      |   4 -
 src/box/sql/vdbeaux.c      |   4 -
 test/sql-tap/view.test.lua |  26 ++-
 27 files changed, 593 insertions(+), 987 deletions(-)
 delete mode 100644 src/box/sql/complete.c

-- 
2.15.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives
  2018-04-03 14:54 [tarantool-patches] [PATCH 0/3] Rework VIEW processing Nikita Pettik
@ 2018-04-03 14:54 ` Nikita Pettik
  2018-04-03 17:23   ` [tarantool-patches] " Vladislav Shpilevoy
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 2/3] sql: add view column aliases to space format Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 3/3] sql: load SELECT from 'CREATE VIEW ...' string Nikita Pettik
  2 siblings, 1 reply; 5+ messages in thread
From: Nikita Pettik @ 2018-04-03 14:54 UTC (permalink / raw)
  To: tarantool-patches; +Cc: v.shpilevoy, Nikita Pettik

Since in our SQL implemetation triggers, foreign keys and views are
always available, there is no need in #ifdef directives which
turn them off.
Removed: SQLITE_OMIT_VIEW, SQLITE_OMIT_TRIGGER, SQLITE_OMIT_FOREIGN_KEY
defines. Also, removed obsolete compelete.c source file.
---
 src/box/sql/CMakeLists.txt |   1 -
 src/box/sql/alter.c        |   2 -
 src/box/sql/attach.c       |   6 -
 src/box/sql/build.c        |  20 ---
 src/box/sql/complete.c     | 333 ---------------------------------------------
 src/box/sql/delete.c       |  18 ---
 src/box/sql/expr.c         |   5 +-
 src/box/sql/fkey.c         |   8 --
 src/box/sql/insert.c       |  15 --
 src/box/sql/parse.c        | 320 +++++++++++++++++++++----------------------
 src/box/sql/parse.y        |   7 -
 src/box/sql/pragma.c       |   8 --
 src/box/sql/pragma.h       |   8 --
 src/box/sql/resolve.c      |   3 -
 src/box/sql/select.c       |  20 ++-
 src/box/sql/sqliteInt.h    |  39 ------
 src/box/sql/treeview.c     |   2 -
 src/box/sql/trigger.c      |   3 -
 src/box/sql/update.c       |  15 --
 src/box/sql/vdbe.c         |   5 -
 src/box/sql/vdbe.h         |   2 -
 src/box/sql/vdbeInt.h      |   4 -
 src/box/sql/vdbeaux.c      |   4 -
 23 files changed, 169 insertions(+), 679 deletions(-)
 delete mode 100644 src/box/sql/complete.c

diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt
index 678eb4cc4..65143f431 100644
--- a/src/box/sql/CMakeLists.txt
+++ b/src/box/sql/CMakeLists.txt
@@ -35,7 +35,6 @@ add_library(sql STATIC
         cursor.c
     build.c
     callback.c
-    complete.c
     date.c
     delete.c
     expr.c
diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c
index 054c0856c..87de03217 100644
--- a/src/box/sql/alter.c
+++ b/src/box/sql/alter.c
@@ -106,13 +106,11 @@ sqlite3AlterRenameTable(Parse * pParse,	/* Parser context. */
 		goto exit_rename_table;
 	}
 
-#ifndef SQLITE_OMIT_VIEW
 	if (space_is_view(pTab)) {
 		sqlite3ErrorMsg(pParse, "view %s may not be altered",
 				pTab->zName);
 		goto exit_rename_table;
 	}
-#endif
 
 	/* Begin a transaction for database.
 	 * Then modify the schema cookie (since the ALTER TABLE modifies the
diff --git a/src/box/sql/attach.c b/src/box/sql/attach.c
index 0a68b76ca..59492351c 100644
--- a/src/box/sql/attach.c
+++ b/src/box/sql/attach.c
@@ -83,17 +83,14 @@ sqlite3FixSrcList(DbFixer * pFix,	/* Context of the fixation */
 		if (pFix->bVarOnly == 0) {
 			pItem->pSchema = pFix->pSchema;
 		}
-#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
 		if (sqlite3FixSelect(pFix, pItem->pSelect))
 			return 1;
 		if (sqlite3FixExpr(pFix, pItem->pOn))
 			return 1;
-#endif
 	}
 	return 0;
 }
 
-#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
 int
 sqlite3FixSelect(DbFixer * pFix,	/* Context of the fixation */
 		 Select * pSelect	/* The SELECT statement to be fixed to one database */
@@ -178,9 +175,7 @@ sqlite3FixExprList(DbFixer * pFix,	/* Context of the fixation */
 	}
 	return 0;
 }
-#endif
 
-#ifndef SQLITE_OMIT_TRIGGER
 int
 sqlite3FixTriggerStep(DbFixer * pFix,	/* Context of the fixation */
 		      TriggerStep * pStep	/* The trigger step be fixed to one database */
@@ -200,4 +195,3 @@ sqlite3FixTriggerStep(DbFixer * pFix,	/* Context of the fixation */
 	}
 	return 0;
 }
-#endif
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 5e3ed0f39..75b26a93a 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -1912,11 +1912,9 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 		if (p->pSelect == 0) {
 			/* A regular table */
 			zType = "TABLE";
-#ifndef SQLITE_OMIT_VIEW
 		} else {
 			/* A view */
 			zType = "VIEW";
-#endif
 		}
 
 		/* If this is a CREATE TABLE xx AS SELECT ..., execute the SELECT
@@ -2011,7 +2009,6 @@ sqlite3EndTable(Parse * pParse,	/* Parse context */
 	}
 }
 
-#ifndef SQLITE_OMIT_VIEW
 /*
  * The parser calls this routine in order to create a new VIEW
  */
@@ -2080,9 +2077,7 @@ sqlite3CreateView(Parse * pParse,	/* The parsing context */
 	sqlite3ExprListDelete(db, pCNames);
 	return;
 }
-#endif				/* SQLITE_OMIT_VIEW */
 
-#if !defined(SQLITE_OMIT_VIEW)
 /*
  * The Table structure pTable is really a VIEW.  Fill in the names of
  * the columns of the view in the pTable structure.  Return the number
@@ -2099,7 +2094,6 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 
 	assert(pTable);
 
-#ifndef SQLITE_OMIT_VIEW
 	/* A positive nCol means the columns names for this view are
 	 * already known.
 	 */
@@ -2179,12 +2173,9 @@ sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
 	} else {
 		nErr++;
 	}
-#endif				/* SQLITE_OMIT_VIEW */
 	return nErr;
 }
-#endif				/* !defined(SQLITE_OMIT_VIEW) */
 
-#ifndef SQLITE_OMIT_VIEW
 /*
  * Clear the column names from every VIEW in database idx.
  */
@@ -2202,9 +2193,6 @@ sqliteViewResetAll(sqlite3 * db)
 		}
 	}
 }
-#else
-#define sqliteViewResetAll(A,B)
-#endif				/* SQLITE_OMIT_VIEW */
 
 /*
  * Remove entries from the sqlite_statN tables (for N in (1,2,3))
@@ -2385,7 +2373,6 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr)
 			sqlite3CodeVerifySchema(pParse);
 		goto exit_drop_table;
 	}
-#ifndef SQLITE_OMIT_VIEW
 	/* Ensure DROP TABLE is not used on a view, and DROP VIEW is not used
 	 * on a table.
 	 */
@@ -2399,7 +2386,6 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr)
 				pTab->zName);
 		goto exit_drop_table;
 	}
-#endif
 
 	/* Generate code to remove the table from Tarantool and internal SQL
 	 * tables. Basically, it consists from 3 stages:
@@ -2448,7 +2434,6 @@ sqlite3CreateForeignKey(Parse * pParse,	/* Parsing context */
     )
 {
 	sqlite3 *db = pParse->db;
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 	FKey *pFKey = 0;
 	FKey *pNextTo;
 	Table *p = pParse->pNewTable;
@@ -2552,7 +2537,6 @@ sqlite3CreateForeignKey(Parse * pParse,	/* Parsing context */
 
  fk_end:
 	sqlite3DbFree(db, pFKey);
-#endif				/* !defined(SQLITE_OMIT_FOREIGN_KEY) */
 	sqlite3ExprListDelete(db, pFromCol);
 	sqlite3ExprListDelete(db, pToCol);
 }
@@ -2567,14 +2551,12 @@ sqlite3CreateForeignKey(Parse * pParse,	/* Parsing context */
 void
 sqlite3DeferForeignKey(Parse * pParse, int isDeferred)
 {
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 	Table *pTab;
 	FKey *pFKey;
 	if ((pTab = pParse->pNewTable) == 0 || (pFKey = pTab->pFKey) == 0)
 		return;
 	assert(isDeferred == 0 || isDeferred == 1);	/* EV: R-30323-21917 */
 	pFKey->isDeferred = (u8) isDeferred;
-#endif
 }
 
 /*
@@ -2896,12 +2878,10 @@ sqlite3CreateIndex(Parse * pParse,	/* All information about this parse */
 
 	assert(pTab != 0);
 	assert(pParse->nErr == 0);
-#ifndef SQLITE_OMIT_VIEW
 	if (pTab->pSelect) {
 		sqlite3ErrorMsg(pParse, "views may not be indexed");
 		goto exit_create_index;
 	}
-#endif
 	/*
 	 * Find the name of the index.  Make sure there is not already another
 	 * index or table with the same name.
diff --git a/src/box/sql/complete.c b/src/box/sql/complete.c
deleted file mode 100644
index bdd17e1da..000000000
--- a/src/box/sql/complete.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * 1. Redistributions of source code must retain the above
- *    copyright notice, this list of conditions and the
- *    following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
- * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
- * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
- * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*
- * An tokenizer for SQL
- *
- * This file contains C code that implements the sqlite3_complete() API.
- * This code used to be part of the tokenizer.c source file.  But by
- * separating it out, the code will be automatically omitted from
- * static links that do not use it.
- */
-#include "sqliteInt.h"
-#ifndef SQLITE_OMIT_COMPLETE
-
-/*
- * This is defined in tokenize.c.  We just have to import the definition.
- */
-#ifndef SQLITE_AMALGAMATION
-#ifdef SQLITE_ASCII
-#define IdChar(C)  ((sqlite3CtypeMap[(unsigned char)C]&0x46)!=0)
-#endif
-#ifdef SQLITE_EBCDIC
-extern const char sqlite3IsEbcdicIdChar[];
-#define IdChar(C)  (((c=C)>=0x42 && sqlite3IsEbcdicIdChar[c-0x40]))
-#endif
-#endif				/* SQLITE_AMALGAMATION */
-
-/*
- * Token types used by the sqlite3_complete() routine.  See the header
- * comments on that procedure for additional information.
- */
-#define tkSEMI    0
-#define tkWS      1
-#define tkOTHER   2
-#ifndef SQLITE_OMIT_TRIGGER
-#define tkEXPLAIN 3
-#define tkCREATE  4
-#define tkTEMP    5
-#define tkTRIGGER 6
-#define tkEND     7
-#endif
-
-/*
- * Return TRUE if the given SQL string ends in a semicolon.
- *
- * Special handling is require for CREATE TRIGGER statements.
- * Whenever the CREATE TRIGGER keywords are seen, the statement
- * must end with ";END;".
- *
- * This implementation uses a state machine with 8 states:
- *
- *   (0) INVALID   We have not yet seen a non-whitespace character.
- *
- *   (1) START     At the beginning or end of an SQL statement.  This routine
- *                 returns 1 if it ends in the START state and 0 if it ends
- *                 in any other state.
- *
- *   (2) NORMAL    We are in the middle of statement which ends with a single
- *                 semicolon.
- *
- *   (3) EXPLAIN   The keyword EXPLAIN has been seen at the beginning of
- *                 a statement.
- *
- *   (4) CREATE    The keyword CREATE has been seen at the beginning of a
- *                 statement, possibly preceded by EXPLAIN and/or followed by
- *                 TEMP or TEMPORARY
- *
- *   (5) TRIGGER   We are in the middle of a trigger definition that must be
- *                 ended by a semicolon, the keyword END, and another semicolon.
- *
- *   (6) SEMI      We've seen the first semicolon in the ";END;" that occurs at
- *                 the end of a trigger definition.
- *
- *   (7) END       We've seen the ";END" of the ";END;" that occurs at the end
- *                 of a trigger definition.
- *
- * Transitions between states above are determined by tokens extracted
- * from the input.  The following tokens are significant:
- *
- *   (0) tkSEMI      A semicolon.
- *   (1) tkWS        Whitespace.
- *   (2) tkOTHER     Any other SQL token.
- *   (3) tkEXPLAIN   The "explain" keyword.
- *   (4) tkCREATE    The "create" keyword.
- *   (5) tkTEMP      The "temp" or "temporary" keyword.
- *   (6) tkTRIGGER   The "trigger" keyword.
- *   (7) tkEND       The "end" keyword.
- *
- * Whitespace never causes a state transition and is always ignored.
- * This means that a SQL string of all whitespace is invalid.
- *
- * If we compile with SQLITE_OMIT_TRIGGER, all of the computation needed
- * to recognize the end of a trigger can be omitted.  All we have to do
- * is look for a semicolon that is not part of an string or comment.
- */
-int
-sqlite3_complete(const char *zSql)
-{
-	u8 state = 0;		/* Current state, using numbers defined in header comment */
-	u8 token;		/* Value of the next token */
-
-#ifndef SQLITE_OMIT_TRIGGER
-	/* A complex statement machine used to detect the end of a CREATE TRIGGER
-	 * statement.  This is the normal case.
-	 */
-	static const u8 trans[8][8] = {
-		/* Token:                                                */
-		/* State:       *  SEMI  WS  OTHER  EXPLAIN  CREATE  TEMP  TRIGGER  END */
-		/* 0 INVALID: */ {1, 0, 2, 3, 4, 2, 2, 2,},
-		/* 1   START: */ {1, 1, 2, 3, 4, 2, 2, 2,},
-		/* 2  NORMAL: */ {1, 2, 2, 2, 2, 2, 2, 2,},
-		/* 3 EXPLAIN: */ {1, 3, 3, 2, 4, 2, 2, 2,},
-		/* 4  CREATE: */ {1, 4, 2, 2, 2, 4, 5, 2,},
-		/* 5 TRIGGER: */ {6, 5, 5, 5, 5, 5, 5, 5,},
-		/* 6    SEMI: */ {6, 6, 5, 5, 5, 5, 5, 7,},
-		/* 7     END: */ {1, 7, 5, 5, 5, 5, 5, 5,},
-	};
-#else
-	/* If triggers are not supported by this compile then the statement machine
-	 * used to detect the end of a statement is much simpler
-	 */
-	static const u8 trans[3][3] = {
-		/* Token:           */
-		/* State:       *  SEMI  WS  OTHER */
-		/* 0 INVALID: */ {1, 0, 2,},
-		/* 1   START: */ {1, 1, 2,},
-		/* 2  NORMAL: */ {1, 2, 2,},
-	};
-#endif				/* SQLITE_OMIT_TRIGGER */
-
-#ifdef SQLITE_ENABLE_API_ARMOR
-	if (zSql == 0) {
-		(void)SQLITE_MISUSE_BKPT;
-		return 0;
-	}
-#endif
-
-	while (*zSql) {
-		switch (*zSql) {
-		case ';':{	/* A semicolon */
-				token = tkSEMI;
-				break;
-			}
-		case ' ':
-		case '\r':
-		case '\t':
-		case '\n':
-		case '\f':{	/* White space is ignored */
-				token = tkWS;
-				break;
-			}
-		case '/':{	/* C-style comments */
-				if (zSql[1] != '*') {
-					token = tkOTHER;
-					break;
-				}
-				zSql += 2;
-				while (zSql[0]
-				       && (zSql[0] != '*' || zSql[1] != '/')) {
-					zSql++;
-				}
-				if (zSql[0] == 0)
-					return 0;
-				zSql++;
-				token = tkWS;
-				break;
-			}
-		case '-':{	/* SQL-style comments from "--" to end of line */
-				if (zSql[1] != '-') {
-					token = tkOTHER;
-					break;
-				}
-				while (*zSql && *zSql != '\n') {
-					zSql++;
-				}
-				if (*zSql == 0)
-					return state == 1;
-				token = tkWS;
-				break;
-			}
-		case '[':{	/* Microsoft-style identifiers in [...] */
-				zSql++;
-				while (*zSql && *zSql != ']') {
-					zSql++;
-				}
-				if (*zSql == 0)
-					return 0;
-				token = tkOTHER;
-				break;
-			}
-		case '`':	/* Grave-accent quoted symbols used by MySQL */
-		case '"':	/* single- and double-quoted strings */
-		case '\'':{
-				int c = *zSql;
-				zSql++;
-				while (*zSql && *zSql != c) {
-					zSql++;
-				}
-				if (*zSql == 0)
-					return 0;
-				token = tkOTHER;
-				break;
-			}
-		default:{
-#ifdef SQLITE_EBCDIC
-				unsigned char c;
-#endif
-				if (IdChar((u8) * zSql)) {
-					/* Keywords and unquoted identifiers */
-					int nId;
-					for (nId = 1; IdChar(zSql[nId]); nId++) {
-					}
-#ifdef SQLITE_OMIT_TRIGGER
-					token = tkOTHER;
-#else
-					switch (*zSql) {
-					case 'c':
-					case 'C':{
-							if (nId == 6
-							    &&
-							    sqlite3StrNICmp
-							    (zSql, "create",
-							     6) == 0) {
-								token =
-								    tkCREATE;
-							} else {
-								token = tkOTHER;
-							}
-							break;
-						}
-					case 't':
-					case 'T':{
-							if (nId == 7
-							    &&
-							    sqlite3StrNICmp
-							    (zSql, "trigger",
-							     7) == 0) {
-								token =
-								    tkTRIGGER;
-							} else if (nId == 4
-								   &&
-								   sqlite3StrNICmp
-								   (zSql,
-								    "temp",
-								    4) == 0) {
-								token = tkTEMP;
-							} else if (nId == 9
-								   &&
-								   sqlite3StrNICmp
-								   (zSql,
-								    "temporary",
-								    9) == 0) {
-								token = tkTEMP;
-							} else {
-								token = tkOTHER;
-							}
-							break;
-						}
-					case 'e':
-					case 'E':{
-							if (nId == 3
-							    &&
-							    sqlite3StrNICmp
-							    (zSql, "end",
-							     3) == 0) {
-								token = tkEND;
-							} else
-#ifndef SQLITE_OMIT_EXPLAIN
-							if (nId == 7
-								    &&
-								    sqlite3StrNICmp
-								    (zSql,
-									     "explain",
-									     7)
-								    == 0) {
-								token =
-								    tkEXPLAIN;
-							} else
-#endif
-							{
-								token = tkOTHER;
-							}
-							break;
-						}
-					default:{
-							token = tkOTHER;
-							break;
-						}
-					}
-#endif				/* SQLITE_OMIT_TRIGGER */
-					zSql += nId - 1;
-				} else {
-					/* Operators and special symbols */
-					token = tkOTHER;
-				}
-				break;
-			}
-		}
-		state = trans[state][token];
-		zSql++;
-	}
-	return state == 1;
-}
-
-#endif				/* SQLITE_OMIT_COMPLETE */
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index 7d1d71577..a588082e1 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -87,17 +87,14 @@ sqlite3IsReadOnly(Parse * pParse, Table * pTab, int viewOk)
 				pTab->zName);
 		return 1;
 	}
-#ifndef SQLITE_OMIT_VIEW
 	if (!viewOk && space_is_view(pTab)) {
 		sqlite3ErrorMsg(pParse, "cannot modify %s because it is a view",
 				pTab->zName);
 		return 1;
 	}
-#endif
 	return 0;
 }
 
-#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
 /*
  * Evaluate a view and store its result in an ephemeral table.  The
  * pWhere argument is an optional WHERE clause that restricts the
@@ -128,7 +125,6 @@ sqlite3MaterializeView(Parse * pParse,	/* Parsing context */
 	sqlite3Select(pParse, pSel, &dest);
 	sqlite3SelectDelete(db, pSel);
 }
-#endif				/* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
 
 #if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
 /*
@@ -261,11 +257,8 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 				 * subqueries in the WHERE clause
 				 */
 	struct session *user_session = current_session();
-
-#ifndef SQLITE_OMIT_TRIGGER
 	int isView;		/* True if attempting to delete from a view */
 	Trigger *pTrigger;	/* List of table triggers, if required */
-#endif
 
 	db = pParse->db;
 	if (pParse->nErr || db->mallocFailed) {
@@ -285,18 +278,9 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 	/* Figure out if we have any triggers and if the table being
 	 * deleted from is a view
 	 */
-#ifndef SQLITE_OMIT_TRIGGER
 	pTrigger = sqlite3TriggersExist(pTab, TK_DELETE, 0, 0);
 	isView = pTab->pSelect != 0;
 	bComplex = pTrigger || sqlite3FkRequired(pTab, 0);
-#else
-#define pTrigger 0
-#define isView 0
-#endif
-#ifdef SQLITE_OMIT_VIEW
-#undef isView
-#define isView 0
-#endif
 
 	/* If pTab is really a view, make sure it has been initialized.
 	 */
@@ -330,12 +314,10 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 	/* If we are trying to delete from a view, realize that view into
 	 * an ephemeral table.
 	 */
-#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
 	if (isView) {
 		sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
 		iDataCur = iIdxCur = iTabCur;
 	}
-#endif
 
 	/* Resolve the column names in the WHERE clause.
 	 */
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index f4e3cf735..12d5cabce 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -1537,8 +1537,7 @@ sqlite3ExprListDup(sqlite3 * db, ExprList * p, int flags)
  * sqlite3SelectDup(), can be called. sqlite3SelectDup() is sometimes
  * called with a NULL argument.
  */
-#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) \
- || !defined(SQLITE_OMIT_SUBQUERY)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 SrcList *
 sqlite3SrcListDup(sqlite3 * db, SrcList * p, int flags)
 {
@@ -4429,7 +4428,6 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 			sqlite3VdbeResolveLabel(v, endLabel);
 			break;
 		}
-#ifndef SQLITE_OMIT_TRIGGER
 	case TK_RAISE:{
 			assert(pExpr->affinity == ON_CONFLICT_ACTION_ROLLBACK
 			       || pExpr->affinity == ON_CONFLICT_ACTION_ABORT
@@ -4459,7 +4457,6 @@ sqlite3ExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
 
 			break;
 		}
-#endif
 	}
 	sqlite3ReleaseTempReg(pParse, regFree1);
 	sqlite3ReleaseTempReg(pParse, regFree2);
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index f4a6b2707..686888320 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -37,9 +37,6 @@
 #include "sqliteInt.h"
 #include "box/session.h"
 
-#ifndef SQLITE_OMIT_FOREIGN_KEY
-#ifndef SQLITE_OMIT_TRIGGER
-
 /*
  * Deferred and Immediate FKs
  * --------------------------
@@ -1495,8 +1492,6 @@ sqlite3FkActions(Parse * pParse,	/* Parse context */
 	}
 }
 
-#endif				/* ifndef SQLITE_OMIT_TRIGGER */
-
 /*
  * Free all memory associated with foreign key definitions attached to
  * table pTab. Remove the deleted foreign keys from the Schema.fkeyHash
@@ -1531,13 +1526,10 @@ sqlite3FkDelete(sqlite3 * db, Table * pTab)
 		assert(pFKey->isDeferred == 0 || pFKey->isDeferred == 1);
 
 		/* Delete any triggers created to implement actions for this FK. */
-#ifndef SQLITE_OMIT_TRIGGER
 		fkTriggerDelete(db, pFKey->apTrigger[0]);
 		fkTriggerDelete(db, pFKey->apTrigger[1]);
-#endif
 
 		pNext = pFKey->pNextFrom;
 		sqlite3DbFree(db, pFKey);
 	}
 }
-#endif				/* ifndef SQLITE_OMIT_FOREIGN_KEY */
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 4a57b23f5..5e67c2b73 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -347,12 +347,9 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	int regData;		/* register holding first column to insert */
 	int *aRegIdx = 0;	/* One register allocated to each index */
 	uint32_t space_id = 0;
-
-#ifndef SQLITE_OMIT_TRIGGER
 	int isView;		/* True if attempting to insert into a view */
 	Trigger *pTrigger;	/* List of triggers on pTab, if required */
 	int tmask;		/* Mask of trigger times */
-#endif
 
 	db = pParse->db;
 	memset(&dest, 0, sizeof(dest));
@@ -388,18 +385,8 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	/* Figure out if we have any triggers and if the table being
 	 * inserted into is a view
 	 */
-#ifndef SQLITE_OMIT_TRIGGER
 	pTrigger = sqlite3TriggersExist(pTab, TK_INSERT, 0, &tmask);
 	isView = space_is_view(pTab);
-#else
-#define pTrigger 0
-#define tmask 0
-#define isView 0
-#endif
-#ifdef SQLITE_OMIT_VIEW
-#undef isView
-#define isView 0
-#endif
 	assert((pTrigger && tmask) || (pTrigger == 0 && tmask == 0));
 
 	/* If pTab is really a view, make sure it has been initialized.
@@ -1896,7 +1883,6 @@ xferOptimization(Parse * pParse,	/* Parser context */
 		return 0;	/* Tables have different CHECK constraints.  Ticket #2252 */
 	}
 #endif
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 	/* Disallow the transfer optimization if the destination table constains
 	 * any foreign key constraints.  This is more restrictive than necessary.
 	 * So the extra complication to make this rule less restrictive is probably
@@ -1906,7 +1892,6 @@ xferOptimization(Parse * pParse,	/* Parser context */
 	    && pDest->pFKey != 0) {
 		return 0;
 	}
-#endif
 	if ((user_session->sql_flags & SQLITE_CountRows) != 0) {
 		return 0;	/* xfer opt does not play well with PRAGMA count_changes */
 	}
diff --git a/src/box/sql/parse.c b/src/box/sql/parse.c
index 9f547d25e..72a2cf0bd 100644
--- a/src/box/sql/parse.c
+++ b/src/box/sql/parse.c
@@ -81,7 +81,7 @@ static void disableLookaside(Parse *pParse){
   pParse->db->lookaside.bDisable++;
 }
 
-#line 398 "parse.y"
+#line 396 "parse.y"
 
   /*
   ** For a compound SELECT statement, make sure p->pPrior->pNext==p for
@@ -104,7 +104,7 @@ static void disableLookaside(Parse *pParse){
       }
     }
   }
-#line 837 "parse.y"
+#line 835 "parse.y"
 
   /* This is a utility routine used to set the ExprSpan.zStart and
   ** ExprSpan.zEnd values of pOut so that the span covers the complete
@@ -140,7 +140,7 @@ static void disableLookaside(Parse *pParse){
     pOut->zStart = t.z;
     pOut->zEnd = &t.z[t.n];
   }
-#line 945 "parse.y"
+#line 943 "parse.y"
 
   /* This routine constructs a binary expression node out of two ExprSpan
   ** objects and uses the result to populate a new ExprSpan object.
@@ -163,7 +163,7 @@ static void disableLookaside(Parse *pParse){
       pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0);
     }
   }
-#line 1019 "parse.y"
+#line 1017 "parse.y"
 
   /* Construct an expression node for a unary postfix operator
   */
@@ -176,7 +176,7 @@ static void disableLookaside(Parse *pParse){
     pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
     pOperand->zEnd = &pPostOp->z[pPostOp->n];
   }                           
-#line 1036 "parse.y"
+#line 1034 "parse.y"
 
   /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
   ** unary TK_ISNULL or TK_NOTNULL expression. */
@@ -188,7 +188,7 @@ static void disableLookaside(Parse *pParse){
       pA->pRight = 0;
     }
   }
-#line 1064 "parse.y"
+#line 1062 "parse.y"
 
   /* Construct an expression node for a unary prefix operator
   */
@@ -203,7 +203,7 @@ static void disableLookaside(Parse *pParse){
     pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
     pOut->zEnd = pOperand->zEnd;
   }
-#line 1269 "parse.y"
+#line 1267 "parse.y"
 
   /* Add a single new term to an ExprList that is used to store a
   ** list of identifiers.  Report an error if the ID list contains
@@ -1468,7 +1468,7 @@ static void yy_destructor(
     case 183: /* oneselect */
     case 194: /* values */
 {
-#line 392 "parse.y"
+#line 390 "parse.y"
 sqlite3SelectDelete(pParse->db, (yypminor->yy279));
 #line 1474 "parse.c"
 }
@@ -1476,7 +1476,7 @@ sqlite3SelectDelete(pParse->db, (yypminor->yy279));
     case 160: /* term */
     case 161: /* expr */
 {
-#line 835 "parse.y"
+#line 833 "parse.y"
 sql_expr_free(pParse->db, (yypminor->yy162).pExpr, false);
 #line 1482 "parse.c"
 }
@@ -1494,7 +1494,7 @@ sql_expr_free(pParse->db, (yypminor->yy162).pExpr, false);
     case 213: /* paren_exprlist */
     case 215: /* case_exprlist */
 {
-#line 1267 "parse.y"
+#line 1265 "parse.y"
 sqlite3ExprListDelete(pParse->db, (yypminor->yy382));
 #line 1500 "parse.c"
 }
@@ -1504,7 +1504,7 @@ sqlite3ExprListDelete(pParse->db, (yypminor->yy382));
     case 199: /* seltablist */
     case 200: /* stl_prefix */
 {
-#line 619 "parse.y"
+#line 617 "parse.y"
 sqlite3SrcListDelete(pParse->db, (yypminor->yy387));
 #line 1510 "parse.c"
 }
@@ -1512,7 +1512,7 @@ sqlite3SrcListDelete(pParse->db, (yypminor->yy387));
     case 184: /* with */
     case 229: /* wqlist */
 {
-#line 1517 "parse.y"
+#line 1510 "parse.y"
 sqlite3WithDelete(pParse->db, (yypminor->yy151));
 #line 1518 "parse.c"
 }
@@ -1524,7 +1524,7 @@ sqlite3WithDelete(pParse->db, (yypminor->yy151));
     case 216: /* case_else */
     case 225: /* when_clause */
 {
-#line 744 "parse.y"
+#line 742 "parse.y"
 sql_expr_free(pParse->db, (yypminor->yy362), false);
 #line 1530 "parse.c"
 }
@@ -1533,7 +1533,7 @@ sql_expr_free(pParse->db, (yypminor->yy362), false);
     case 206: /* idlist */
     case 209: /* idlist_opt */
 {
-#line 656 "parse.y"
+#line 654 "parse.y"
 sqlite3IdListDelete(pParse->db, (yypminor->yy40));
 #line 1539 "parse.c"
 }
@@ -1541,14 +1541,14 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy40));
     case 221: /* trigger_cmd_list */
     case 226: /* trigger_cmd */
 {
-#line 1391 "parse.y"
+#line 1387 "parse.y"
 sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
 #line 1547 "parse.c"
 }
       break;
     case 223: /* trigger_event */
 {
-#line 1377 "parse.y"
+#line 1373 "parse.y"
 sqlite3IdListDelete(pParse->db, (yypminor->yy10).b);
 #line 1554 "parse.c"
 }
@@ -2535,21 +2535,21 @@ static void yy_reduce(
 #line 2536 "parse.c"
         break;
       case 73: /* cmd ::= createkw VIEW ifnotexists nm eidlist_opt AS select */
-#line 372 "parse.y"
+#line 371 "parse.y"
 {
   sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy382, yymsp[0].minor.yy279, yymsp[-4].minor.yy52);
 }
 #line 2543 "parse.c"
         break;
       case 74: /* cmd ::= DROP VIEW ifexists fullname */
-#line 375 "parse.y"
+#line 374 "parse.y"
 {
   sqlite3DropTable(pParse, yymsp[0].minor.yy387, 1, yymsp[-1].minor.yy52);
 }
 #line 2550 "parse.c"
         break;
       case 75: /* cmd ::= select */
-#line 382 "parse.y"
+#line 380 "parse.y"
 {
   SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
   if(!pParse->parse_only)
@@ -2561,7 +2561,7 @@ static void yy_reduce(
 #line 2562 "parse.c"
         break;
       case 76: /* select ::= with selectnowith */
-#line 422 "parse.y"
+#line 420 "parse.y"
 {
   Select *p = yymsp[0].minor.yy279;
   if( p ){
@@ -2575,7 +2575,7 @@ static void yy_reduce(
 #line 2576 "parse.c"
         break;
       case 77: /* selectnowith ::= selectnowith multiselect_op oneselect */
-#line 435 "parse.y"
+#line 433 "parse.y"
 {
   Select *pRhs = yymsp[0].minor.yy279;
   Select *pLhs = yymsp[-2].minor.yy279;
@@ -2602,17 +2602,17 @@ static void yy_reduce(
         break;
       case 78: /* multiselect_op ::= UNION */
       case 80: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==80);
-#line 458 "parse.y"
+#line 456 "parse.y"
 {yymsp[0].minor.yy52 = yymsp[0].major; /*A-overwrites-OP*/}
 #line 2608 "parse.c"
         break;
       case 79: /* multiselect_op ::= UNION ALL */
-#line 459 "parse.y"
+#line 457 "parse.y"
 {yymsp[-1].minor.yy52 = TK_ALL;}
 #line 2613 "parse.c"
         break;
       case 81: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
-#line 463 "parse.y"
+#line 461 "parse.y"
 {
 #ifdef SELECTTRACE_ENABLED
   Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
@@ -2646,14 +2646,14 @@ static void yy_reduce(
 #line 2647 "parse.c"
         break;
       case 82: /* values ::= VALUES LP nexprlist RP */
-#line 497 "parse.y"
+#line 495 "parse.y"
 {
   yymsp[-3].minor.yy279 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy382,0,0,0,0,0,SF_Values,0,0);
 }
 #line 2654 "parse.c"
         break;
       case 83: /* values ::= values COMMA LP exprlist RP */
-#line 500 "parse.y"
+#line 498 "parse.y"
 {
   Select *pRight, *pLeft = yymsp[-4].minor.yy279;
   pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy382,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
@@ -2669,12 +2669,12 @@ static void yy_reduce(
 #line 2670 "parse.c"
         break;
       case 84: /* distinct ::= DISTINCT */
-#line 517 "parse.y"
+#line 515 "parse.y"
 {yymsp[0].minor.yy52 = SF_Distinct;}
 #line 2675 "parse.c"
         break;
       case 85: /* distinct ::= ALL */
-#line 518 "parse.y"
+#line 516 "parse.y"
 {yymsp[0].minor.yy52 = SF_All;}
 #line 2680 "parse.c"
         break;
@@ -2684,12 +2684,12 @@ static void yy_reduce(
       case 196: /* exprlist ::= */ yytestcase(yyruleno==196);
       case 199: /* paren_exprlist ::= */ yytestcase(yyruleno==199);
       case 204: /* eidlist_opt ::= */ yytestcase(yyruleno==204);
-#line 531 "parse.y"
+#line 529 "parse.y"
 {yymsp[1].minor.yy382 = 0;}
 #line 2690 "parse.c"
         break;
       case 88: /* selcollist ::= sclp expr as */
-#line 532 "parse.y"
+#line 530 "parse.y"
 {
    yymsp[-2].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy382, yymsp[-1].minor.yy162.pExpr);
    if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy382, &yymsp[0].minor.yy0, 1);
@@ -2698,7 +2698,7 @@ static void yy_reduce(
 #line 2699 "parse.c"
         break;
       case 89: /* selcollist ::= sclp STAR */
-#line 537 "parse.y"
+#line 535 "parse.y"
 {
   Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
   yymsp[-1].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy382, p);
@@ -2706,7 +2706,7 @@ static void yy_reduce(
 #line 2707 "parse.c"
         break;
       case 90: /* selcollist ::= sclp nm DOT STAR */
-#line 541 "parse.y"
+#line 539 "parse.y"
 {
   Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
   Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
@@ -2718,17 +2718,17 @@ static void yy_reduce(
       case 91: /* as ::= AS nm */
       case 218: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==218);
       case 219: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==219);
-#line 552 "parse.y"
+#line 550 "parse.y"
 {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
 #line 2724 "parse.c"
         break;
       case 93: /* from ::= */
-#line 566 "parse.y"
+#line 564 "parse.y"
 {yymsp[1].minor.yy387 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy387));}
 #line 2729 "parse.c"
         break;
       case 94: /* from ::= FROM seltablist */
-#line 567 "parse.y"
+#line 565 "parse.y"
 {
   yymsp[-1].minor.yy387 = yymsp[0].minor.yy387;
   sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy387);
@@ -2736,19 +2736,19 @@ static void yy_reduce(
 #line 2737 "parse.c"
         break;
       case 95: /* stl_prefix ::= seltablist joinop */
-#line 575 "parse.y"
+#line 573 "parse.y"
 {
    if( ALWAYS(yymsp[-1].minor.yy387 && yymsp[-1].minor.yy387->nSrc>0) ) yymsp[-1].minor.yy387->a[yymsp[-1].minor.yy387->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy52;
 }
 #line 2744 "parse.c"
         break;
       case 96: /* stl_prefix ::= */
-#line 578 "parse.y"
+#line 576 "parse.y"
 {yymsp[1].minor.yy387 = 0;}
 #line 2749 "parse.c"
         break;
       case 97: /* seltablist ::= stl_prefix nm as indexed_opt on_opt using_opt */
-#line 580 "parse.y"
+#line 578 "parse.y"
 {
   yymsp[-5].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy387,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy387, &yymsp[-2].minor.yy0);
@@ -2756,7 +2756,7 @@ static void yy_reduce(
 #line 2757 "parse.c"
         break;
       case 98: /* seltablist ::= stl_prefix nm LP exprlist RP as on_opt using_opt */
-#line 585 "parse.y"
+#line 583 "parse.y"
 {
   yymsp[-7].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy387,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy387, yymsp[-4].minor.yy382);
@@ -2764,14 +2764,14 @@ static void yy_reduce(
 #line 2765 "parse.c"
         break;
       case 99: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
-#line 591 "parse.y"
+#line 589 "parse.y"
 {
     yymsp[-6].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy387,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy279,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   }
 #line 2772 "parse.c"
         break;
       case 100: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
-#line 595 "parse.y"
+#line 593 "parse.y"
 {
     if( yymsp[-6].minor.yy387==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy362==0 && yymsp[0].minor.yy40==0 ){
       yymsp[-6].minor.yy387 = yymsp[-4].minor.yy387;
@@ -2796,27 +2796,27 @@ static void yy_reduce(
 #line 2797 "parse.c"
         break;
       case 101: /* fullname ::= nm */
-#line 621 "parse.y"
+#line 619 "parse.y"
 {yymsp[0].minor.yy387 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
 #line 2802 "parse.c"
         break;
       case 102: /* joinop ::= COMMA|JOIN */
-#line 627 "parse.y"
+#line 625 "parse.y"
 { yymsp[0].minor.yy52 = JT_INNER; }
 #line 2807 "parse.c"
         break;
       case 103: /* joinop ::= JOIN_KW JOIN */
-#line 629 "parse.y"
+#line 627 "parse.y"
 {yymsp[-1].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
 #line 2812 "parse.c"
         break;
       case 104: /* joinop ::= JOIN_KW join_nm JOIN */
-#line 631 "parse.y"
+#line 629 "parse.y"
 {yymsp[-2].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
 #line 2817 "parse.c"
         break;
       case 105: /* joinop ::= JOIN_KW join_nm join_nm JOIN */
-#line 633 "parse.y"
+#line 631 "parse.y"
 {yymsp[-3].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
 #line 2822 "parse.c"
         break;
@@ -2824,7 +2824,7 @@ static void yy_reduce(
       case 123: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==123);
       case 130: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==130);
       case 192: /* case_else ::= ELSE expr */ yytestcase(yyruleno==192);
-#line 637 "parse.y"
+#line 635 "parse.y"
 {yymsp[-1].minor.yy362 = yymsp[0].minor.yy162.pExpr;}
 #line 2830 "parse.c"
         break;
@@ -2833,44 +2833,44 @@ static void yy_reduce(
       case 129: /* where_opt ::= */ yytestcase(yyruleno==129);
       case 193: /* case_else ::= */ yytestcase(yyruleno==193);
       case 195: /* case_operand ::= */ yytestcase(yyruleno==195);
-#line 638 "parse.y"
+#line 636 "parse.y"
 {yymsp[1].minor.yy362 = 0;}
 #line 2839 "parse.c"
         break;
       case 108: /* indexed_opt ::= */
-#line 651 "parse.y"
+#line 649 "parse.y"
 {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
 #line 2844 "parse.c"
         break;
       case 109: /* indexed_opt ::= INDEXED BY nm */
-#line 652 "parse.y"
+#line 650 "parse.y"
 {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
 #line 2849 "parse.c"
         break;
       case 110: /* indexed_opt ::= NOT INDEXED */
-#line 653 "parse.y"
+#line 651 "parse.y"
 {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
 #line 2854 "parse.c"
         break;
       case 111: /* using_opt ::= USING LP idlist RP */
-#line 657 "parse.y"
+#line 655 "parse.y"
 {yymsp[-3].minor.yy40 = yymsp[-1].minor.yy40;}
 #line 2859 "parse.c"
         break;
       case 112: /* using_opt ::= */
       case 140: /* idlist_opt ::= */ yytestcase(yyruleno==140);
-#line 658 "parse.y"
+#line 656 "parse.y"
 {yymsp[1].minor.yy40 = 0;}
 #line 2865 "parse.c"
         break;
       case 114: /* orderby_opt ::= ORDER BY sortlist */
       case 121: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==121);
-#line 672 "parse.y"
+#line 670 "parse.y"
 {yymsp[-2].minor.yy382 = yymsp[0].minor.yy382;}
 #line 2871 "parse.c"
         break;
       case 115: /* sortlist ::= sortlist COMMA expr sortorder */
-#line 673 "parse.y"
+#line 671 "parse.y"
 {
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy382,yymsp[-1].minor.yy162.pExpr);
   sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy382,yymsp[0].minor.yy52);
@@ -2878,7 +2878,7 @@ static void yy_reduce(
 #line 2879 "parse.c"
         break;
       case 116: /* sortlist ::= expr sortorder */
-#line 677 "parse.y"
+#line 675 "parse.y"
 {
   yymsp[-1].minor.yy382 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy162.pExpr); /*A-overwrites-Y*/
   sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy382,yymsp[0].minor.yy52);
@@ -2886,42 +2886,42 @@ static void yy_reduce(
 #line 2887 "parse.c"
         break;
       case 117: /* sortorder ::= ASC */
-#line 684 "parse.y"
+#line 682 "parse.y"
 {yymsp[0].minor.yy52 = SQLITE_SO_ASC;}
 #line 2892 "parse.c"
         break;
       case 118: /* sortorder ::= DESC */
-#line 685 "parse.y"
+#line 683 "parse.y"
 {yymsp[0].minor.yy52 = SQLITE_SO_DESC;}
 #line 2897 "parse.c"
         break;
       case 119: /* sortorder ::= */
-#line 686 "parse.y"
+#line 684 "parse.y"
 {yymsp[1].minor.yy52 = SQLITE_SO_UNDEFINED;}
 #line 2902 "parse.c"
         break;
       case 124: /* limit_opt ::= */
-#line 711 "parse.y"
+#line 709 "parse.y"
 {yymsp[1].minor.yy384.pLimit = 0; yymsp[1].minor.yy384.pOffset = 0;}
 #line 2907 "parse.c"
         break;
       case 125: /* limit_opt ::= LIMIT expr */
-#line 712 "parse.y"
+#line 710 "parse.y"
 {yymsp[-1].minor.yy384.pLimit = yymsp[0].minor.yy162.pExpr; yymsp[-1].minor.yy384.pOffset = 0;}
 #line 2912 "parse.c"
         break;
       case 126: /* limit_opt ::= LIMIT expr OFFSET expr */
-#line 714 "parse.y"
+#line 712 "parse.y"
 {yymsp[-3].minor.yy384.pLimit = yymsp[-2].minor.yy162.pExpr; yymsp[-3].minor.yy384.pOffset = yymsp[0].minor.yy162.pExpr;}
 #line 2917 "parse.c"
         break;
       case 127: /* limit_opt ::= LIMIT expr COMMA expr */
-#line 716 "parse.y"
+#line 714 "parse.y"
 {yymsp[-3].minor.yy384.pOffset = yymsp[-2].minor.yy162.pExpr; yymsp[-3].minor.yy384.pLimit = yymsp[0].minor.yy162.pExpr;}
 #line 2922 "parse.c"
         break;
       case 128: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
-#line 733 "parse.y"
+#line 731 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy151, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy387, &yymsp[-1].minor.yy0);
@@ -2933,7 +2933,7 @@ static void yy_reduce(
 #line 2934 "parse.c"
         break;
       case 131: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
-#line 766 "parse.y"
+#line 764 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-7].minor.yy151, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy387, &yymsp[-3].minor.yy0);
@@ -2946,7 +2946,7 @@ static void yy_reduce(
 #line 2947 "parse.c"
         break;
       case 132: /* setlist ::= setlist COMMA nm EQ expr */
-#line 780 "parse.y"
+#line 778 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy382, yymsp[0].minor.yy162.pExpr);
   sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy382, &yymsp[-2].minor.yy0, 1);
@@ -2954,14 +2954,14 @@ static void yy_reduce(
 #line 2955 "parse.c"
         break;
       case 133: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
-#line 784 "parse.y"
+#line 782 "parse.y"
 {
   yymsp[-6].minor.yy382 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy382, yymsp[-3].minor.yy40, yymsp[0].minor.yy162.pExpr);
 }
 #line 2962 "parse.c"
         break;
       case 134: /* setlist ::= nm EQ expr */
-#line 787 "parse.y"
+#line 785 "parse.y"
 {
   yylhsminor.yy382 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy162.pExpr);
   sqlite3ExprListSetName(pParse, yylhsminor.yy382, &yymsp[-2].minor.yy0, 1);
@@ -2970,14 +2970,14 @@ static void yy_reduce(
   yymsp[-2].minor.yy382 = yylhsminor.yy382;
         break;
       case 135: /* setlist ::= LP idlist RP EQ expr */
-#line 791 "parse.y"
+#line 789 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy40, yymsp[0].minor.yy162.pExpr);
 }
 #line 2978 "parse.c"
         break;
       case 136: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
-#line 797 "parse.y"
+#line 795 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy151, 1);
   sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS;
@@ -2988,7 +2988,7 @@ static void yy_reduce(
 #line 2989 "parse.c"
         break;
       case 137: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
-#line 805 "parse.y"
+#line 803 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-6].minor.yy151, 1);
   sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS;
@@ -2999,40 +2999,40 @@ static void yy_reduce(
 #line 3000 "parse.c"
         break;
       case 141: /* idlist_opt ::= LP idlist RP */
-#line 823 "parse.y"
+#line 821 "parse.y"
 {yymsp[-2].minor.yy40 = yymsp[-1].minor.yy40;}
 #line 3005 "parse.c"
         break;
       case 142: /* idlist ::= idlist COMMA nm */
-#line 825 "parse.y"
+#line 823 "parse.y"
 {yymsp[-2].minor.yy40 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy40,&yymsp[0].minor.yy0);}
 #line 3010 "parse.c"
         break;
       case 143: /* idlist ::= nm */
-#line 827 "parse.y"
+#line 825 "parse.y"
 {yymsp[0].minor.yy40 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
 #line 3015 "parse.c"
         break;
       case 144: /* expr ::= LP expr RP */
-#line 876 "parse.y"
+#line 874 "parse.y"
 {spanSet(&yymsp[-2].minor.yy162,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/  yymsp[-2].minor.yy162.pExpr = yymsp[-1].minor.yy162.pExpr;}
 #line 3020 "parse.c"
         break;
       case 145: /* term ::= NULL */
       case 149: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==149);
       case 150: /* term ::= STRING */ yytestcase(yyruleno==150);
-#line 877 "parse.y"
+#line 875 "parse.y"
 {spanExpr(&yymsp[0].minor.yy162,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/}
 #line 3027 "parse.c"
         break;
       case 146: /* expr ::= ID|INDEXED */
       case 147: /* expr ::= JOIN_KW */ yytestcase(yyruleno==147);
-#line 878 "parse.y"
+#line 876 "parse.y"
 {spanExpr(&yymsp[0].minor.yy162,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
 #line 3033 "parse.c"
         break;
       case 148: /* expr ::= nm DOT nm */
-#line 880 "parse.y"
+#line 878 "parse.y"
 {
   Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
   Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
@@ -3042,7 +3042,7 @@ static void yy_reduce(
 #line 3043 "parse.c"
         break;
       case 151: /* term ::= INTEGER */
-#line 888 "parse.y"
+#line 886 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
   yylhsminor.yy162.zStart = yymsp[0].minor.yy0.z;
@@ -3053,7 +3053,7 @@ static void yy_reduce(
   yymsp[0].minor.yy162 = yylhsminor.yy162;
         break;
       case 152: /* expr ::= VARIABLE */
-#line 894 "parse.y"
+#line 892 "parse.y"
 {
   if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
     u32 n = yymsp[0].minor.yy0.n;
@@ -3078,7 +3078,7 @@ static void yy_reduce(
 #line 3079 "parse.c"
         break;
       case 153: /* expr ::= expr COLLATE ID|INDEXED */
-#line 915 "parse.y"
+#line 913 "parse.y"
 {
   yymsp[-2].minor.yy162.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy162.pExpr, &yymsp[0].minor.yy0, 1);
   yymsp[-2].minor.yy162.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
@@ -3086,7 +3086,7 @@ static void yy_reduce(
 #line 3087 "parse.c"
         break;
       case 154: /* expr ::= CAST LP expr AS typetoken RP */
-#line 920 "parse.y"
+#line 918 "parse.y"
 {
   spanSet(&yymsp[-5].minor.yy162,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
   yymsp[-5].minor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
@@ -3095,7 +3095,7 @@ static void yy_reduce(
 #line 3096 "parse.c"
         break;
       case 155: /* expr ::= ID|INDEXED LP distinct exprlist RP */
-#line 926 "parse.y"
+#line 924 "parse.y"
 {
   if( yymsp[-1].minor.yy382 && yymsp[-1].minor.yy382->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
@@ -3110,7 +3110,7 @@ static void yy_reduce(
   yymsp[-4].minor.yy162 = yylhsminor.yy162;
         break;
       case 156: /* expr ::= ID|INDEXED LP STAR RP */
-#line 936 "parse.y"
+#line 934 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
   spanSet(&yylhsminor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
@@ -3119,7 +3119,7 @@ static void yy_reduce(
   yymsp[-3].minor.yy162 = yylhsminor.yy162;
         break;
       case 157: /* term ::= CTIME_KW */
-#line 940 "parse.y"
+#line 938 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
   spanSet(&yylhsminor.yy162, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
@@ -3128,7 +3128,7 @@ static void yy_reduce(
   yymsp[0].minor.yy162 = yylhsminor.yy162;
         break;
       case 158: /* expr ::= LP nexprlist COMMA expr RP */
-#line 969 "parse.y"
+#line 967 "parse.y"
 {
   ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy382, yymsp[-1].minor.yy162.pExpr);
   yylhsminor.yy162.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -3150,22 +3150,22 @@ static void yy_reduce(
       case 164: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==164);
       case 165: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==165);
       case 166: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==166);
-#line 980 "parse.y"
+#line 978 "parse.y"
 {spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy162);}
 #line 3156 "parse.c"
         break;
       case 167: /* likeop ::= LIKE_KW|MATCH */
-#line 993 "parse.y"
+#line 991 "parse.y"
 {yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/}
 #line 3161 "parse.c"
         break;
       case 168: /* likeop ::= NOT LIKE_KW|MATCH */
-#line 994 "parse.y"
+#line 992 "parse.y"
 {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
 #line 3166 "parse.c"
         break;
       case 169: /* expr ::= expr likeop expr */
-#line 995 "parse.y"
+#line 993 "parse.y"
 {
   ExprList *pList;
   int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
@@ -3180,7 +3180,7 @@ static void yy_reduce(
 #line 3181 "parse.c"
         break;
       case 170: /* expr ::= expr likeop expr ESCAPE expr */
-#line 1006 "parse.y"
+#line 1004 "parse.y"
 {
   ExprList *pList;
   int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
@@ -3196,17 +3196,17 @@ static void yy_reduce(
 #line 3197 "parse.c"
         break;
       case 171: /* expr ::= expr ISNULL|NOTNULL */
-#line 1033 "parse.y"
+#line 1031 "parse.y"
 {spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy162,&yymsp[0].minor.yy0);}
 #line 3202 "parse.c"
         break;
       case 172: /* expr ::= expr NOT NULL */
-#line 1034 "parse.y"
+#line 1032 "parse.y"
 {spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);}
 #line 3207 "parse.c"
         break;
       case 173: /* expr ::= expr IS expr */
-#line 1055 "parse.y"
+#line 1053 "parse.y"
 {
   spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy162);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy162.pExpr, yymsp[-2].minor.yy162.pExpr, TK_ISNULL);
@@ -3214,7 +3214,7 @@ static void yy_reduce(
 #line 3215 "parse.c"
         break;
       case 174: /* expr ::= expr IS NOT expr */
-#line 1059 "parse.y"
+#line 1057 "parse.y"
 {
   spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy162,&yymsp[0].minor.yy162);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy162.pExpr, yymsp[-3].minor.yy162.pExpr, TK_NOTNULL);
@@ -3223,28 +3223,28 @@ static void yy_reduce(
         break;
       case 175: /* expr ::= NOT expr */
       case 176: /* expr ::= BITNOT expr */ yytestcase(yyruleno==176);
-#line 1083 "parse.y"
+#line 1081 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,yymsp[-1].major,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
 #line 3229 "parse.c"
         break;
       case 177: /* expr ::= MINUS expr */
-#line 1087 "parse.y"
+#line 1085 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,TK_UMINUS,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
 #line 3234 "parse.c"
         break;
       case 178: /* expr ::= PLUS expr */
-#line 1089 "parse.y"
+#line 1087 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,TK_UPLUS,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
 #line 3239 "parse.c"
         break;
       case 179: /* between_op ::= BETWEEN */
       case 182: /* in_op ::= IN */ yytestcase(yyruleno==182);
-#line 1092 "parse.y"
+#line 1090 "parse.y"
 {yymsp[0].minor.yy52 = 0;}
 #line 3245 "parse.c"
         break;
       case 181: /* expr ::= expr between_op expr AND expr */
-#line 1094 "parse.y"
+#line 1092 "parse.y"
 {
   ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy162.pExpr);
   pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy162.pExpr);
@@ -3260,7 +3260,7 @@ static void yy_reduce(
 #line 3261 "parse.c"
         break;
       case 184: /* expr ::= expr in_op LP exprlist RP */
-#line 1110 "parse.y"
+#line 1108 "parse.y"
 {
     if( yymsp[-1].minor.yy382==0 ){
       /* Expressions of the form
@@ -3315,7 +3315,7 @@ static void yy_reduce(
 #line 3316 "parse.c"
         break;
       case 185: /* expr ::= LP select RP */
-#line 1161 "parse.y"
+#line 1159 "parse.y"
 {
     spanSet(&yymsp[-2].minor.yy162,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
     yymsp[-2].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
@@ -3324,7 +3324,7 @@ static void yy_reduce(
 #line 3325 "parse.c"
         break;
       case 186: /* expr ::= expr in_op LP select RP */
-#line 1166 "parse.y"
+#line 1164 "parse.y"
 {
     yymsp[-4].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy162.pExpr, 0);
     sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy162.pExpr, yymsp[-1].minor.yy279);
@@ -3334,7 +3334,7 @@ static void yy_reduce(
 #line 3335 "parse.c"
         break;
       case 187: /* expr ::= expr in_op nm paren_exprlist */
-#line 1172 "parse.y"
+#line 1170 "parse.y"
 {
     SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0);
     Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
@@ -3347,7 +3347,7 @@ static void yy_reduce(
 #line 3348 "parse.c"
         break;
       case 188: /* expr ::= EXISTS LP select RP */
-#line 1181 "parse.y"
+#line 1179 "parse.y"
 {
     Expr *p;
     spanSet(&yymsp[-3].minor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
@@ -3357,7 +3357,7 @@ static void yy_reduce(
 #line 3358 "parse.c"
         break;
       case 189: /* expr ::= CASE case_operand case_exprlist case_else END */
-#line 1190 "parse.y"
+#line 1188 "parse.y"
 {
   spanSet(&yymsp[-4].minor.yy162,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-C*/
   yymsp[-4].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy362, 0);
@@ -3372,7 +3372,7 @@ static void yy_reduce(
 #line 3373 "parse.c"
         break;
       case 190: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
-#line 1203 "parse.y"
+#line 1201 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy382, yymsp[-2].minor.yy162.pExpr);
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy382, yymsp[0].minor.yy162.pExpr);
@@ -3380,7 +3380,7 @@ static void yy_reduce(
 #line 3381 "parse.c"
         break;
       case 191: /* case_exprlist ::= WHEN expr THEN expr */
-#line 1207 "parse.y"
+#line 1205 "parse.y"
 {
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy162.pExpr);
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy382, yymsp[0].minor.yy162.pExpr);
@@ -3388,28 +3388,28 @@ static void yy_reduce(
 #line 3389 "parse.c"
         break;
       case 194: /* case_operand ::= expr */
-#line 1217 "parse.y"
+#line 1215 "parse.y"
 {yymsp[0].minor.yy362 = yymsp[0].minor.yy162.pExpr; /*A-overwrites-X*/}
 #line 3394 "parse.c"
         break;
       case 197: /* nexprlist ::= nexprlist COMMA expr */
-#line 1228 "parse.y"
+#line 1226 "parse.y"
 {yymsp[-2].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy382,yymsp[0].minor.yy162.pExpr);}
 #line 3399 "parse.c"
         break;
       case 198: /* nexprlist ::= expr */
-#line 1230 "parse.y"
+#line 1228 "parse.y"
 {yymsp[0].minor.yy382 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy162.pExpr); /*A-overwrites-Y*/}
 #line 3404 "parse.c"
         break;
       case 200: /* paren_exprlist ::= LP exprlist RP */
       case 205: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==205);
-#line 1238 "parse.y"
+#line 1236 "parse.y"
 {yymsp[-2].minor.yy382 = yymsp[-1].minor.yy382;}
 #line 3410 "parse.c"
         break;
       case 201: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm ON nm LP sortlist RP where_opt */
-#line 1245 "parse.y"
+#line 1243 "parse.y"
 {
   sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy0, 
                      sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0), yymsp[-2].minor.yy382, yymsp[-9].minor.yy52,
@@ -3419,87 +3419,87 @@ static void yy_reduce(
         break;
       case 202: /* uniqueflag ::= UNIQUE */
       case 243: /* raisetype ::= ABORT */ yytestcase(yyruleno==243);
-#line 1252 "parse.y"
+#line 1250 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_ABORT;}
 #line 3425 "parse.c"
         break;
       case 203: /* uniqueflag ::= */
-#line 1253 "parse.y"
+#line 1251 "parse.y"
 {yymsp[1].minor.yy52 = ON_CONFLICT_ACTION_NONE;}
 #line 3430 "parse.c"
         break;
       case 206: /* eidlist ::= eidlist COMMA nm collate sortorder */
-#line 1296 "parse.y"
+#line 1294 "parse.y"
 {
   yymsp[-4].minor.yy382 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy382, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy52, yymsp[0].minor.yy52);
 }
 #line 3437 "parse.c"
         break;
       case 207: /* eidlist ::= nm collate sortorder */
-#line 1299 "parse.y"
+#line 1297 "parse.y"
 {
   yymsp[-2].minor.yy382 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy52, yymsp[0].minor.yy52); /*A-overwrites-Y*/
 }
 #line 3444 "parse.c"
         break;
       case 210: /* cmd ::= DROP INDEX ifexists fullname ON nm */
-#line 1310 "parse.y"
+#line 1308 "parse.y"
 {
     sqlite3DropIndex(pParse, yymsp[-2].minor.yy387, &yymsp[0].minor.yy0, yymsp[-3].minor.yy52);
 }
 #line 3451 "parse.c"
         break;
       case 211: /* cmd ::= PRAGMA nm */
-#line 1317 "parse.y"
+#line 1315 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[0].minor.yy0,0,0,0,0);
 }
 #line 3458 "parse.c"
         break;
       case 212: /* cmd ::= PRAGMA nm EQ nmnum */
-#line 1320 "parse.y"
+#line 1318 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy0,0,0);
 }
 #line 3465 "parse.c"
         break;
       case 213: /* cmd ::= PRAGMA nm LP nmnum RP */
-#line 1323 "parse.y"
+#line 1321 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,0,&yymsp[-1].minor.yy0,0,0);
 }
 #line 3472 "parse.c"
         break;
       case 214: /* cmd ::= PRAGMA nm EQ minus_num */
-#line 1326 "parse.y"
+#line 1324 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy0,0,1);
 }
 #line 3479 "parse.c"
         break;
       case 215: /* cmd ::= PRAGMA nm LP minus_num RP */
-#line 1329 "parse.y"
+#line 1327 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,0,&yymsp[-1].minor.yy0,0,1);
 }
 #line 3486 "parse.c"
         break;
       case 216: /* cmd ::= PRAGMA nm EQ nm DOT nm */
-#line 1332 "parse.y"
+#line 1330 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0,0);
 }
 #line 3493 "parse.c"
         break;
       case 217: /* cmd ::= PRAGMA */
-#line 1335 "parse.y"
+#line 1333 "parse.y"
 {
     sqlite3Pragma(pParse, 0,0,0,0,0);
 }
 #line 3500 "parse.c"
         break;
       case 220: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
-#line 1355 "parse.y"
+#line 1351 "parse.y"
 {
   Token all;
   all.z = yymsp[-3].minor.yy0.z;
@@ -3510,7 +3510,7 @@ static void yy_reduce(
 #line 3511 "parse.c"
         break;
       case 221: /* trigger_decl ::= TRIGGER ifnotexists nm trigger_time trigger_event ON fullname foreach_clause when_clause */
-#line 1365 "parse.y"
+#line 1361 "parse.y"
 {
   sqlite3BeginTrigger(pParse, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy52, yymsp[-4].minor.yy10.a, yymsp[-4].minor.yy10.b, yymsp[-2].minor.yy387, yymsp[0].minor.yy362, yymsp[-7].minor.yy52);
   yymsp[-8].minor.yy0 = yymsp[-6].minor.yy0; /*yymsp[-8].minor.yy0-overwrites-T*/
@@ -3518,48 +3518,48 @@ static void yy_reduce(
 #line 3519 "parse.c"
         break;
       case 222: /* trigger_time ::= BEFORE */
-#line 1371 "parse.y"
+#line 1367 "parse.y"
 { yymsp[0].minor.yy52 = TK_BEFORE; }
 #line 3524 "parse.c"
         break;
       case 223: /* trigger_time ::= AFTER */
-#line 1372 "parse.y"
+#line 1368 "parse.y"
 { yymsp[0].minor.yy52 = TK_AFTER;  }
 #line 3529 "parse.c"
         break;
       case 224: /* trigger_time ::= INSTEAD OF */
-#line 1373 "parse.y"
+#line 1369 "parse.y"
 { yymsp[-1].minor.yy52 = TK_INSTEAD;}
 #line 3534 "parse.c"
         break;
       case 225: /* trigger_time ::= */
-#line 1374 "parse.y"
+#line 1370 "parse.y"
 { yymsp[1].minor.yy52 = TK_BEFORE; }
 #line 3539 "parse.c"
         break;
       case 226: /* trigger_event ::= DELETE|INSERT */
       case 227: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==227);
-#line 1378 "parse.y"
+#line 1374 "parse.y"
 {yymsp[0].minor.yy10.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy10.b = 0;}
 #line 3545 "parse.c"
         break;
       case 228: /* trigger_event ::= UPDATE OF idlist */
-#line 1380 "parse.y"
+#line 1376 "parse.y"
 {yymsp[-2].minor.yy10.a = TK_UPDATE; yymsp[-2].minor.yy10.b = yymsp[0].minor.yy40;}
 #line 3550 "parse.c"
         break;
       case 229: /* when_clause ::= */
-#line 1387 "parse.y"
+#line 1383 "parse.y"
 { yymsp[1].minor.yy362 = 0; }
 #line 3555 "parse.c"
         break;
       case 230: /* when_clause ::= WHEN expr */
-#line 1388 "parse.y"
+#line 1384 "parse.y"
 { yymsp[-1].minor.yy362 = yymsp[0].minor.yy162.pExpr; }
 #line 3560 "parse.c"
         break;
       case 231: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
-#line 1392 "parse.y"
+#line 1388 "parse.y"
 {
   assert( yymsp[-2].minor.yy427!=0 );
   yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
@@ -3568,7 +3568,7 @@ static void yy_reduce(
 #line 3569 "parse.c"
         break;
       case 232: /* trigger_cmd_list ::= trigger_cmd SEMI */
-#line 1397 "parse.y"
+#line 1393 "parse.y"
 { 
   assert( yymsp[-1].minor.yy427!=0 );
   yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
@@ -3576,7 +3576,7 @@ static void yy_reduce(
 #line 3577 "parse.c"
         break;
       case 233: /* trnm ::= nm DOT nm */
-#line 1408 "parse.y"
+#line 1404 "parse.y"
 {
   yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
   sqlite3ErrorMsg(pParse, 
@@ -3586,7 +3586,7 @@ static void yy_reduce(
 #line 3587 "parse.c"
         break;
       case 234: /* tridxby ::= INDEXED BY nm */
-#line 1420 "parse.y"
+#line 1416 "parse.y"
 {
   sqlite3ErrorMsg(pParse,
         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
@@ -3595,7 +3595,7 @@ static void yy_reduce(
 #line 3596 "parse.c"
         break;
       case 235: /* tridxby ::= NOT INDEXED */
-#line 1425 "parse.y"
+#line 1421 "parse.y"
 {
   sqlite3ErrorMsg(pParse,
         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
@@ -3604,27 +3604,27 @@ static void yy_reduce(
 #line 3605 "parse.c"
         break;
       case 236: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-#line 1438 "parse.y"
+#line 1434 "parse.y"
 {yymsp[-6].minor.yy427 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy382, yymsp[0].minor.yy362, yymsp[-5].minor.yy52);}
 #line 3610 "parse.c"
         break;
       case 237: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
-#line 1442 "parse.y"
+#line 1438 "parse.y"
 {yymsp[-4].minor.yy427 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy40, yymsp[0].minor.yy279, yymsp[-4].minor.yy52);/*A-overwrites-R*/}
 #line 3615 "parse.c"
         break;
       case 238: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-#line 1446 "parse.y"
+#line 1442 "parse.y"
 {yymsp[-4].minor.yy427 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy362);}
 #line 3620 "parse.c"
         break;
       case 239: /* trigger_cmd ::= select */
-#line 1450 "parse.y"
+#line 1446 "parse.y"
 {yymsp[0].minor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy279); /*A-overwrites-X*/}
 #line 3625 "parse.c"
         break;
       case 240: /* expr ::= RAISE LP IGNORE RP */
-#line 1453 "parse.y"
+#line 1449 "parse.y"
 {
   spanSet(&yymsp[-3].minor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-X*/
   yymsp[-3].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
@@ -3635,7 +3635,7 @@ static void yy_reduce(
 #line 3636 "parse.c"
         break;
       case 241: /* expr ::= RAISE LP raisetype COMMA STRING RP */
-#line 1460 "parse.y"
+#line 1456 "parse.y"
 {
   spanSet(&yymsp[-5].minor.yy162,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-X*/
   yymsp[-5].minor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
@@ -3646,78 +3646,78 @@ static void yy_reduce(
 #line 3647 "parse.c"
         break;
       case 242: /* raisetype ::= ROLLBACK */
-#line 1470 "parse.y"
+#line 1465 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_ROLLBACK;}
 #line 3652 "parse.c"
         break;
       case 244: /* raisetype ::= FAIL */
-#line 1472 "parse.y"
+#line 1467 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_FAIL;}
 #line 3657 "parse.c"
         break;
       case 245: /* cmd ::= DROP TRIGGER ifexists fullname */
-#line 1477 "parse.y"
+#line 1471 "parse.y"
 {
   sqlite3DropTrigger(pParse,yymsp[0].minor.yy387,yymsp[-1].minor.yy52);
 }
 #line 3664 "parse.c"
         break;
       case 246: /* cmd ::= REINDEX */
-#line 1484 "parse.y"
+#line 1477 "parse.y"
 {sqlite3Reindex(pParse, 0, 0);}
 #line 3669 "parse.c"
         break;
       case 247: /* cmd ::= REINDEX nm */
-#line 1485 "parse.y"
+#line 1478 "parse.y"
 {sqlite3Reindex(pParse, &yymsp[0].minor.yy0, 0);}
 #line 3674 "parse.c"
         break;
       case 248: /* cmd ::= REINDEX nm ON nm */
-#line 1486 "parse.y"
+#line 1479 "parse.y"
 {sqlite3Reindex(pParse, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);}
 #line 3679 "parse.c"
         break;
       case 249: /* cmd ::= ANALYZE */
-#line 1491 "parse.y"
+#line 1484 "parse.y"
 {sqlite3Analyze(pParse, 0);}
 #line 3684 "parse.c"
         break;
       case 250: /* cmd ::= ANALYZE nm */
-#line 1492 "parse.y"
+#line 1485 "parse.y"
 {sqlite3Analyze(pParse, &yymsp[0].minor.yy0);}
 #line 3689 "parse.c"
         break;
       case 251: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
-#line 1497 "parse.y"
+#line 1490 "parse.y"
 {
   sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy387,&yymsp[0].minor.yy0);
 }
 #line 3696 "parse.c"
         break;
       case 252: /* with ::= */
-#line 1520 "parse.y"
+#line 1513 "parse.y"
 {yymsp[1].minor.yy151 = 0;}
 #line 3701 "parse.c"
         break;
       case 253: /* with ::= WITH wqlist */
-#line 1522 "parse.y"
+#line 1515 "parse.y"
 { yymsp[-1].minor.yy151 = yymsp[0].minor.yy151; }
 #line 3706 "parse.c"
         break;
       case 254: /* with ::= WITH RECURSIVE wqlist */
-#line 1523 "parse.y"
+#line 1516 "parse.y"
 { yymsp[-2].minor.yy151 = yymsp[0].minor.yy151; }
 #line 3711 "parse.c"
         break;
       case 255: /* wqlist ::= nm eidlist_opt AS LP select RP */
-#line 1525 "parse.y"
+#line 1518 "parse.y"
 {
   yymsp[-5].minor.yy151 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy382, yymsp[-1].minor.yy279); /*A-overwrites-X*/
 }
 #line 3718 "parse.c"
         break;
       case 256: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
-#line 1528 "parse.y"
+#line 1521 "parse.y"
 {
   yymsp[-7].minor.yy151 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy151, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy382, yymsp[-1].minor.yy279);
 }
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 9ee7daccf..7fc19bded 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -367,7 +367,6 @@ ifexists(A) ::= .            {A = 0;}
 
 ///////////////////// The CREATE VIEW statement /////////////////////////////
 //
-%ifndef SQLITE_OMIT_VIEW
 cmd ::= createkw(X) VIEW ifnotexists(E) nm(Y) eidlist_opt(C)
           AS select(S). {
   sqlite3CreateView(pParse, &X, &Y, C, S, E);
@@ -375,7 +374,6 @@ cmd ::= createkw(X) VIEW ifnotexists(E) nm(Y) eidlist_opt(C)
 cmd ::= DROP VIEW ifexists(E) fullname(X). {
   sqlite3DropTable(pParse, X, 1, E);
 }
-%endif  SQLITE_OMIT_VIEW
 
 //////////////////////// The SELECT statement /////////////////////////////////
 //
@@ -1350,8 +1348,6 @@ plus_num(A) ::= number(A).
 minus_num(A) ::= MINUS number(X).     {A = X;}
 //////////////////////////// The CREATE TRIGGER command /////////////////////
 
-%ifndef SQLITE_OMIT_TRIGGER
-
 cmd ::= createkw trigger_decl(A) BEGIN trigger_cmd_list(S) END(Z). {
   Token all;
   all.z = A.z;
@@ -1464,7 +1460,6 @@ expr(A) ::= RAISE(X) LP raisetype(T) COMMA STRING(Z) RP(Y).  {
     A.pExpr->affinity = (char)T;
   }
 }
-%endif  !SQLITE_OMIT_TRIGGER
 
 %type raisetype {int}
 raisetype(A) ::= ROLLBACK.  {A = ON_CONFLICT_ACTION_ROLLBACK;}
@@ -1473,11 +1468,9 @@ raisetype(A) ::= FAIL.      {A = ON_CONFLICT_ACTION_FAIL;}
 
 
 ////////////////////////  DROP TRIGGER statement //////////////////////////////
-%ifndef SQLITE_OMIT_TRIGGER
 cmd ::= DROP TRIGGER ifexists(NOERR) fullname(X). {
   sqlite3DropTrigger(pParse,X,NOERR);
 }
-%endif  !SQLITE_OMIT_TRIGGER
 
 ////////////////////////// REINDEX collation //////////////////////////////////
 %ifndef SQLITE_OMIT_REINDEX
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 23b4c73b5..8aa96119f 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -153,7 +153,6 @@ returnSingleInt(Vdbe * v, i64 value)
 /*
  * Return a human-readable name for a constraint resolution action.
  */
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 static const char *
 actionName(u8 action)
 {
@@ -178,7 +177,6 @@ actionName(u8 action)
 	}
 	return zName;
 }
-#endif
 
 /*
  * Locate a pragma in the aPragmaName[] array.
@@ -536,7 +534,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 	}
 #endif				/* SQLITE_OMIT_SCHEMA_PRAGMAS */
 
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 	case PragTyp_FOREIGN_KEY_LIST:{
 			if (zRight) {
 				FKey *pFK;
@@ -569,10 +566,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			}
 			break;
 		}
-#endif				/* !defined(SQLITE_OMIT_FOREIGN_KEY) */
 
-#ifndef SQLITE_OMIT_FOREIGN_KEY
-#ifndef SQLITE_OMIT_TRIGGER
 	case PragTyp_FOREIGN_KEY_CHECK:{
 			FKey *pFK;	/* A foreign key constraint */
 			Table *pTab;	/* Child table contain "REFERENCES"
@@ -743,8 +737,6 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 			}
 			break;
 		}
-#endif				/* !defined(SQLITE_OMIT_TRIGGER) */
-#endif				/* !defined(SQLITE_OMIT_FOREIGN_KEY) */
 
 #ifndef NDEBUG
 	case PragTyp_PARSER_TRACE:{
diff --git a/src/box/sql/pragma.h b/src/box/sql/pragma.h
index f04c27d47..cfdd868c5 100644
--- a/src/box/sql/pragma.h
+++ b/src/box/sql/pragma.h
@@ -153,14 +153,12 @@ static const PragmaName aPragmaName[] = {
 	 /* iArg:      */ 0},
 #endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 	{ /* zName:     */ "defer_foreign_keys",
 	 /* ePragTyp:  */ PragTyp_FLAG,
 	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
 	 /* ColNames:  */ 0, 0,
 	 /* iArg:      */ SQLITE_DeferFKs},
 #endif
-#endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 	{ /* zName:     */ "empty_result_callbacks",
 	 /* ePragTyp:  */ PragTyp_FLAG,
@@ -168,30 +166,24 @@ static const PragmaName aPragmaName[] = {
 	 /* ColNames:  */ 0, 0,
 	 /* iArg:      */ SQLITE_NullCallback},
 #endif
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 	{ /* zName:     */ "foreign_key_check",
 	 /* ePragTyp:  */ PragTyp_FOREIGN_KEY_CHECK,
 	 /* ePragFlg:  */ PragFlg_NeedSchema,
 	 /* ColNames:  */ 37, 4,
 	 /* iArg:      */ 0},
-#endif
-#if !defined(SQLITE_OMIT_FOREIGN_KEY)
 	{ /* zName:     */ "foreign_key_list",
 	 /* ePragTyp:  */ PragTyp_FOREIGN_KEY_LIST,
 	 /* ePragFlg:  */
 	 PragFlg_NeedSchema | PragFlg_Result1 | PragFlg_SchemaOpt,
 	 /* ColNames:  */ 29, 8,
 	 /* iArg:      */ 0},
-#endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 	{ /* zName:     */ "foreign_keys",
 	 /* ePragTyp:  */ PragTyp_FLAG,
 	 /* ePragFlg:  */ PragFlg_Result0 | PragFlg_NoColumns1,
 	 /* ColNames:  */ 0, 0,
 	 /* iArg:      */ SQLITE_ForeignKeys},
 #endif
-#endif
 #if !defined(SQLITE_OMIT_FLAG_PRAGMAS)
 	{ /* zName:     */ "full_column_names",
 	 /* ePragTyp:  */ PragTyp_FLAG,
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 63997f25e..c5db29c96 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -307,8 +307,6 @@ lookupName(Parse * pParse,	/* The parsing context */
 				}
 			}
 		}
-		/* if( pSrcList ) */
-#ifndef SQLITE_OMIT_TRIGGER
 		/* If we have not already resolved the name, then maybe
 		 * it is a new.* or old.* trigger argument reference
 		 */
@@ -367,7 +365,6 @@ lookupName(Parse * pParse,	/* The parsing context */
 				}
 			}
 		}
-#endif				/* !defined(SQLITE_OMIT_TRIGGER) */
 
 		/*
 		 * If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index c7f87f340..44863b394 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -1175,7 +1175,6 @@ selectInnerLoop(Parse * pParse,		/* The parser context */
 		}
 #endif				/* SQLITE_OMIT_CTE */
 
-#if !defined(SQLITE_OMIT_TRIGGER)
 		/* Discard the results.  This is used for SELECT statements inside
 		 * the body of a TRIGGER.  The purpose of such selects is to call
 		 * user-defined functions that have side effects.  We do not care
@@ -1185,7 +1184,6 @@ selectInnerLoop(Parse * pParse,		/* The parser context */
 			assert(eDest == SRT_Discard);
 			break;
 		}
-#endif
 	}
 
 	/* Jump to the end of the loop if the LIMIT is reached.  Except, if
@@ -3471,7 +3469,7 @@ multiSelectOrderBy(Parse * pParse,	/* Parsing context */
 }
 #endif
 
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 /* Forward Declarations */
 static void substExprList(Parse *, ExprList *, int, ExprList *);
 static void substSelect(Parse *, Select *, int, ExprList *, int);
@@ -3576,9 +3574,9 @@ substSelect(Parse * pParse,	/* Report errors here */
 		}
 	} while (doPrior && (p = p->pPrior) != 0);
 }
-#endif				/* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
 
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 /*
  * This routine attempts to flatten subqueries as a performance optimization.
  * This routine returns 1 if it makes changes and 0 if no flattening occurs.
@@ -4146,9 +4144,9 @@ flattenSubquery(Parse * pParse,		/* Parsing context */
 
 	return 1;
 }
-#endif				/* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
 
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 /*
  * Make copies of relevant WHERE clause terms of the outer query into
  * the WHERE clause of subquery.  Example:
@@ -4225,7 +4223,7 @@ pushDownWhereTerms(Parse * pParse,	/* Parse context (for malloc() and error repo
 	}
 	return nChng;
 }
-#endif				/* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
+#endif /* !defined(SQLITE_OMIT_SUBQUERY) */
 
 /*
  * Based on the contents of the AggInfo structure indicated by the first
@@ -4759,7 +4757,6 @@ selectExpander(Walker * pWalker, Select * p)
 			if (cannotBeFunction(pParse, pFrom)) {
 				return WRC_Abort;
 			}
-#if !defined(SQLITE_OMIT_VIEW)
 			if (space_is_view(pTab)) {
 				i16 nCol;
 				if (sqlite3ViewGetColumnNames(pParse, pTab))
@@ -4774,7 +4771,6 @@ selectExpander(Walker * pWalker, Select * p)
 				sqlite3WalkSelect(pWalker, pFrom->pSelect);
 				pTab->nCol = nCol;
 			}
-#endif
 		}
 
 		/* Locate the index named by the INDEXED BY clause, if any. */
@@ -5416,7 +5412,7 @@ sqlite3Select(Parse * pParse,		/* The parser context */
 
 	/* Try to flatten subqueries in the FROM clause up into the main query
 	 */
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 	for (i = 0; !p->pPrior && i < pTabList->nSrc; i++) {
 		struct SrcList_item *pItem = &pTabList->a[i];
 		Select *pSub = pItem->pSelect;
@@ -5478,7 +5474,7 @@ sqlite3Select(Parse * pParse,		/* The parser context */
 
 	/* Generate code for all sub-queries in the FROM clause
 	 */
-#if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW)
+#if !defined(SQLITE_OMIT_SUBQUERY)
 	for (i = 0; i < pTabList->nSrc; i++) {
 		struct SrcList_item *pItem = &pTabList->a[i];
 		SelectDest dest;
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index f43711a7f..91a338246 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -3580,12 +3580,7 @@ int sqlite3FaultSim(int);
 #endif
 
 void sqlite3CreateView(Parse *, Token *, Token *, ExprList *, Select *, int);
-
-#if !defined(SQLITE_OMIT_VIEW)
 int sqlite3ViewGetColumnNames(Parse *, Table *);
-#else
-#define sqlite3ViewGetColumnNames(A,B) 0
-#endif
 
 #if SQLITE_MAX_ATTACHED>30
 int sqlite3DbMaskAllZero(yDbMask);
@@ -3742,11 +3737,8 @@ int sqlite3SafetyCheckOk(sqlite3 *);
 int sqlite3SafetyCheckSickOrOk(sqlite3 *);
 void sqlite3ChangeCookie(Parse *);
 
-#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
 void sqlite3MaterializeView(Parse *, Table *, Expr *, int);
-#endif
 
-#ifndef SQLITE_OMIT_TRIGGER
 void sqlite3BeginTrigger(Parse *, Token *, int, int, IdList *, SrcList *,
 			 Expr *, int);
 void sqlite3FinishTrigger(Parse *, TriggerStep *, Token *);
@@ -3770,17 +3762,6 @@ u32 sqlite3TriggerColmask(Parse *, Trigger *, ExprList *, int, int, Table *,
 			  int);
 #define sqlite3ParseToplevel(p) ((p)->pToplevel ? (p)->pToplevel : (p))
 #define sqlite3IsToplevel(p) ((p)->pToplevel==0)
-#else
-#define sqlite3TriggersExist(C,D,E,F) 0
-#define sqlite3DeleteTrigger(A,B)
-#define sqlite3DropTriggerPtr(A,B)
-#define sqlite3UnlinkAndDeleteTrigger(A,B,C)
-#define sqlite3CodeRowTrigger(A,B,C,D,E,F,G,H,I)
-#define sqlite3CodeRowTriggerDirect(A,B,C,D,E,F)
-#define sqlite3ParseToplevel(p) p
-#define sqlite3IsToplevel(p) 1
-#define sqlite3TriggerColmask(A,B,C,D,E,F,G) 0
-#endif
 
 int sqlite3JoinType(Parse *, Token *, Token *, Token *);
 void sqlite3CreateForeignKey(Parse *, ExprList *, Token *, ExprList *, int);
@@ -3997,34 +3978,14 @@ void sqlite3WithPush(Parse *, With *, u8);
 #define sqlite3WithDelete(x,y)
 #endif
 
-/* Declarations for functions in fkey.c. All of these are replaced by
- * no-op macros if OMIT_FOREIGN_KEY is defined. In this case no foreign
- * key functionality is available. If OMIT_TRIGGER is defined but
- * OMIT_FOREIGN_KEY is not, only some of the functions are no-oped. In
- * this case foreign keys are parsed, but no other functionality is
- * provided (enforcement of FK constraints requires the triggers sub-system).
- */
-#if !defined(SQLITE_OMIT_FOREIGN_KEY) && !defined(SQLITE_OMIT_TRIGGER)
 void sqlite3FkCheck(Parse *, Table *, int, int, int *);
 void sqlite3FkDropTable(Parse *, SrcList *, Table *);
 void sqlite3FkActions(Parse *, Table *, ExprList *, int, int *);
 int sqlite3FkRequired(Table *, int *);
 u32 sqlite3FkOldmask(Parse *, Table *);
 FKey *sqlite3FkReferences(Table *);
-#else
-#define sqlite3FkActions(a,b,c,d,e)
-#define sqlite3FkCheck(a,b,c,d,e,f)
-#define sqlite3FkDropTable(a,b,c)
-#define sqlite3FkOldmask(a,b)         0
-#define sqlite3FkRequired(b,c)    0
-#endif
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 void sqlite3FkDelete(sqlite3 *, Table *);
 int sqlite3FkLocateIndex(Parse *, Table *, FKey *, Index **, int **);
-#else
-#define sqlite3FkDelete(a,b)
-#define sqlite3FkLocateIndex(a,b,c,d,e)
-#endif
 
 /*
  * Available fault injectors.  Should be numbered beginning with 0.
diff --git a/src/box/sql/treeview.c b/src/box/sql/treeview.c
index 3cdf64b56..8568e206e 100644
--- a/src/box/sql/treeview.c
+++ b/src/box/sql/treeview.c
@@ -574,7 +574,6 @@ sqlite3TreeViewExpr(TreeView * pView, const Expr * pExpr, u8 moreToFollow)
 			sqlite3TreeViewExprList(pView, pExpr->x.pList, 0, 0);
 			break;
 		}
-#ifndef SQLITE_OMIT_TRIGGER
 	case TK_RAISE:{
 			const char *zType = "unk";
 			switch (pExpr->affinity) {
@@ -595,7 +594,6 @@ sqlite3TreeViewExpr(TreeView * pView, const Expr * pExpr, u8 moreToFollow)
 					    pExpr->u.zToken);
 			break;
 		}
-#endif
 	case TK_MATCH:{
 			sqlite3TreeViewLine(pView, "MATCH {%d:%d}%s",
 					    pExpr->iTable, pExpr->iColumn,
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index 859b421db..6248059bf 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -41,7 +41,6 @@
 /* See comment in sqliteInt.h */
 int sqlSubProgramsRemaining;
 
-#ifndef SQLITE_OMIT_TRIGGER
 /*
  * Delete a linked list of TriggerStep structures.
  */
@@ -1161,5 +1160,3 @@ sqlite3TriggerColmask(Parse * pParse,	/* Parse context */
 
 	return mask;
 }
-
-#endif				/* !defined(SQLITE_OMIT_TRIGGER) */
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index 7727ae5d5..fe568ad4c 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -127,12 +127,9 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	int labelBreak;		/* Jump here to break out of UPDATE loop */
 	int labelContinue;	/* Jump here to continue next step of UPDATE loop */
 	struct session *user_session = current_session();
-
-#ifndef SQLITE_OMIT_TRIGGER
 	int isView;		/* True when updating a view (INSTEAD OF trigger) */
 	Trigger *pTrigger;	/* List of triggers on pTab, if required */
 	int tmask;		/* Mask of TRIGGER_BEFORE|TRIGGER_AFTER */
-#endif
 	int newmask;		/* Mask of NEW.* columns accessed by BEFORE triggers */
 	int iEph = 0;		/* Ephemeral table holding all primary key values */
 	int nKey = 0;		/* Number of elements in regKey */
@@ -161,19 +158,9 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	/* Figure out if we have any triggers and if the table being
 	 * updated is a view.
 	 */
-#ifndef SQLITE_OMIT_TRIGGER
 	pTrigger = sqlite3TriggersExist(pTab, TK_UPDATE, pChanges, &tmask);
 	isView = space_is_view(pTab);
 	assert(pTrigger || tmask == 0);
-#else
-#define pTrigger 0
-#define isView 0
-#define tmask 0
-#endif
-#ifdef SQLITE_OMIT_VIEW
-#undef isView
-#define isView 0
-#endif
 
 	if (sqlite3ViewGetColumnNames(pParse, pTab)) {
 		goto update_cleanup;
@@ -306,13 +293,11 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	/* If we are trying to update a view, realize that view into
 	 * an ephemeral table.
 	 */
-#if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
 	if (isView) {
 		sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
 		/* Number of columns from SELECT plus ID.*/
 		nKey = pTab->nCol + 1;
 	}
-#endif
 
 	/* Resolve the column names in all the expressions in the
 	 * WHERE clause.
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 329d46886..c7c84bbc0 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -4919,7 +4919,6 @@ case OP_DropTrigger: {
 	sqlite3UnlinkAndDeleteTrigger(db, pOp->p4.z);
 	break;
 }
-#ifndef SQLITE_OMIT_TRIGGER
 
 /* Opcode: Program P1 P2 P3 P4 P5
  *
@@ -5076,9 +5075,6 @@ case OP_Param: {           /* out2 */
 	break;
 }
 
-#endif /* #ifndef SQLITE_OMIT_TRIGGER */
-
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 /* Opcode: FkCounter P1 P2 * * *
  * Synopsis: fkctr[P1]+=P2
  *
@@ -5120,7 +5116,6 @@ case OP_FkIfZero: {         /* jump */
 	}
 	break;
 }
-#endif /* #ifndef SQLITE_OMIT_FOREIGN_KEY */
 
 /* Opcode: IfPos P1 P2 P3 * *
  * Synopsis: if r[P1]>0 then r[P1]-=P3, goto P2
diff --git a/src/box/sql/vdbe.h b/src/box/sql/vdbe.h
index 340ddc766..79ebc2d0d 100644
--- a/src/box/sql/vdbe.h
+++ b/src/box/sql/vdbe.h
@@ -266,9 +266,7 @@ int sql_vdbe_mem_alloc_region(Mem *, uint32_t);
 typedef int (*RecordCompare) (int, const void *, UnpackedRecord *);
 RecordCompare sqlite3VdbeFindCompare(UnpackedRecord *);
 
-#ifndef SQLITE_OMIT_TRIGGER
 void sqlite3VdbeLinkSubProgram(Vdbe *, SubProgram *);
-#endif
 
 /* Use SQLITE_ENABLE_COMMENTS to enable generation of extra comments on
  * each VDBE opcode.
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index fcb45c8a8..e5308ed85 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -556,11 +556,7 @@ void sqlite3VdbeMemAboutToChange(Vdbe *, Mem *);
 int sqlite3VdbeCheckMemInvariants(Mem *);
 #endif
 
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 int sqlite3VdbeCheckFk(Vdbe *, int);
-#else
-#define sqlite3VdbeCheckFk(p,i) 0
-#endif
 
 int sqlite3VdbeMemTranslate(Mem *, u8);
 #ifdef SQLITE_DEBUG
diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
index e4335524a..a4dd698ca 100644
--- a/src/box/sql/vdbeaux.c
+++ b/src/box/sql/vdbeaux.c
@@ -619,11 +619,9 @@ sqlite3VdbeAssertMayAbort(Vdbe * v, int mayAbort)
 			hasAbort = 1;
 			break;
 		}
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 		if (opcode == OP_FkCounter && pOp->p1 == 0 && pOp->p2 == 1) {
 			hasFkCounter = 1;
 		}
-#endif
 	}
 	sqlite3DbFree(v->db, sIter.apSub);
 
@@ -2463,7 +2461,6 @@ sqlite3VdbeCloseStatement(Vdbe * p, int eOp)
  * SQLITE_ERROR, set the result of the VM to SQLITE_CONSTRAINT_FOREIGNKEY
  * and write an error message to it. Then return SQLITE_ERROR.
  */
-#ifndef SQLITE_OMIT_FOREIGN_KEY
 int
 sqlite3VdbeCheckFk(Vdbe * p, int deferred)
 {
@@ -2477,7 +2474,6 @@ sqlite3VdbeCheckFk(Vdbe * p, int deferred)
 	}
 	return SQLITE_OK;
 }
-#endif
 
 int
 sql_txn_begin(Vdbe *p)
-- 
2.15.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [tarantool-patches] [PATCH 2/3] sql: add view column aliases to space format
  2018-04-03 14:54 [tarantool-patches] [PATCH 0/3] Rework VIEW processing Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives Nikita Pettik
@ 2018-04-03 14:54 ` Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 3/3] sql: load SELECT from 'CREATE VIEW ...' string Nikita Pettik
  2 siblings, 0 replies; 5+ messages in thread
From: Nikita Pettik @ 2018-04-03 14:54 UTC (permalink / raw)
  To: tarantool-patches; +Cc: v.shpilevoy, Nikita Pettik

One can create view as: 'CREATE VIEW v(a, b) AS SELECT ...'.
This patch adds these column aliases to space format just as named
fields. It is worth mentioning, that we can't fetch types of columns
from SELECT statement at this stage, since table to select from may not
exist:

    CREATE VIEW v AS SELECT * FROM t1;
    CREATE TABLE t1(id PRIMARY KEY);
    SELECT * FROM v;

Part of #3300
---
 src/box/sql.c              | 22 ++++++++++++++++++++--
 src/box/sql/build.c        | 13 +++++++++----
 src/box/sql/tarantoolInt.h |  2 +-
 3 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/src/box/sql.c b/src/box/sql.c
index c2577abef..acee96d27 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -1450,7 +1450,7 @@ static const char *convertSqliteAffinity(int affinity, bool allow_nulls)
  *
  * Ex: [{"name": "col1", "type": "integer"}, ... ]
  */
-int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
+int tarantoolSqlite3MakeTableFormat(Parse *parse, Table *pTable, void *buf)
 {
 	struct Column *aCol = pTable->aCol;
 	const struct Enc *enc = get_enc(buf);
@@ -1459,7 +1459,8 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 	char *base = buf, *p;
 	int i, n = pTable->nCol;
 
-	p = enc->encode_array(base, n);
+	if (n != 0 || pTable->pCheck == NULL)
+		p = enc->encode_array(base, n);
 
 	/* If table's PK is single column which is INTEGER, then
 	 * treat it as strict type, not affinity.  */
@@ -1511,6 +1512,23 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
 			p = enc->encode_str(p, def->u.zToken, strlen(def->u.zToken));
 		}
 	}
+	/* If table is really a view, set only fields names.
+	 * In this case they are encoded as CHECK constraints.
+	 */
+	if (n == 0 && pTable->pCheck != NULL) {
+		Column *cols;
+		i16 col_count;
+		sqlite3ColumnsFromExprList(parse, pTable->pCheck,
+					   &col_count, &cols);
+		p = enc->encode_array(base, col_count);
+		for (i = 0; i < col_count; ++i) {
+			p = enc->encode_map(p, 1);
+			p = enc->encode_str(p, "name", 4);
+			p = enc->encode_str(p, cols[i].zName,
+					    strlen(cols[i].zName));
+		}
+		sqlite3_free(cols);
+	}
 	return (int)(p - base);
 }
 
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 75b26a93a..293d88a60 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -1639,7 +1639,7 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 	int zOptsSz, zFormatSz;
 
 	zOpts = sqlite3DbMallocRaw(pParse->db,
-				   tarantoolSqlite3MakeTableFormat(p, NULL) +
+				   tarantoolSqlite3MakeTableFormat(pParse, p, NULL) +
 				   tarantoolSqlite3MakeTableOpts(p, zStmt,
 								 NULL) + 2);
 	if (!zOpts) {
@@ -1649,7 +1649,7 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 	} else {
 		zOptsSz = tarantoolSqlite3MakeTableOpts(p, zStmt, zOpts);
 		zFormat = zOpts + zOptsSz + 1;
-		zFormatSz = tarantoolSqlite3MakeTableFormat(p, zFormat);
+		zFormatSz = tarantoolSqlite3MakeTableFormat(pParse, p, zFormat);
 #if SQLITE_DEBUG
 		/* NUL-termination is necessary for VDBE-tracing facility only */
 		zOpts[zOptsSz] = 0;
@@ -1664,8 +1664,13 @@ createSpace(Parse * pParse, int iSpaceId, char *zStmt)
 			  sqlite3DbStrDup(pParse->db, p->zName), P4_DYNAMIC);
 	sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3 /* engine */ , 0,
 			  "memtx", P4_STATIC);
-	sqlite3VdbeAddOp2(v, OP_Integer, p->nCol,
-			  iFirstCol + 4 /* field_count */ );
+	/* Add field count. */
+	if (p->pSelect != NULL && p->pCheck != NULL) {
+		sqlite3VdbeAddOp2(v, OP_Integer, p->pCheck->nExpr,
+				  iFirstCol + 4);
+	} else {
+		sqlite3VdbeAddOp2(v, OP_Integer, p->nCol, iFirstCol + 4);
+	}
 	sqlite3VdbeAddOp4(v, OP_Blob, zOptsSz, iFirstCol + 5, MSGPACK_SUBTYPE,
 			  zOpts, P4_DYNAMIC);
 	/* zOpts and zFormat are co-located, hence STATIC */
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index 65acf1198..5649a9cae 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -126,7 +126,7 @@ tarantoolSqlite3IncrementMaxid(uint64_t *space_max_id);
  * Returns result size.
  * If buf==NULL estimate result size.
  */
-int tarantoolSqlite3MakeTableFormat(Table * pTable, void *buf);
+int tarantoolSqlite3MakeTableFormat(Parse *parse, Table * pTable, void *buf);
 
 /*
  * Format "opts" dictionary for _space entry.
-- 
2.15.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [tarantool-patches] [PATCH 3/3] sql: load SELECT from 'CREATE VIEW ...' string
  2018-04-03 14:54 [tarantool-patches] [PATCH 0/3] Rework VIEW processing Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives Nikita Pettik
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 2/3] sql: add view column aliases to space format Nikita Pettik
@ 2018-04-03 14:54 ` Nikita Pettik
  2 siblings, 0 replies; 5+ messages in thread
From: Nikita Pettik @ 2018-04-03 14:54 UTC (permalink / raw)
  To: tarantool-patches; +Cc: v.shpilevoy, Nikita Pettik

Space holds string of 'CREATE VIEW AS SELECT ...' statement, when space
represents VIEW.  To fetch from this string SELECT and load it into
internal structure, simple nested parsing has been introduced.  By
setting flag in parse context, it is possible to break parsing and
finish it immediately after SELECT processing. Alongside with it, SELECT
struct is saved into current parser. Further, this select is used in the
same wasy as struct Table->pSelect in original SQLite.

Also, refactored SQL routine connected with VIEW processing: fixed
codestyle, added comments, removed redundant routine, involved struct
space. Added tests on circularly view dependencies.

Closes #3300
---
 src/box/sql/build.c        | 198 +++++++++------
 src/box/sql/delete.c       |   2 +-
 src/box/sql/insert.c       |   2 +-
 src/box/sql/parse.c        | 614 +++++++++++++++++++++++----------------------
 src/box/sql/parse.y        |   6 +-
 src/box/sql/pragma.c       |   2 +-
 src/box/sql/select.c       | 160 ++++++------
 src/box/sql/sqliteInt.h    |  17 +-
 src/box/sql/tokenize.c     |  30 ++-
 src/box/sql/update.c       |   2 +-
 test/sql-tap/view.test.lua |  26 +-
 11 files changed, 576 insertions(+), 483 deletions(-)

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 293d88a60..c2690a6e9 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -2083,102 +2083,144 @@ sqlite3CreateView(Parse * pParse,	/* The parsing context */
 	return;
 }
 
-/*
- * The Table structure pTable is really a VIEW.  Fill in the names of
- * the columns of the view in the pTable structure.  Return the number
- * of errors.  If an error is seen leave an error message in pParse->zErrMsg.
+/**
+ * Store duplicate of SELECT into parsing context.
+ * This routine is called during parsing.
+ *
+ * @param parse_context Current parsing context.
+ * @param select Select to be stored.
  */
-int
-sqlite3ViewGetColumnNames(Parse * pParse, Table * pTable)
+void
+sql_store_select(struct Parse *parse_context, struct Select *select)
 {
-	Table *pSelTab;		/* A fake table from which we get the result set */
-	Select *pSel;		/* Copy of the SELECT that implements the view */
-	int nErr = 0;		/* Number of errors encountered */
-	int n;			/* Temporarily holds the number of cursors assigned */
-	sqlite3 *db = pParse->db;	/* Database connection for malloc errors */
-
-	assert(pTable);
+	Select *select_copy = sqlite3SelectDup(parse_context->db, select, 0);
+	parse_context->parsed_select = select_copy;
+}
 
-	/* A positive nCol means the columns names for this view are
-	 * already known.
+/**
+ * The Table structure table is really a VIEW. Fill in the names
+ * of the columns of the view in the table structure.
+ * This routine is needed due to the fact that at VIEW
+ * compilation time table(s) may not exist:
+ *
+ * CREATE VIEW v AS SELECT * FROM t;
+ * CREATE TABLE t1 (id INT PRIMARY KEY, a TEXT) ...;
+ * SELECT a FROM v1 WHERE id = 1;
+ *
+ * Thus, we should fetch column's names and types at compilation
+ * of SELECT statement stage.
+ *
+ * @param parse_context Current parsing context.
+ * @param[out] table Table which represent a view and to be filled
+ *                   with names and types of columns.
+ * @retval 0 on success, number of occurred errors otherwise.
+ */
+int
+sql_view_column_names(struct Parse *parse_context, struct Table *table)
+{
+	assert(table != NULL);
+	struct sqlite3 *db = parse_context->db;
+	/*
+	 * A positive nCol means the columns names for this view
+	 * are already known.
 	 */
-	if (pTable->nCol > 0)
+	if (table->nCol > 0)
 		return 0;
-
-	/* A negative nCol is a special marker meaning that we are currently
-	 * trying to compute the column names.  If we enter this routine with
-	 * a negative nCol, it means two or more views form a loop, like this:
+	/*
+	 * A negative nCol is a special marker meaning that we
+	 * are currently trying to compute the column names.
+	 * If we enter this routine with a negative nCol,
+	 * it means two or more views form a loop, like this:
 	 *
 	 *     CREATE VIEW one AS SELECT * FROM two;
 	 *     CREATE VIEW two AS SELECT * FROM one;
-	 *
-	 * Actually, the error above is now caught prior to reaching this point.
-	 * But the following test is still important as it does come up
-	 * in the following:
-	 *
-	 *     CREATE TABLE main.ex1(a);
-	 *     CREATE TEMP VIEW ex1 AS SELECT a FROM ex1;
-	 *     SELECT * FROM temp.ex1;
+	 * or
+	 *     CREATE VIEW v AS SELECT * FROM v;
 	 */
-	if (pTable->nCol < 0) {
-		sqlite3ErrorMsg(pParse, "view %s is circularly defined",
-				pTable->zName);
+	if (table->nCol < 0) {
+		sqlite3ErrorMsg(parse_context, "view %s is circularly defined",
+				table->zName);
 		return 1;
 	}
-	assert(pTable->nCol >= 0);
-
-	/* If we get this far, it means we need to compute the table names.
-	 * Note that the call to sqlite3ResultSetOfSelect() will expand any
-	 * "*" elements in the results set of the view and will assign cursors
-	 * to the elements of the FROM clause.  But we do not want these changes
-	 * to be permanent.  So the computation is done on a copy of the SELECT
-	 * statement that defines the view.
+	uint32_t space_id =
+		SQLITE_PAGENO_TO_SPACEID(table->tnum);
+	struct space *space = space_by_id(space_id);
+	assert(space != NULL);
+	assert(space->def->opts.is_view);
+	/*
+	 * If we get this far, it means we need to compute
+	 * the table names. Note that the call to
+	 * sql_result_set_of_select() will expand any "*" elements
+	 * in the results set of the view and will assign cursors
+	 * to the elements of the FROM clause. But we do not want
+	 * these changes to be permanent. So the computation is
+	 * done on a copy of the SELECT statement that defines
+	 * the view.
 	 */
-	assert(pTable->pSelect);
-	pSel = sqlite3SelectDup(db, pTable->pSelect, 0);
-	if (pSel) {
-		n = pParse->nTab;
-		sqlite3SrcListAssignCursors(pParse, pSel->pSrc);
-		pTable->nCol = -1;
-		db->lookaside.bDisable++;
-		pSelTab = sqlite3ResultSetOfSelect(pParse, pSel);
-		pParse->nTab = n;
-		if (pTable->pCheck) {
-			/* CREATE VIEW name(arglist) AS ...
-			 * The names of the columns in the table are taken from
-			 * arglist which is stored in pTable->pCheck.  The pCheck field
-			 * normally holds CHECK constraints on an ordinary table, but for
-			 * a VIEW it holds the list of column names.
-			 */
-			sqlite3ColumnsFromExprList(pParse, pTable->pCheck,
-						   &pTable->nCol,
-						   &pTable->aCol);
-			if (db->mallocFailed == 0 && pParse->nErr == 0
-			    && pTable->nCol == pSel->pEList->nExpr) {
-				sqlite3SelectAddColumnTypeAndCollation(pParse,
-								       pTable,
-								       pSel);
+	/* Copy of the SELECT that implements the view. */
+	struct Select *select = NULL;
+	/* Fetch SELECT statement from "CREATE VIEW ..." string. */
+	if (sql_view_compile(db, space->def->opts.sql, &select) != 0) {
+		sqlite3ErrorMsg(parse_context,
+				"failed to parse view statement: %s",
+				space->def->opts.sql);
+		return 1;
+	}
+	int error_count = 0;
+	if (select != NULL) {
+		/* Temporarily holds the number of cursors assigned. */
+		int n = parse_context->nTab;
+		sqlite3SrcListAssignCursors(parse_context, select->pSrc);
+		table->nCol = -1;
+		/* Fill fake table from which we get the result set. */
+		struct Table *select_table =
+			sql_result_set_of_select(parse_context, select);
+		parse_context->nTab = n;
+		if (space->def->field_count > 0) {
+			/* CREATE VIEW name(arglist) AS ... */
+			table->nCol = space->def->field_count;
+			uint32_t size = sizeof(table->aCol[0]) * table->nCol;
+			table->aCol = sqlite3Malloc(size);
+			if (table->aCol == NULL)
+				return ++error_count;
+			memset(table->aCol, 0, size);
+			for (int i = 0; i < table->nCol; ++i) {
+				size_t name_len =
+					strlen(space->def->fields[i].name) + 1;
+				table->aCol[i].zName = sqlite3Malloc(name_len);
+				if (table->aCol[i].zName == NULL)
+					return ++error_count;
+				memcpy(table->aCol[i].zName,
+				       space->def->fields[i].name, name_len);
+			}
+			if (db->mallocFailed == 0 && parse_context->nErr == 0
+			    && table->nCol == select->pEList->nExpr) {
+				sql_select_add_column_properties(parse_context,
+								 table,
+								 select);
 			}
-		} else if (pSelTab) {
-			/* CREATE VIEW name AS...  without an argument list.  Construct
-			 * the column names from the SELECT statement that defines the view.
+		} else if (select_table != NULL) {
+			/*
+			 * CREATE VIEW name AS...  without an
+			 * argument list. Construct the column
+			 * names from the SELECT statement that
+			 * defines the view.
 			 */
-			assert(pTable->aCol == 0);
-			pTable->nCol = pSelTab->nCol;
-			pTable->aCol = pSelTab->aCol;
-			pSelTab->nCol = 0;
-			pSelTab->aCol = 0;
+			assert(table->aCol == 0);
+			table->nCol = select_table->nCol;
+			table->aCol = select_table->aCol;
+			select_table->nCol = 0;
+			select_table->aCol = 0;
 		} else {
-			pTable->nCol = 0;
-			nErr++;
+			table->nCol = 0;
+			error_count++;
 		}
-		sqlite3DeleteTable(db, pSelTab);
-		sqlite3SelectDelete(db, pSel);
-		db->lookaside.bDisable--;
+		sqlite3DeleteTable(db, select_table);
+		sqlite3SelectDelete(db, select);
 	} else {
-		nErr++;
+		error_count++;
 	}
-	return nErr;
+	return error_count;
 }
 
 /*
diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
index a588082e1..f7397e631 100644
--- a/src/box/sql/delete.c
+++ b/src/box/sql/delete.c
@@ -284,7 +284,7 @@ sqlite3DeleteFrom(Parse * pParse,	/* The parser context */
 
 	/* If pTab is really a view, make sure it has been initialized.
 	 */
-	if (sqlite3ViewGetColumnNames(pParse, pTab)) {
+	if (sql_view_column_names(pParse, pTab)) {
 		goto delete_from_cleanup;
 	}
 
diff --git a/src/box/sql/insert.c b/src/box/sql/insert.c
index 5e67c2b73..1413b4459 100644
--- a/src/box/sql/insert.c
+++ b/src/box/sql/insert.c
@@ -392,7 +392,7 @@ sqlite3Insert(Parse * pParse,	/* Parser context */
 	/* If pTab is really a view, make sure it has been initialized.
 	 * ViewGetColumnNames() is a no-op if pTab is not a view.
 	 */
-	if (sqlite3ViewGetColumnNames(pParse, pTab)) {
+	if (sql_view_column_names(pParse, pTab)) {
 		goto insert_cleanup;
 	}
 
diff --git a/src/box/sql/parse.c b/src/box/sql/parse.c
index 72a2cf0bd..300cff500 100644
--- a/src/box/sql/parse.c
+++ b/src/box/sql/parse.c
@@ -81,7 +81,7 @@ static void disableLookaside(Parse *pParse){
   pParse->db->lookaside.bDisable++;
 }
 
-#line 396 "parse.y"
+#line 400 "parse.y"
 
   /*
   ** For a compound SELECT statement, make sure p->pPrior->pNext==p for
@@ -104,7 +104,7 @@ static void disableLookaside(Parse *pParse){
       }
     }
   }
-#line 835 "parse.y"
+#line 839 "parse.y"
 
   /* This is a utility routine used to set the ExprSpan.zStart and
   ** ExprSpan.zEnd values of pOut so that the span covers the complete
@@ -140,7 +140,7 @@ static void disableLookaside(Parse *pParse){
     pOut->zStart = t.z;
     pOut->zEnd = &t.z[t.n];
   }
-#line 943 "parse.y"
+#line 947 "parse.y"
 
   /* This routine constructs a binary expression node out of two ExprSpan
   ** objects and uses the result to populate a new ExprSpan object.
@@ -163,7 +163,7 @@ static void disableLookaside(Parse *pParse){
       pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0);
     }
   }
-#line 1017 "parse.y"
+#line 1021 "parse.y"
 
   /* Construct an expression node for a unary postfix operator
   */
@@ -176,7 +176,7 @@ static void disableLookaside(Parse *pParse){
     pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
     pOperand->zEnd = &pPostOp->z[pPostOp->n];
   }                           
-#line 1034 "parse.y"
+#line 1038 "parse.y"
 
   /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
   ** unary TK_ISNULL or TK_NOTNULL expression. */
@@ -188,7 +188,7 @@ static void disableLookaside(Parse *pParse){
       pA->pRight = 0;
     }
   }
-#line 1062 "parse.y"
+#line 1066 "parse.y"
 
   /* Construct an expression node for a unary prefix operator
   */
@@ -203,7 +203,7 @@ static void disableLookaside(Parse *pParse){
     pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0);
     pOut->zEnd = pOperand->zEnd;
   }
-#line 1267 "parse.y"
+#line 1271 "parse.y"
 
   /* Add a single new term to an ExprList that is used to store a
   ** list of identifiers.  Report an error if the ID list contains
@@ -1468,7 +1468,7 @@ static void yy_destructor(
     case 183: /* oneselect */
     case 194: /* values */
 {
-#line 390 "parse.y"
+#line 394 "parse.y"
 sqlite3SelectDelete(pParse->db, (yypminor->yy279));
 #line 1474 "parse.c"
 }
@@ -1476,7 +1476,7 @@ sqlite3SelectDelete(pParse->db, (yypminor->yy279));
     case 160: /* term */
     case 161: /* expr */
 {
-#line 833 "parse.y"
+#line 837 "parse.y"
 sql_expr_free(pParse->db, (yypminor->yy162).pExpr, false);
 #line 1482 "parse.c"
 }
@@ -1494,7 +1494,7 @@ sql_expr_free(pParse->db, (yypminor->yy162).pExpr, false);
     case 213: /* paren_exprlist */
     case 215: /* case_exprlist */
 {
-#line 1265 "parse.y"
+#line 1269 "parse.y"
 sqlite3ExprListDelete(pParse->db, (yypminor->yy382));
 #line 1500 "parse.c"
 }
@@ -1504,7 +1504,7 @@ sqlite3ExprListDelete(pParse->db, (yypminor->yy382));
     case 199: /* seltablist */
     case 200: /* stl_prefix */
 {
-#line 617 "parse.y"
+#line 621 "parse.y"
 sqlite3SrcListDelete(pParse->db, (yypminor->yy387));
 #line 1510 "parse.c"
 }
@@ -1512,7 +1512,7 @@ sqlite3SrcListDelete(pParse->db, (yypminor->yy387));
     case 184: /* with */
     case 229: /* wqlist */
 {
-#line 1510 "parse.y"
+#line 1514 "parse.y"
 sqlite3WithDelete(pParse->db, (yypminor->yy151));
 #line 1518 "parse.c"
 }
@@ -1524,7 +1524,7 @@ sqlite3WithDelete(pParse->db, (yypminor->yy151));
     case 216: /* case_else */
     case 225: /* when_clause */
 {
-#line 742 "parse.y"
+#line 746 "parse.y"
 sql_expr_free(pParse->db, (yypminor->yy362), false);
 #line 1530 "parse.c"
 }
@@ -1533,7 +1533,7 @@ sql_expr_free(pParse->db, (yypminor->yy362), false);
     case 206: /* idlist */
     case 209: /* idlist_opt */
 {
-#line 654 "parse.y"
+#line 658 "parse.y"
 sqlite3IdListDelete(pParse->db, (yypminor->yy40));
 #line 1539 "parse.c"
 }
@@ -1541,14 +1541,14 @@ sqlite3IdListDelete(pParse->db, (yypminor->yy40));
     case 221: /* trigger_cmd_list */
     case 226: /* trigger_cmd */
 {
-#line 1387 "parse.y"
+#line 1391 "parse.y"
 sqlite3DeleteTriggerStep(pParse->db, (yypminor->yy427));
 #line 1547 "parse.c"
 }
       break;
     case 223: /* trigger_event */
 {
-#line 1373 "parse.y"
+#line 1377 "parse.y"
 sqlite3IdListDelete(pParse->db, (yypminor->yy10).b);
 #line 1554 "parse.c"
 }
@@ -2537,19 +2537,23 @@ static void yy_reduce(
       case 73: /* cmd ::= createkw VIEW ifnotexists nm eidlist_opt AS select */
 #line 371 "parse.y"
 {
-  sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy382, yymsp[0].minor.yy279, yymsp[-4].minor.yy52);
+  if (!pParse->parse_only)
+    sqlite3CreateView(pParse, &yymsp[-6].minor.yy0, &yymsp[-3].minor.yy0, yymsp[-2].minor.yy382, yymsp[0].minor.yy279, yymsp[-4].minor.yy52);
+  else {
+    sql_store_select(pParse, yymsp[0].minor.yy279);
+  }
 }
-#line 2543 "parse.c"
+#line 2547 "parse.c"
         break;
       case 74: /* cmd ::= DROP VIEW ifexists fullname */
-#line 374 "parse.y"
+#line 378 "parse.y"
 {
   sqlite3DropTable(pParse, yymsp[0].minor.yy387, 1, yymsp[-1].minor.yy52);
 }
-#line 2550 "parse.c"
+#line 2554 "parse.c"
         break;
       case 75: /* cmd ::= select */
-#line 380 "parse.y"
+#line 384 "parse.y"
 {
   SelectDest dest = {SRT_Output, 0, 0, 0, 0, 0};
   if(!pParse->parse_only)
@@ -2558,10 +2562,10 @@ static void yy_reduce(
 	  sql_expr_extract_select(pParse, yymsp[0].minor.yy279);
   sqlite3SelectDelete(pParse->db, yymsp[0].minor.yy279);
 }
-#line 2562 "parse.c"
+#line 2566 "parse.c"
         break;
       case 76: /* select ::= with selectnowith */
-#line 420 "parse.y"
+#line 424 "parse.y"
 {
   Select *p = yymsp[0].minor.yy279;
   if( p ){
@@ -2572,10 +2576,10 @@ static void yy_reduce(
   }
   yymsp[-1].minor.yy279 = p; /*A-overwrites-W*/
 }
-#line 2576 "parse.c"
+#line 2580 "parse.c"
         break;
       case 77: /* selectnowith ::= selectnowith multiselect_op oneselect */
-#line 433 "parse.y"
+#line 437 "parse.y"
 {
   Select *pRhs = yymsp[0].minor.yy279;
   Select *pLhs = yymsp[-2].minor.yy279;
@@ -2598,21 +2602,21 @@ static void yy_reduce(
   }
   yymsp[-2].minor.yy279 = pRhs;
 }
-#line 2602 "parse.c"
+#line 2606 "parse.c"
         break;
       case 78: /* multiselect_op ::= UNION */
       case 80: /* multiselect_op ::= EXCEPT|INTERSECT */ yytestcase(yyruleno==80);
-#line 456 "parse.y"
+#line 460 "parse.y"
 {yymsp[0].minor.yy52 = yymsp[0].major; /*A-overwrites-OP*/}
-#line 2608 "parse.c"
+#line 2612 "parse.c"
         break;
       case 79: /* multiselect_op ::= UNION ALL */
-#line 457 "parse.y"
+#line 461 "parse.y"
 {yymsp[-1].minor.yy52 = TK_ALL;}
-#line 2613 "parse.c"
+#line 2617 "parse.c"
         break;
       case 81: /* oneselect ::= SELECT distinct selcollist from where_opt groupby_opt having_opt orderby_opt limit_opt */
-#line 461 "parse.y"
+#line 465 "parse.y"
 {
 #ifdef SELECTTRACE_ENABLED
   Token s = yymsp[-8].minor.yy0; /*A-overwrites-S*/
@@ -2643,17 +2647,17 @@ static void yy_reduce(
   }
 #endif /* SELECTRACE_ENABLED */
 }
-#line 2647 "parse.c"
+#line 2651 "parse.c"
         break;
       case 82: /* values ::= VALUES LP nexprlist RP */
-#line 495 "parse.y"
+#line 499 "parse.y"
 {
   yymsp[-3].minor.yy279 = sqlite3SelectNew(pParse,yymsp[-1].minor.yy382,0,0,0,0,0,SF_Values,0,0);
 }
-#line 2654 "parse.c"
+#line 2658 "parse.c"
         break;
       case 83: /* values ::= values COMMA LP exprlist RP */
-#line 498 "parse.y"
+#line 502 "parse.y"
 {
   Select *pRight, *pLeft = yymsp[-4].minor.yy279;
   pRight = sqlite3SelectNew(pParse,yymsp[-1].minor.yy382,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
@@ -2666,17 +2670,17 @@ static void yy_reduce(
     yymsp[-4].minor.yy279 = pLeft;
   }
 }
-#line 2670 "parse.c"
+#line 2674 "parse.c"
         break;
       case 84: /* distinct ::= DISTINCT */
-#line 515 "parse.y"
+#line 519 "parse.y"
 {yymsp[0].minor.yy52 = SF_Distinct;}
-#line 2675 "parse.c"
+#line 2679 "parse.c"
         break;
       case 85: /* distinct ::= ALL */
-#line 516 "parse.y"
+#line 520 "parse.y"
 {yymsp[0].minor.yy52 = SF_All;}
-#line 2680 "parse.c"
+#line 2684 "parse.c"
         break;
       case 87: /* sclp ::= */
       case 113: /* orderby_opt ::= */ yytestcase(yyruleno==113);
@@ -2684,94 +2688,94 @@ static void yy_reduce(
       case 196: /* exprlist ::= */ yytestcase(yyruleno==196);
       case 199: /* paren_exprlist ::= */ yytestcase(yyruleno==199);
       case 204: /* eidlist_opt ::= */ yytestcase(yyruleno==204);
-#line 529 "parse.y"
+#line 533 "parse.y"
 {yymsp[1].minor.yy382 = 0;}
-#line 2690 "parse.c"
+#line 2694 "parse.c"
         break;
       case 88: /* selcollist ::= sclp expr as */
-#line 530 "parse.y"
+#line 534 "parse.y"
 {
    yymsp[-2].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-2].minor.yy382, yymsp[-1].minor.yy162.pExpr);
    if( yymsp[0].minor.yy0.n>0 ) sqlite3ExprListSetName(pParse, yymsp[-2].minor.yy382, &yymsp[0].minor.yy0, 1);
    sqlite3ExprListSetSpan(pParse,yymsp[-2].minor.yy382,&yymsp[-1].minor.yy162);
 }
-#line 2699 "parse.c"
+#line 2703 "parse.c"
         break;
       case 89: /* selcollist ::= sclp STAR */
-#line 535 "parse.y"
+#line 539 "parse.y"
 {
   Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
   yymsp[-1].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-1].minor.yy382, p);
 }
-#line 2707 "parse.c"
+#line 2711 "parse.c"
         break;
       case 90: /* selcollist ::= sclp nm DOT STAR */
-#line 539 "parse.y"
+#line 543 "parse.y"
 {
   Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0);
   Expr *pLeft = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
   Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight);
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy382, pDot);
 }
-#line 2717 "parse.c"
+#line 2721 "parse.c"
         break;
       case 91: /* as ::= AS nm */
       case 218: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==218);
       case 219: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==219);
-#line 550 "parse.y"
+#line 554 "parse.y"
 {yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
-#line 2724 "parse.c"
+#line 2728 "parse.c"
         break;
       case 93: /* from ::= */
-#line 564 "parse.y"
+#line 568 "parse.y"
 {yymsp[1].minor.yy387 = sqlite3DbMallocZero(pParse->db, sizeof(*yymsp[1].minor.yy387));}
-#line 2729 "parse.c"
+#line 2733 "parse.c"
         break;
       case 94: /* from ::= FROM seltablist */
-#line 565 "parse.y"
+#line 569 "parse.y"
 {
   yymsp[-1].minor.yy387 = yymsp[0].minor.yy387;
   sqlite3SrcListShiftJoinType(yymsp[-1].minor.yy387);
 }
-#line 2737 "parse.c"
+#line 2741 "parse.c"
         break;
       case 95: /* stl_prefix ::= seltablist joinop */
-#line 573 "parse.y"
+#line 577 "parse.y"
 {
    if( ALWAYS(yymsp[-1].minor.yy387 && yymsp[-1].minor.yy387->nSrc>0) ) yymsp[-1].minor.yy387->a[yymsp[-1].minor.yy387->nSrc-1].fg.jointype = (u8)yymsp[0].minor.yy52;
 }
-#line 2744 "parse.c"
+#line 2748 "parse.c"
         break;
       case 96: /* stl_prefix ::= */
-#line 576 "parse.y"
+#line 580 "parse.y"
 {yymsp[1].minor.yy387 = 0;}
-#line 2749 "parse.c"
+#line 2753 "parse.c"
         break;
       case 97: /* seltablist ::= stl_prefix nm as indexed_opt on_opt using_opt */
-#line 578 "parse.y"
+#line 582 "parse.y"
 {
   yymsp[-5].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy387,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,0,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   sqlite3SrcListIndexedBy(pParse, yymsp[-5].minor.yy387, &yymsp[-2].minor.yy0);
 }
-#line 2757 "parse.c"
+#line 2761 "parse.c"
         break;
       case 98: /* seltablist ::= stl_prefix nm LP exprlist RP as on_opt using_opt */
-#line 583 "parse.y"
+#line 587 "parse.y"
 {
   yymsp[-7].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-7].minor.yy387,&yymsp[-6].minor.yy0,&yymsp[-2].minor.yy0,0,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   sqlite3SrcListFuncArgs(pParse, yymsp[-7].minor.yy387, yymsp[-4].minor.yy382);
 }
-#line 2765 "parse.c"
+#line 2769 "parse.c"
         break;
       case 99: /* seltablist ::= stl_prefix LP select RP as on_opt using_opt */
-#line 589 "parse.y"
+#line 593 "parse.y"
 {
     yymsp[-6].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy387,0,&yymsp[-2].minor.yy0,yymsp[-4].minor.yy279,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
   }
-#line 2772 "parse.c"
+#line 2776 "parse.c"
         break;
       case 100: /* seltablist ::= stl_prefix LP seltablist RP as on_opt using_opt */
-#line 593 "parse.y"
+#line 597 "parse.y"
 {
     if( yymsp[-6].minor.yy387==0 && yymsp[-2].minor.yy0.n==0 && yymsp[-1].minor.yy362==0 && yymsp[0].minor.yy40==0 ){
       yymsp[-6].minor.yy387 = yymsp[-4].minor.yy387;
@@ -2793,135 +2797,135 @@ static void yy_reduce(
       yymsp[-6].minor.yy387 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-6].minor.yy387,0,&yymsp[-2].minor.yy0,pSubquery,yymsp[-1].minor.yy362,yymsp[0].minor.yy40);
     }
   }
-#line 2797 "parse.c"
+#line 2801 "parse.c"
         break;
       case 101: /* fullname ::= nm */
-#line 619 "parse.y"
+#line 623 "parse.y"
 {yymsp[0].minor.yy387 = sqlite3SrcListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-X*/}
-#line 2802 "parse.c"
+#line 2806 "parse.c"
         break;
       case 102: /* joinop ::= COMMA|JOIN */
-#line 625 "parse.y"
+#line 629 "parse.y"
 { yymsp[0].minor.yy52 = JT_INNER; }
-#line 2807 "parse.c"
+#line 2811 "parse.c"
         break;
       case 103: /* joinop ::= JOIN_KW JOIN */
-#line 627 "parse.y"
+#line 631 "parse.y"
 {yymsp[-1].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-1].minor.yy0,0,0);  /*X-overwrites-A*/}
-#line 2812 "parse.c"
+#line 2816 "parse.c"
         break;
       case 104: /* joinop ::= JOIN_KW join_nm JOIN */
-#line 629 "parse.y"
+#line 633 "parse.y"
 {yymsp[-2].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0,0); /*X-overwrites-A*/}
-#line 2817 "parse.c"
+#line 2821 "parse.c"
         break;
       case 105: /* joinop ::= JOIN_KW join_nm join_nm JOIN */
-#line 631 "parse.y"
+#line 635 "parse.y"
 {yymsp[-3].minor.yy52 = sqlite3JoinType(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);/*X-overwrites-A*/}
-#line 2822 "parse.c"
+#line 2826 "parse.c"
         break;
       case 106: /* on_opt ::= ON expr */
       case 123: /* having_opt ::= HAVING expr */ yytestcase(yyruleno==123);
       case 130: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==130);
       case 192: /* case_else ::= ELSE expr */ yytestcase(yyruleno==192);
-#line 635 "parse.y"
+#line 639 "parse.y"
 {yymsp[-1].minor.yy362 = yymsp[0].minor.yy162.pExpr;}
-#line 2830 "parse.c"
+#line 2834 "parse.c"
         break;
       case 107: /* on_opt ::= */
       case 122: /* having_opt ::= */ yytestcase(yyruleno==122);
       case 129: /* where_opt ::= */ yytestcase(yyruleno==129);
       case 193: /* case_else ::= */ yytestcase(yyruleno==193);
       case 195: /* case_operand ::= */ yytestcase(yyruleno==195);
-#line 636 "parse.y"
+#line 640 "parse.y"
 {yymsp[1].minor.yy362 = 0;}
-#line 2839 "parse.c"
+#line 2843 "parse.c"
         break;
       case 108: /* indexed_opt ::= */
-#line 649 "parse.y"
+#line 653 "parse.y"
 {yymsp[1].minor.yy0.z=0; yymsp[1].minor.yy0.n=0;}
-#line 2844 "parse.c"
+#line 2848 "parse.c"
         break;
       case 109: /* indexed_opt ::= INDEXED BY nm */
-#line 650 "parse.y"
+#line 654 "parse.y"
 {yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;}
-#line 2849 "parse.c"
+#line 2853 "parse.c"
         break;
       case 110: /* indexed_opt ::= NOT INDEXED */
-#line 651 "parse.y"
+#line 655 "parse.y"
 {yymsp[-1].minor.yy0.z=0; yymsp[-1].minor.yy0.n=1;}
-#line 2854 "parse.c"
+#line 2858 "parse.c"
         break;
       case 111: /* using_opt ::= USING LP idlist RP */
-#line 655 "parse.y"
+#line 659 "parse.y"
 {yymsp[-3].minor.yy40 = yymsp[-1].minor.yy40;}
-#line 2859 "parse.c"
+#line 2863 "parse.c"
         break;
       case 112: /* using_opt ::= */
       case 140: /* idlist_opt ::= */ yytestcase(yyruleno==140);
-#line 656 "parse.y"
+#line 660 "parse.y"
 {yymsp[1].minor.yy40 = 0;}
-#line 2865 "parse.c"
+#line 2869 "parse.c"
         break;
       case 114: /* orderby_opt ::= ORDER BY sortlist */
       case 121: /* groupby_opt ::= GROUP BY nexprlist */ yytestcase(yyruleno==121);
-#line 670 "parse.y"
+#line 674 "parse.y"
 {yymsp[-2].minor.yy382 = yymsp[0].minor.yy382;}
-#line 2871 "parse.c"
+#line 2875 "parse.c"
         break;
       case 115: /* sortlist ::= sortlist COMMA expr sortorder */
-#line 671 "parse.y"
+#line 675 "parse.y"
 {
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy382,yymsp[-1].minor.yy162.pExpr);
   sqlite3ExprListSetSortOrder(yymsp[-3].minor.yy382,yymsp[0].minor.yy52);
 }
-#line 2879 "parse.c"
+#line 2883 "parse.c"
         break;
       case 116: /* sortlist ::= expr sortorder */
-#line 675 "parse.y"
+#line 679 "parse.y"
 {
   yymsp[-1].minor.yy382 = sqlite3ExprListAppend(pParse,0,yymsp[-1].minor.yy162.pExpr); /*A-overwrites-Y*/
   sqlite3ExprListSetSortOrder(yymsp[-1].minor.yy382,yymsp[0].minor.yy52);
 }
-#line 2887 "parse.c"
+#line 2891 "parse.c"
         break;
       case 117: /* sortorder ::= ASC */
-#line 682 "parse.y"
+#line 686 "parse.y"
 {yymsp[0].minor.yy52 = SQLITE_SO_ASC;}
-#line 2892 "parse.c"
+#line 2896 "parse.c"
         break;
       case 118: /* sortorder ::= DESC */
-#line 683 "parse.y"
+#line 687 "parse.y"
 {yymsp[0].minor.yy52 = SQLITE_SO_DESC;}
-#line 2897 "parse.c"
+#line 2901 "parse.c"
         break;
       case 119: /* sortorder ::= */
-#line 684 "parse.y"
+#line 688 "parse.y"
 {yymsp[1].minor.yy52 = SQLITE_SO_UNDEFINED;}
-#line 2902 "parse.c"
+#line 2906 "parse.c"
         break;
       case 124: /* limit_opt ::= */
-#line 709 "parse.y"
+#line 713 "parse.y"
 {yymsp[1].minor.yy384.pLimit = 0; yymsp[1].minor.yy384.pOffset = 0;}
-#line 2907 "parse.c"
+#line 2911 "parse.c"
         break;
       case 125: /* limit_opt ::= LIMIT expr */
-#line 710 "parse.y"
+#line 714 "parse.y"
 {yymsp[-1].minor.yy384.pLimit = yymsp[0].minor.yy162.pExpr; yymsp[-1].minor.yy384.pOffset = 0;}
-#line 2912 "parse.c"
+#line 2916 "parse.c"
         break;
       case 126: /* limit_opt ::= LIMIT expr OFFSET expr */
-#line 712 "parse.y"
+#line 716 "parse.y"
 {yymsp[-3].minor.yy384.pLimit = yymsp[-2].minor.yy162.pExpr; yymsp[-3].minor.yy384.pOffset = yymsp[0].minor.yy162.pExpr;}
-#line 2917 "parse.c"
+#line 2921 "parse.c"
         break;
       case 127: /* limit_opt ::= LIMIT expr COMMA expr */
-#line 714 "parse.y"
+#line 718 "parse.y"
 {yymsp[-3].minor.yy384.pOffset = yymsp[-2].minor.yy162.pExpr; yymsp[-3].minor.yy384.pLimit = yymsp[0].minor.yy162.pExpr;}
-#line 2922 "parse.c"
+#line 2926 "parse.c"
         break;
       case 128: /* cmd ::= with DELETE FROM fullname indexed_opt where_opt */
-#line 731 "parse.y"
+#line 735 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy151, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-2].minor.yy387, &yymsp[-1].minor.yy0);
@@ -2930,10 +2934,10 @@ static void yy_reduce(
   pParse->initiateTTrans = true;
   sqlite3DeleteFrom(pParse,yymsp[-2].minor.yy387,yymsp[0].minor.yy362);
 }
-#line 2934 "parse.c"
+#line 2938 "parse.c"
         break;
       case 131: /* cmd ::= with UPDATE orconf fullname indexed_opt SET setlist where_opt */
-#line 764 "parse.y"
+#line 768 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-7].minor.yy151, 1);
   sqlite3SrcListIndexedBy(pParse, yymsp[-4].minor.yy387, &yymsp[-3].minor.yy0);
@@ -2943,41 +2947,41 @@ static void yy_reduce(
   pParse->initiateTTrans = true;
   sqlite3Update(pParse,yymsp[-4].minor.yy387,yymsp[-1].minor.yy382,yymsp[0].minor.yy362,yymsp[-5].minor.yy52);
 }
-#line 2947 "parse.c"
+#line 2951 "parse.c"
         break;
       case 132: /* setlist ::= setlist COMMA nm EQ expr */
-#line 778 "parse.y"
+#line 782 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse, yymsp[-4].minor.yy382, yymsp[0].minor.yy162.pExpr);
   sqlite3ExprListSetName(pParse, yymsp[-4].minor.yy382, &yymsp[-2].minor.yy0, 1);
 }
-#line 2955 "parse.c"
+#line 2959 "parse.c"
         break;
       case 133: /* setlist ::= setlist COMMA LP idlist RP EQ expr */
-#line 782 "parse.y"
+#line 786 "parse.y"
 {
   yymsp[-6].minor.yy382 = sqlite3ExprListAppendVector(pParse, yymsp[-6].minor.yy382, yymsp[-3].minor.yy40, yymsp[0].minor.yy162.pExpr);
 }
-#line 2962 "parse.c"
+#line 2966 "parse.c"
         break;
       case 134: /* setlist ::= nm EQ expr */
-#line 785 "parse.y"
+#line 789 "parse.y"
 {
   yylhsminor.yy382 = sqlite3ExprListAppend(pParse, 0, yymsp[0].minor.yy162.pExpr);
   sqlite3ExprListSetName(pParse, yylhsminor.yy382, &yymsp[-2].minor.yy0, 1);
 }
-#line 2970 "parse.c"
+#line 2974 "parse.c"
   yymsp[-2].minor.yy382 = yylhsminor.yy382;
         break;
       case 135: /* setlist ::= LP idlist RP EQ expr */
-#line 789 "parse.y"
+#line 793 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppendVector(pParse, 0, yymsp[-3].minor.yy40, yymsp[0].minor.yy162.pExpr);
 }
-#line 2978 "parse.c"
+#line 2982 "parse.c"
         break;
       case 136: /* cmd ::= with insert_cmd INTO fullname idlist_opt select */
-#line 795 "parse.y"
+#line 799 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-5].minor.yy151, 1);
   sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS;
@@ -2985,10 +2989,10 @@ static void yy_reduce(
   pParse->initiateTTrans = true;
   sqlite3Insert(pParse, yymsp[-2].minor.yy387, yymsp[0].minor.yy279, yymsp[-1].minor.yy40, yymsp[-4].minor.yy52);
 }
-#line 2989 "parse.c"
+#line 2993 "parse.c"
         break;
       case 137: /* cmd ::= with insert_cmd INTO fullname idlist_opt DEFAULT VALUES */
-#line 803 "parse.y"
+#line 807 "parse.y"
 {
   sqlite3WithPush(pParse, yymsp[-6].minor.yy151, 1);
   sqlSubProgramsRemaining = SQL_MAX_COMPILING_TRIGGERS;
@@ -2996,64 +3000,64 @@ static void yy_reduce(
   pParse->initiateTTrans = true;
   sqlite3Insert(pParse, yymsp[-3].minor.yy387, 0, yymsp[-2].minor.yy40, yymsp[-5].minor.yy52);
 }
-#line 3000 "parse.c"
+#line 3004 "parse.c"
         break;
       case 141: /* idlist_opt ::= LP idlist RP */
-#line 821 "parse.y"
+#line 825 "parse.y"
 {yymsp[-2].minor.yy40 = yymsp[-1].minor.yy40;}
-#line 3005 "parse.c"
+#line 3009 "parse.c"
         break;
       case 142: /* idlist ::= idlist COMMA nm */
-#line 823 "parse.y"
+#line 827 "parse.y"
 {yymsp[-2].minor.yy40 = sqlite3IdListAppend(pParse->db,yymsp[-2].minor.yy40,&yymsp[0].minor.yy0);}
-#line 3010 "parse.c"
+#line 3014 "parse.c"
         break;
       case 143: /* idlist ::= nm */
-#line 825 "parse.y"
+#line 829 "parse.y"
 {yymsp[0].minor.yy40 = sqlite3IdListAppend(pParse->db,0,&yymsp[0].minor.yy0); /*A-overwrites-Y*/}
-#line 3015 "parse.c"
+#line 3019 "parse.c"
         break;
       case 144: /* expr ::= LP expr RP */
-#line 874 "parse.y"
+#line 878 "parse.y"
 {spanSet(&yymsp[-2].minor.yy162,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/  yymsp[-2].minor.yy162.pExpr = yymsp[-1].minor.yy162.pExpr;}
-#line 3020 "parse.c"
+#line 3024 "parse.c"
         break;
       case 145: /* term ::= NULL */
       case 149: /* term ::= FLOAT|BLOB */ yytestcase(yyruleno==149);
       case 150: /* term ::= STRING */ yytestcase(yyruleno==150);
-#line 875 "parse.y"
+#line 879 "parse.y"
 {spanExpr(&yymsp[0].minor.yy162,pParse,yymsp[0].major,yymsp[0].minor.yy0);/*A-overwrites-X*/}
-#line 3027 "parse.c"
+#line 3031 "parse.c"
         break;
       case 146: /* expr ::= ID|INDEXED */
       case 147: /* expr ::= JOIN_KW */ yytestcase(yyruleno==147);
-#line 876 "parse.y"
+#line 880 "parse.y"
 {spanExpr(&yymsp[0].minor.yy162,pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
-#line 3033 "parse.c"
+#line 3037 "parse.c"
         break;
       case 148: /* expr ::= nm DOT nm */
-#line 878 "parse.y"
+#line 882 "parse.y"
 {
   Expr *temp1 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[-2].minor.yy0, 1);
   Expr *temp2 = sqlite3ExprAlloc(pParse->db, TK_ID, &yymsp[0].minor.yy0, 1);
   spanSet(&yymsp[-2].minor.yy162,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
   yymsp[-2].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2);
 }
-#line 3043 "parse.c"
+#line 3047 "parse.c"
         break;
       case 151: /* term ::= INTEGER */
-#line 886 "parse.y"
+#line 890 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
   yylhsminor.yy162.zStart = yymsp[0].minor.yy0.z;
   yylhsminor.yy162.zEnd = yymsp[0].minor.yy0.z + yymsp[0].minor.yy0.n;
   if( yylhsminor.yy162.pExpr ) yylhsminor.yy162.pExpr->flags |= EP_Leaf;
 }
-#line 3053 "parse.c"
+#line 3057 "parse.c"
   yymsp[0].minor.yy162 = yylhsminor.yy162;
         break;
       case 152: /* expr ::= VARIABLE */
-#line 892 "parse.y"
+#line 896 "parse.y"
 {
   if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
     u32 n = yymsp[0].minor.yy0.n;
@@ -3075,27 +3079,27 @@ static void yy_reduce(
     }
   }
 }
-#line 3079 "parse.c"
+#line 3083 "parse.c"
         break;
       case 153: /* expr ::= expr COLLATE ID|INDEXED */
-#line 913 "parse.y"
+#line 917 "parse.y"
 {
   yymsp[-2].minor.yy162.pExpr = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy162.pExpr, &yymsp[0].minor.yy0, 1);
   yymsp[-2].minor.yy162.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
 }
-#line 3087 "parse.c"
+#line 3091 "parse.c"
         break;
       case 154: /* expr ::= CAST LP expr AS typetoken RP */
-#line 918 "parse.y"
+#line 922 "parse.y"
 {
   spanSet(&yymsp[-5].minor.yy162,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-X*/
   yymsp[-5].minor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
   sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy162.pExpr, yymsp[-3].minor.yy162.pExpr, 0);
 }
-#line 3096 "parse.c"
+#line 3100 "parse.c"
         break;
       case 155: /* expr ::= ID|INDEXED LP distinct exprlist RP */
-#line 924 "parse.y"
+#line 928 "parse.y"
 {
   if( yymsp[-1].minor.yy382 && yymsp[-1].minor.yy382->nExpr>pParse->db->aLimit[SQLITE_LIMIT_FUNCTION_ARG] ){
     sqlite3ErrorMsg(pParse, "too many arguments on function %T", &yymsp[-4].minor.yy0);
@@ -3106,29 +3110,29 @@ static void yy_reduce(
     yylhsminor.yy162.pExpr->flags |= EP_Distinct;
   }
 }
-#line 3110 "parse.c"
+#line 3114 "parse.c"
   yymsp[-4].minor.yy162 = yylhsminor.yy162;
         break;
       case 156: /* expr ::= ID|INDEXED LP STAR RP */
-#line 934 "parse.y"
+#line 938 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0);
   spanSet(&yylhsminor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);
 }
-#line 3119 "parse.c"
+#line 3123 "parse.c"
   yymsp[-3].minor.yy162 = yylhsminor.yy162;
         break;
       case 157: /* term ::= CTIME_KW */
-#line 938 "parse.y"
+#line 942 "parse.y"
 {
   yylhsminor.yy162.pExpr = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0);
   spanSet(&yylhsminor.yy162, &yymsp[0].minor.yy0, &yymsp[0].minor.yy0);
 }
-#line 3128 "parse.c"
+#line 3132 "parse.c"
   yymsp[0].minor.yy162 = yylhsminor.yy162;
         break;
       case 158: /* expr ::= LP nexprlist COMMA expr RP */
-#line 967 "parse.y"
+#line 971 "parse.y"
 {
   ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy382, yymsp[-1].minor.yy162.pExpr);
   yylhsminor.yy162.pExpr = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -3139,7 +3143,7 @@ static void yy_reduce(
     sqlite3ExprListDelete(pParse->db, pList);
   }
 }
-#line 3143 "parse.c"
+#line 3147 "parse.c"
   yymsp[-4].minor.yy162 = yylhsminor.yy162;
         break;
       case 159: /* expr ::= expr AND expr */
@@ -3150,22 +3154,22 @@ static void yy_reduce(
       case 164: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==164);
       case 165: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==165);
       case 166: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==166);
-#line 978 "parse.y"
+#line 982 "parse.y"
 {spanBinaryExpr(pParse,yymsp[-1].major,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy162);}
-#line 3156 "parse.c"
+#line 3160 "parse.c"
         break;
       case 167: /* likeop ::= LIKE_KW|MATCH */
-#line 991 "parse.y"
+#line 995 "parse.y"
 {yymsp[0].minor.yy0=yymsp[0].minor.yy0;/*A-overwrites-X*/}
-#line 3161 "parse.c"
+#line 3165 "parse.c"
         break;
       case 168: /* likeop ::= NOT LIKE_KW|MATCH */
-#line 992 "parse.y"
+#line 996 "parse.y"
 {yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
-#line 3166 "parse.c"
+#line 3170 "parse.c"
         break;
       case 169: /* expr ::= expr likeop expr */
-#line 993 "parse.y"
+#line 997 "parse.y"
 {
   ExprList *pList;
   int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
@@ -3177,10 +3181,10 @@ static void yy_reduce(
   yymsp[-2].minor.yy162.zEnd = yymsp[0].minor.yy162.zEnd;
   if( yymsp[-2].minor.yy162.pExpr ) yymsp[-2].minor.yy162.pExpr->flags |= EP_InfixFunc;
 }
-#line 3181 "parse.c"
+#line 3185 "parse.c"
         break;
       case 170: /* expr ::= expr likeop expr ESCAPE expr */
-#line 1004 "parse.y"
+#line 1008 "parse.y"
 {
   ExprList *pList;
   int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
@@ -3193,58 +3197,58 @@ static void yy_reduce(
   yymsp[-4].minor.yy162.zEnd = yymsp[0].minor.yy162.zEnd;
   if( yymsp[-4].minor.yy162.pExpr ) yymsp[-4].minor.yy162.pExpr->flags |= EP_InfixFunc;
 }
-#line 3197 "parse.c"
+#line 3201 "parse.c"
         break;
       case 171: /* expr ::= expr ISNULL|NOTNULL */
-#line 1031 "parse.y"
+#line 1035 "parse.y"
 {spanUnaryPostfix(pParse,yymsp[0].major,&yymsp[-1].minor.yy162,&yymsp[0].minor.yy0);}
-#line 3202 "parse.c"
+#line 3206 "parse.c"
         break;
       case 172: /* expr ::= expr NOT NULL */
-#line 1032 "parse.y"
+#line 1036 "parse.y"
 {spanUnaryPostfix(pParse,TK_NOTNULL,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy0);}
-#line 3207 "parse.c"
+#line 3211 "parse.c"
         break;
       case 173: /* expr ::= expr IS expr */
-#line 1053 "parse.y"
+#line 1057 "parse.y"
 {
   spanBinaryExpr(pParse,TK_IS,&yymsp[-2].minor.yy162,&yymsp[0].minor.yy162);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy162.pExpr, yymsp[-2].minor.yy162.pExpr, TK_ISNULL);
 }
-#line 3215 "parse.c"
+#line 3219 "parse.c"
         break;
       case 174: /* expr ::= expr IS NOT expr */
-#line 1057 "parse.y"
+#line 1061 "parse.y"
 {
   spanBinaryExpr(pParse,TK_ISNOT,&yymsp[-3].minor.yy162,&yymsp[0].minor.yy162);
   binaryToUnaryIfNull(pParse, yymsp[0].minor.yy162.pExpr, yymsp[-3].minor.yy162.pExpr, TK_NOTNULL);
 }
-#line 3223 "parse.c"
+#line 3227 "parse.c"
         break;
       case 175: /* expr ::= NOT expr */
       case 176: /* expr ::= BITNOT expr */ yytestcase(yyruleno==176);
-#line 1081 "parse.y"
+#line 1085 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,yymsp[-1].major,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
-#line 3229 "parse.c"
+#line 3233 "parse.c"
         break;
       case 177: /* expr ::= MINUS expr */
-#line 1085 "parse.y"
+#line 1089 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,TK_UMINUS,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
-#line 3234 "parse.c"
+#line 3238 "parse.c"
         break;
       case 178: /* expr ::= PLUS expr */
-#line 1087 "parse.y"
+#line 1091 "parse.y"
 {spanUnaryPrefix(&yymsp[-1].minor.yy162,pParse,TK_UPLUS,&yymsp[0].minor.yy162,&yymsp[-1].minor.yy0);/*A-overwrites-B*/}
-#line 3239 "parse.c"
+#line 3243 "parse.c"
         break;
       case 179: /* between_op ::= BETWEEN */
       case 182: /* in_op ::= IN */ yytestcase(yyruleno==182);
-#line 1090 "parse.y"
+#line 1094 "parse.y"
 {yymsp[0].minor.yy52 = 0;}
-#line 3245 "parse.c"
+#line 3249 "parse.c"
         break;
       case 181: /* expr ::= expr between_op expr AND expr */
-#line 1092 "parse.y"
+#line 1096 "parse.y"
 {
   ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy162.pExpr);
   pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy162.pExpr);
@@ -3257,10 +3261,10 @@ static void yy_reduce(
   exprNot(pParse, yymsp[-3].minor.yy52, &yymsp[-4].minor.yy162);
   yymsp[-4].minor.yy162.zEnd = yymsp[0].minor.yy162.zEnd;
 }
-#line 3261 "parse.c"
+#line 3265 "parse.c"
         break;
       case 184: /* expr ::= expr in_op LP exprlist RP */
-#line 1108 "parse.y"
+#line 1112 "parse.y"
 {
     if( yymsp[-1].minor.yy382==0 ){
       /* Expressions of the form
@@ -3312,29 +3316,29 @@ static void yy_reduce(
     }
     yymsp[-4].minor.yy162.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
-#line 3316 "parse.c"
+#line 3320 "parse.c"
         break;
       case 185: /* expr ::= LP select RP */
-#line 1159 "parse.y"
+#line 1163 "parse.y"
 {
     spanSet(&yymsp[-2].minor.yy162,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
     yymsp[-2].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
     sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy162.pExpr, yymsp[-1].minor.yy279);
   }
-#line 3325 "parse.c"
+#line 3329 "parse.c"
         break;
       case 186: /* expr ::= expr in_op LP select RP */
-#line 1164 "parse.y"
+#line 1168 "parse.y"
 {
     yymsp[-4].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy162.pExpr, 0);
     sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy162.pExpr, yymsp[-1].minor.yy279);
     exprNot(pParse, yymsp[-3].minor.yy52, &yymsp[-4].minor.yy162);
     yymsp[-4].minor.yy162.zEnd = &yymsp[0].minor.yy0.z[yymsp[0].minor.yy0.n];
   }
-#line 3335 "parse.c"
+#line 3339 "parse.c"
         break;
       case 187: /* expr ::= expr in_op nm paren_exprlist */
-#line 1170 "parse.y"
+#line 1174 "parse.y"
 {
     SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&yymsp[-1].minor.yy0);
     Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
@@ -3344,20 +3348,20 @@ static void yy_reduce(
     exprNot(pParse, yymsp[-2].minor.yy52, &yymsp[-3].minor.yy162);
     yymsp[-3].minor.yy162.zEnd = &yymsp[-1].minor.yy0.z[yymsp[-1].minor.yy0.n];
   }
-#line 3348 "parse.c"
+#line 3352 "parse.c"
         break;
       case 188: /* expr ::= EXISTS LP select RP */
-#line 1179 "parse.y"
+#line 1183 "parse.y"
 {
     Expr *p;
     spanSet(&yymsp[-3].minor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0); /*A-overwrites-B*/
     p = yymsp[-3].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
     sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy279);
   }
-#line 3358 "parse.c"
+#line 3362 "parse.c"
         break;
       case 189: /* expr ::= CASE case_operand case_exprlist case_else END */
-#line 1188 "parse.y"
+#line 1192 "parse.y"
 {
   spanSet(&yymsp[-4].minor.yy162,&yymsp[-4].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-C*/
   yymsp[-4].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy362, 0);
@@ -3369,137 +3373,137 @@ static void yy_reduce(
     sql_expr_free(pParse->db, yymsp[-1].minor.yy362, false);
   }
 }
-#line 3373 "parse.c"
+#line 3377 "parse.c"
         break;
       case 190: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
-#line 1201 "parse.y"
+#line 1205 "parse.y"
 {
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy382, yymsp[-2].minor.yy162.pExpr);
   yymsp[-4].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy382, yymsp[0].minor.yy162.pExpr);
 }
-#line 3381 "parse.c"
+#line 3385 "parse.c"
         break;
       case 191: /* case_exprlist ::= WHEN expr THEN expr */
-#line 1205 "parse.y"
+#line 1209 "parse.y"
 {
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy162.pExpr);
   yymsp[-3].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy382, yymsp[0].minor.yy162.pExpr);
 }
-#line 3389 "parse.c"
+#line 3393 "parse.c"
         break;
       case 194: /* case_operand ::= expr */
-#line 1215 "parse.y"
+#line 1219 "parse.y"
 {yymsp[0].minor.yy362 = yymsp[0].minor.yy162.pExpr; /*A-overwrites-X*/}
-#line 3394 "parse.c"
+#line 3398 "parse.c"
         break;
       case 197: /* nexprlist ::= nexprlist COMMA expr */
-#line 1226 "parse.y"
+#line 1230 "parse.y"
 {yymsp[-2].minor.yy382 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy382,yymsp[0].minor.yy162.pExpr);}
-#line 3399 "parse.c"
+#line 3403 "parse.c"
         break;
       case 198: /* nexprlist ::= expr */
-#line 1228 "parse.y"
+#line 1232 "parse.y"
 {yymsp[0].minor.yy382 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy162.pExpr); /*A-overwrites-Y*/}
-#line 3404 "parse.c"
+#line 3408 "parse.c"
         break;
       case 200: /* paren_exprlist ::= LP exprlist RP */
       case 205: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==205);
-#line 1236 "parse.y"
+#line 1240 "parse.y"
 {yymsp[-2].minor.yy382 = yymsp[-1].minor.yy382;}
-#line 3410 "parse.c"
+#line 3414 "parse.c"
         break;
       case 201: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm ON nm LP sortlist RP where_opt */
-#line 1243 "parse.y"
+#line 1247 "parse.y"
 {
   sqlite3CreateIndex(pParse, &yymsp[-6].minor.yy0, 
                      sqlite3SrcListAppend(pParse->db,0,&yymsp[-4].minor.yy0), yymsp[-2].minor.yy382, yymsp[-9].minor.yy52,
                       &yymsp[-10].minor.yy0, yymsp[0].minor.yy362, SQLITE_SO_ASC, yymsp[-7].minor.yy52, SQLITE_IDXTYPE_APPDEF);
 }
-#line 3419 "parse.c"
+#line 3423 "parse.c"
         break;
       case 202: /* uniqueflag ::= UNIQUE */
       case 243: /* raisetype ::= ABORT */ yytestcase(yyruleno==243);
-#line 1250 "parse.y"
+#line 1254 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_ABORT;}
-#line 3425 "parse.c"
+#line 3429 "parse.c"
         break;
       case 203: /* uniqueflag ::= */
-#line 1251 "parse.y"
+#line 1255 "parse.y"
 {yymsp[1].minor.yy52 = ON_CONFLICT_ACTION_NONE;}
-#line 3430 "parse.c"
+#line 3434 "parse.c"
         break;
       case 206: /* eidlist ::= eidlist COMMA nm collate sortorder */
-#line 1294 "parse.y"
+#line 1298 "parse.y"
 {
   yymsp[-4].minor.yy382 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy382, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy52, yymsp[0].minor.yy52);
 }
-#line 3437 "parse.c"
+#line 3441 "parse.c"
         break;
       case 207: /* eidlist ::= nm collate sortorder */
-#line 1297 "parse.y"
+#line 1301 "parse.y"
 {
   yymsp[-2].minor.yy382 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy52, yymsp[0].minor.yy52); /*A-overwrites-Y*/
 }
-#line 3444 "parse.c"
+#line 3448 "parse.c"
         break;
       case 210: /* cmd ::= DROP INDEX ifexists fullname ON nm */
-#line 1308 "parse.y"
+#line 1312 "parse.y"
 {
     sqlite3DropIndex(pParse, yymsp[-2].minor.yy387, &yymsp[0].minor.yy0, yymsp[-3].minor.yy52);
 }
-#line 3451 "parse.c"
+#line 3455 "parse.c"
         break;
       case 211: /* cmd ::= PRAGMA nm */
-#line 1315 "parse.y"
+#line 1319 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[0].minor.yy0,0,0,0,0);
 }
-#line 3458 "parse.c"
+#line 3462 "parse.c"
         break;
       case 212: /* cmd ::= PRAGMA nm EQ nmnum */
-#line 1318 "parse.y"
+#line 1322 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy0,0,0);
 }
-#line 3465 "parse.c"
+#line 3469 "parse.c"
         break;
       case 213: /* cmd ::= PRAGMA nm LP nmnum RP */
-#line 1321 "parse.y"
+#line 1325 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,0,&yymsp[-1].minor.yy0,0,0);
 }
-#line 3472 "parse.c"
+#line 3476 "parse.c"
         break;
       case 214: /* cmd ::= PRAGMA nm EQ minus_num */
-#line 1324 "parse.y"
+#line 1328 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-2].minor.yy0,0,&yymsp[0].minor.yy0,0,1);
 }
-#line 3479 "parse.c"
+#line 3483 "parse.c"
         break;
       case 215: /* cmd ::= PRAGMA nm LP minus_num RP */
-#line 1327 "parse.y"
+#line 1331 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,0,&yymsp[-1].minor.yy0,0,1);
 }
-#line 3486 "parse.c"
+#line 3490 "parse.c"
         break;
       case 216: /* cmd ::= PRAGMA nm EQ nm DOT nm */
-#line 1330 "parse.y"
+#line 1334 "parse.y"
 {
     sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,0,&yymsp[0].minor.yy0,&yymsp[-2].minor.yy0,0);
 }
-#line 3493 "parse.c"
+#line 3497 "parse.c"
         break;
       case 217: /* cmd ::= PRAGMA */
-#line 1333 "parse.y"
+#line 1337 "parse.y"
 {
     sqlite3Pragma(pParse, 0,0,0,0,0);
 }
-#line 3500 "parse.c"
+#line 3504 "parse.c"
         break;
       case 220: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
-#line 1351 "parse.y"
+#line 1355 "parse.y"
 {
   Token all;
   all.z = yymsp[-3].minor.yy0.z;
@@ -3507,124 +3511,124 @@ static void yy_reduce(
   pParse->initiateTTrans = false;
   sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy427, &all);
 }
-#line 3511 "parse.c"
+#line 3515 "parse.c"
         break;
       case 221: /* trigger_decl ::= TRIGGER ifnotexists nm trigger_time trigger_event ON fullname foreach_clause when_clause */
-#line 1361 "parse.y"
+#line 1365 "parse.y"
 {
   sqlite3BeginTrigger(pParse, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy52, yymsp[-4].minor.yy10.a, yymsp[-4].minor.yy10.b, yymsp[-2].minor.yy387, yymsp[0].minor.yy362, yymsp[-7].minor.yy52);
   yymsp[-8].minor.yy0 = yymsp[-6].minor.yy0; /*yymsp[-8].minor.yy0-overwrites-T*/
 }
-#line 3519 "parse.c"
+#line 3523 "parse.c"
         break;
       case 222: /* trigger_time ::= BEFORE */
-#line 1367 "parse.y"
+#line 1371 "parse.y"
 { yymsp[0].minor.yy52 = TK_BEFORE; }
-#line 3524 "parse.c"
+#line 3528 "parse.c"
         break;
       case 223: /* trigger_time ::= AFTER */
-#line 1368 "parse.y"
+#line 1372 "parse.y"
 { yymsp[0].minor.yy52 = TK_AFTER;  }
-#line 3529 "parse.c"
+#line 3533 "parse.c"
         break;
       case 224: /* trigger_time ::= INSTEAD OF */
-#line 1369 "parse.y"
+#line 1373 "parse.y"
 { yymsp[-1].minor.yy52 = TK_INSTEAD;}
-#line 3534 "parse.c"
+#line 3538 "parse.c"
         break;
       case 225: /* trigger_time ::= */
-#line 1370 "parse.y"
+#line 1374 "parse.y"
 { yymsp[1].minor.yy52 = TK_BEFORE; }
-#line 3539 "parse.c"
+#line 3543 "parse.c"
         break;
       case 226: /* trigger_event ::= DELETE|INSERT */
       case 227: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==227);
-#line 1374 "parse.y"
+#line 1378 "parse.y"
 {yymsp[0].minor.yy10.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy10.b = 0;}
-#line 3545 "parse.c"
+#line 3549 "parse.c"
         break;
       case 228: /* trigger_event ::= UPDATE OF idlist */
-#line 1376 "parse.y"
+#line 1380 "parse.y"
 {yymsp[-2].minor.yy10.a = TK_UPDATE; yymsp[-2].minor.yy10.b = yymsp[0].minor.yy40;}
-#line 3550 "parse.c"
+#line 3554 "parse.c"
         break;
       case 229: /* when_clause ::= */
-#line 1383 "parse.y"
+#line 1387 "parse.y"
 { yymsp[1].minor.yy362 = 0; }
-#line 3555 "parse.c"
+#line 3559 "parse.c"
         break;
       case 230: /* when_clause ::= WHEN expr */
-#line 1384 "parse.y"
+#line 1388 "parse.y"
 { yymsp[-1].minor.yy362 = yymsp[0].minor.yy162.pExpr; }
-#line 3560 "parse.c"
+#line 3564 "parse.c"
         break;
       case 231: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
-#line 1388 "parse.y"
+#line 1392 "parse.y"
 {
   assert( yymsp[-2].minor.yy427!=0 );
   yymsp[-2].minor.yy427->pLast->pNext = yymsp[-1].minor.yy427;
   yymsp[-2].minor.yy427->pLast = yymsp[-1].minor.yy427;
 }
-#line 3569 "parse.c"
+#line 3573 "parse.c"
         break;
       case 232: /* trigger_cmd_list ::= trigger_cmd SEMI */
-#line 1393 "parse.y"
+#line 1397 "parse.y"
 { 
   assert( yymsp[-1].minor.yy427!=0 );
   yymsp[-1].minor.yy427->pLast = yymsp[-1].minor.yy427;
 }
-#line 3577 "parse.c"
+#line 3581 "parse.c"
         break;
       case 233: /* trnm ::= nm DOT nm */
-#line 1404 "parse.y"
+#line 1408 "parse.y"
 {
   yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
   sqlite3ErrorMsg(pParse, 
         "qualified table names are not allowed on INSERT, UPDATE, and DELETE "
         "statements within triggers");
 }
-#line 3587 "parse.c"
+#line 3591 "parse.c"
         break;
       case 234: /* tridxby ::= INDEXED BY nm */
-#line 1416 "parse.y"
+#line 1420 "parse.y"
 {
   sqlite3ErrorMsg(pParse,
         "the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
-#line 3596 "parse.c"
+#line 3600 "parse.c"
         break;
       case 235: /* tridxby ::= NOT INDEXED */
-#line 1421 "parse.y"
+#line 1425 "parse.y"
 {
   sqlite3ErrorMsg(pParse,
         "the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
         "within triggers");
 }
-#line 3605 "parse.c"
+#line 3609 "parse.c"
         break;
       case 236: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist where_opt */
-#line 1434 "parse.y"
+#line 1438 "parse.y"
 {yymsp[-6].minor.yy427 = sqlite3TriggerUpdateStep(pParse->db, &yymsp[-4].minor.yy0, yymsp[-1].minor.yy382, yymsp[0].minor.yy362, yymsp[-5].minor.yy52);}
-#line 3610 "parse.c"
+#line 3614 "parse.c"
         break;
       case 237: /* trigger_cmd ::= insert_cmd INTO trnm idlist_opt select */
-#line 1438 "parse.y"
+#line 1442 "parse.y"
 {yymsp[-4].minor.yy427 = sqlite3TriggerInsertStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy40, yymsp[0].minor.yy279, yymsp[-4].minor.yy52);/*A-overwrites-R*/}
-#line 3615 "parse.c"
+#line 3619 "parse.c"
         break;
       case 238: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt */
-#line 1442 "parse.y"
+#line 1446 "parse.y"
 {yymsp[-4].minor.yy427 = sqlite3TriggerDeleteStep(pParse->db, &yymsp[-2].minor.yy0, yymsp[0].minor.yy362);}
-#line 3620 "parse.c"
+#line 3624 "parse.c"
         break;
       case 239: /* trigger_cmd ::= select */
-#line 1446 "parse.y"
+#line 1450 "parse.y"
 {yymsp[0].minor.yy427 = sqlite3TriggerSelectStep(pParse->db, yymsp[0].minor.yy279); /*A-overwrites-X*/}
-#line 3625 "parse.c"
+#line 3629 "parse.c"
         break;
       case 240: /* expr ::= RAISE LP IGNORE RP */
-#line 1449 "parse.y"
+#line 1453 "parse.y"
 {
   spanSet(&yymsp[-3].minor.yy162,&yymsp[-3].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-X*/
   yymsp[-3].minor.yy162.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0); 
@@ -3632,10 +3636,10 @@ static void yy_reduce(
     yymsp[-3].minor.yy162.pExpr->affinity = ON_CONFLICT_ACTION_IGNORE;
   }
 }
-#line 3636 "parse.c"
+#line 3640 "parse.c"
         break;
       case 241: /* expr ::= RAISE LP raisetype COMMA STRING RP */
-#line 1456 "parse.y"
+#line 1460 "parse.y"
 {
   spanSet(&yymsp[-5].minor.yy162,&yymsp[-5].minor.yy0,&yymsp[0].minor.yy0);  /*A-overwrites-X*/
   yymsp[-5].minor.yy162.pExpr = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1); 
@@ -3643,85 +3647,85 @@ static void yy_reduce(
     yymsp[-5].minor.yy162.pExpr->affinity = (char)yymsp[-3].minor.yy52;
   }
 }
-#line 3647 "parse.c"
+#line 3651 "parse.c"
         break;
       case 242: /* raisetype ::= ROLLBACK */
-#line 1465 "parse.y"
+#line 1469 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_ROLLBACK;}
-#line 3652 "parse.c"
+#line 3656 "parse.c"
         break;
       case 244: /* raisetype ::= FAIL */
-#line 1467 "parse.y"
+#line 1471 "parse.y"
 {yymsp[0].minor.yy52 = ON_CONFLICT_ACTION_FAIL;}
-#line 3657 "parse.c"
+#line 3661 "parse.c"
         break;
       case 245: /* cmd ::= DROP TRIGGER ifexists fullname */
-#line 1471 "parse.y"
+#line 1475 "parse.y"
 {
   sqlite3DropTrigger(pParse,yymsp[0].minor.yy387,yymsp[-1].minor.yy52);
 }
-#line 3664 "parse.c"
+#line 3668 "parse.c"
         break;
       case 246: /* cmd ::= REINDEX */
-#line 1477 "parse.y"
+#line 1481 "parse.y"
 {sqlite3Reindex(pParse, 0, 0);}
-#line 3669 "parse.c"
+#line 3673 "parse.c"
         break;
       case 247: /* cmd ::= REINDEX nm */
-#line 1478 "parse.y"
+#line 1482 "parse.y"
 {sqlite3Reindex(pParse, &yymsp[0].minor.yy0, 0);}
-#line 3674 "parse.c"
+#line 3678 "parse.c"
         break;
       case 248: /* cmd ::= REINDEX nm ON nm */
-#line 1479 "parse.y"
+#line 1483 "parse.y"
 {sqlite3Reindex(pParse, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);}
-#line 3679 "parse.c"
+#line 3683 "parse.c"
         break;
       case 249: /* cmd ::= ANALYZE */
-#line 1484 "parse.y"
+#line 1488 "parse.y"
 {sqlite3Analyze(pParse, 0);}
-#line 3684 "parse.c"
+#line 3688 "parse.c"
         break;
       case 250: /* cmd ::= ANALYZE nm */
-#line 1485 "parse.y"
+#line 1489 "parse.y"
 {sqlite3Analyze(pParse, &yymsp[0].minor.yy0);}
-#line 3689 "parse.c"
+#line 3693 "parse.c"
         break;
       case 251: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
-#line 1490 "parse.y"
+#line 1494 "parse.y"
 {
   sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy387,&yymsp[0].minor.yy0);
 }
-#line 3696 "parse.c"
+#line 3700 "parse.c"
         break;
       case 252: /* with ::= */
-#line 1513 "parse.y"
+#line 1517 "parse.y"
 {yymsp[1].minor.yy151 = 0;}
-#line 3701 "parse.c"
+#line 3705 "parse.c"
         break;
       case 253: /* with ::= WITH wqlist */
-#line 1515 "parse.y"
+#line 1519 "parse.y"
 { yymsp[-1].minor.yy151 = yymsp[0].minor.yy151; }
-#line 3706 "parse.c"
+#line 3710 "parse.c"
         break;
       case 254: /* with ::= WITH RECURSIVE wqlist */
-#line 1516 "parse.y"
+#line 1520 "parse.y"
 { yymsp[-2].minor.yy151 = yymsp[0].minor.yy151; }
-#line 3711 "parse.c"
+#line 3715 "parse.c"
         break;
       case 255: /* wqlist ::= nm eidlist_opt AS LP select RP */
-#line 1518 "parse.y"
+#line 1522 "parse.y"
 {
   yymsp[-5].minor.yy151 = sqlite3WithAdd(pParse, 0, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy382, yymsp[-1].minor.yy279); /*A-overwrites-X*/
 }
-#line 3718 "parse.c"
+#line 3722 "parse.c"
         break;
       case 256: /* wqlist ::= wqlist COMMA nm eidlist_opt AS LP select RP */
-#line 1521 "parse.y"
+#line 1525 "parse.y"
 {
   yymsp[-7].minor.yy151 = sqlite3WithAdd(pParse, yymsp[-7].minor.yy151, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy382, yymsp[-1].minor.yy279);
 }
-#line 3725 "parse.c"
+#line 3729 "parse.c"
         break;
       default:
       /* (257) input ::= ecmd */ yytestcase(yyruleno==257);
@@ -3832,7 +3836,7 @@ static void yy_syntax_error(
   } else {
     sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
   }
-#line 3836 "parse.c"
+#line 3840 "parse.c"
 /************ End %syntax_error code ******************************************/
   sqlite3ParserARG_STORE; /* Suppress warning about unused %extra_argument variable */
 }
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 7fc19bded..e2f8abc80 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -369,7 +369,11 @@ ifexists(A) ::= .            {A = 0;}
 //
 cmd ::= createkw(X) VIEW ifnotexists(E) nm(Y) eidlist_opt(C)
           AS select(S). {
-  sqlite3CreateView(pParse, &X, &Y, C, S, E);
+  if (!pParse->parse_only)
+    sqlite3CreateView(pParse, &X, &Y, C, S, E);
+  else {
+    sql_store_select(pParse, S);
+  }
 }
 cmd ::= DROP VIEW ifexists(E) fullname(X). {
   sqlite3DropTable(pParse, X, 1, E);
diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c
index 8aa96119f..547ca0afc 100644
--- a/src/box/sql/pragma.c
+++ b/src/box/sql/pragma.c
@@ -357,7 +357,7 @@ sqlite3Pragma(Parse * pParse, Token * pId,	/* First part of [schema.]id field */
 				Index *pPk = sqlite3PrimaryKeyIndex(pTab);
 				pParse->nMem = 6;
 				sqlite3CodeVerifySchema(pParse);
-				sqlite3ViewGetColumnNames(pParse, pTab);
+				sql_view_column_names(pParse, pTab);
 				for (i = 0, pCol = pTab->aCol; i < pTab->nCol;
 				     i++, pCol++) {
 					if (!table_column_is_in_pk(pTab, i)) {
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 44863b394..1f23cb568 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -35,6 +35,8 @@
  */
 #include <box/coll.h>
 #include "sqliteInt.h"
+#include "tarantoolInt.h"
+#include "box/schema.h"
 #include "box/session.h"
 
 /*
@@ -1921,99 +1923,88 @@ sqlite3ColumnsFromExprList(Parse * pParse,	/* Parsing context */
 	return SQLITE_OK;
 }
 
-/*
+/**
  * Add type and collation information to a column list based on
  * a SELECT statement.
  *
- * The column list presumably came from selectColumnNamesFromExprList().
- * The column list has only names, not types or collations.  This
- * routine goes through and adds the types and collations.
- *
+ * The column list presumably came from columnsFromExprList().
+ * The column list has only names, not types or collations.
+ * This routine goes through and adds the types and collations.
  * This routine requires that all identifiers in the SELECT
  * statement be resolved.
+ *
+ * @param parse_context Current parsing context.
+ * @param[out] table Add column type information to this table.
+ * @param select SELECT used to determine types and collations.
  */
 void
-sqlite3SelectAddColumnTypeAndCollation(Parse * pParse,		/* Parsing contexts */
-				       Table * pTab,		/* Add column type information to this table */
-				       Select * pSelect)	/* SELECT used to determine types and collations */
+sql_select_add_column_properties(struct Parse *parse_context,
+				 struct Table *table, struct Select *select)
 {
-	sqlite3 *db = pParse->db;
-	NameContext sNC;
-	Column *pCol;
-	struct coll *pColl;
-	int i;
-	Expr *p;
-	struct ExprList_item *a;
-	u64 szAll = 0;
-
-	assert(pSelect != 0);
-	assert((pSelect->selFlags & SF_Resolved) != 0);
-	assert(pTab->nCol == pSelect->pEList->nExpr || db->mallocFailed);
-	if (db->mallocFailed)
-		return;
-	memset(&sNC, 0, sizeof(sNC));
-	sNC.pSrcList = pSelect->pSrc;
-	a = pSelect->pEList->a;
-	for (i = 0, pCol = pTab->aCol; i < pTab->nCol; i++, pCol++) {
-		enum field_type type;
-		p = a[i].pExpr;
-		type = columnType(&sNC, p, 0, 0, 0, &pCol->szEst);
-		szAll += pCol->szEst;
-		pCol->affinity = sqlite3ExprAffinity(p);
-		pCol->type = type;
-
-		if (pCol->affinity == 0)
-			pCol->affinity = SQLITE_AFF_BLOB;
-		pColl = sqlite3ExprCollSeq(pParse, p);
-		if (pColl && pCol->zColl == 0) {
-			pCol->zColl = sqlite3DbStrDup(db, pColl->name);
-		}
-	}
-	pTab->szTabRow = sqlite3LogEst(szAll * 4);
+	assert(table != NULL);
+	assert(select != NULL);
+	assert((select->selFlags & SF_Resolved) != 0);
+	assert(table->nCol == select->pEList->nExpr);
+	struct sqlite3 *db = parse_context->db;
+	u64 row_size = 0;
+	struct NameContext name_context;
+	memset(&name_context, 0, sizeof(name_context));
+	name_context.pSrcList = select->pSrc;
+	struct ExprList_item *a = select->pEList->a;
+	struct Column *column = table->aCol;
+	for (int i = 0; i < table->nCol; i++, column++) {
+		Expr *p = a[i].pExpr;
+		column->type = columnType(&name_context, p, 0, 0, 0,
+					  &column->szEst);
+		row_size += column->szEst;
+		column->affinity = sqlite3ExprAffinity(p);
+		if (column->affinity == 0)
+			column->affinity = SQLITE_AFF_BLOB;
+		struct coll *collation = sqlite3ExprCollSeq(parse_context, p);
+		if (collation != NULL && column->zColl == NULL)
+			column->zColl = sqlite3DbStrDup(db, collation->name);
+	}
+	table->szTabRow = sqlite3LogEst(row_size * 4);
 }
 
-/*
- * Given a SELECT statement, generate a Table structure that describes
- * the result set of that SELECT.
+/**
+ * Given a SELECT statement, generate a Table structure that
+ * describes the result set of that SELECT, including column
+ * names, their types and collations.
+ *
+ * Also see sql_view_get_column_names().
+ *
+ * @param parse_context Current parsing context.
+ * @param select Select to be processed.
+ * @retval Fake table which represents result set of given select.
  */
 Table *
-sqlite3ResultSetOfSelect(Parse * pParse, Select * pSelect)
+sql_result_set_of_select(struct Parse *parse_context, struct Select *select)
 {
-	Table *pTab;
-	sqlite3 *db = pParse->db;
-	uint32_t savedFlags;
+	struct sqlite3 *db = parse_context->db;
 	struct session *user_session = current_session();
-
-	savedFlags = user_session->sql_flags;
+	uint32_t savedFlags = user_session->sql_flags;
 	user_session->sql_flags |= ~SQLITE_FullColNames;
 	user_session->sql_flags &= SQLITE_ShortColNames;
-	sqlite3SelectPrep(pParse, pSelect, 0);
-	if (pParse->nErr)
-		return 0;
-	while (pSelect->pPrior)
-		pSelect = pSelect->pPrior;
+	sqlite3SelectPrep(parse_context, select, 0);
+	if (parse_context->nErr)
+		return NULL;
+	while (select->pPrior)
+		select = select->pPrior;
 	user_session->sql_flags = savedFlags;
-	pTab = sqlite3DbMallocZero(db, sizeof(Table));
-	if (pTab == 0) {
-		return 0;
-	}
-	/* The sqlite3ResultSetOfSelect() is only used n contexts where lookaside
-	 * is disabled
-	 */
-	assert(db->lookaside.bDisable);
-	pTab->nTabRef = 1;
-	pTab->zName = 0;
-	pTab->nRowLogEst = 200;
-	assert(200 == sqlite3LogEst(1048576));
-	sqlite3ColumnsFromExprList(pParse, pSelect->pEList, &pTab->nCol,
-				   &pTab->aCol);
-	sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSelect);
-	pTab->iPKey = -1;
+	struct Table *result_table = sqlite3Malloc(sizeof(Table));
+	if (result_table == NULL)
+		return NULL;
+	memset(result_table, 0, sizeof(struct Table));
+	result_table->nTabRef = 1;
+	sqlite3ColumnsFromExprList(parse_context, select->pEList,
+				   &result_table->nCol, &result_table->aCol);
+	sql_select_add_column_properties(parse_context, result_table, select);
 	if (db->mallocFailed) {
-		sqlite3DeleteTable(db, pTab);
-		return 0;
+		sqlite3DeleteTable(db, result_table);
+		return NULL;
 	}
-	return pTab;
+	return result_table;
 }
 
 /*
@@ -4600,8 +4591,9 @@ withExpand(Walker * pWalker, struct SrcList_item *pFrom)
 			pEList = pCte->pCols;
 		}
 
-		sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol,
-					   &pTab->aCol);
+		if (sqlite3ColumnsFromExprList(pParse, pEList, &pTab->nCol,
+					       &pTab->aCol))
+			return SQLITE_NOMEM;
 		if (bMayRecursive) {
 			if (pSel->selFlags & SF_Recursive) {
 				pCte->zCteErr =
@@ -4758,12 +4750,16 @@ selectExpander(Walker * pWalker, Select * p)
 				return WRC_Abort;
 			}
 			if (space_is_view(pTab)) {
+				uint32_t space_id = SQLITE_PAGENO_TO_SPACEID(pTab->tnum);
+				struct space *space = space_by_id(space_id);
+				assert(space != NULL);
 				i16 nCol;
-				if (sqlite3ViewGetColumnNames(pParse, pTab))
+				if (sql_view_column_names(pParse, pTab))
 					return WRC_Abort;
 				assert(pFrom->pSelect == 0);
-				pFrom->pSelect =
-				    sqlite3SelectDup(db, pTab->pSelect, 0);
+				if (sql_view_compile(db, space->def->opts.sql,
+						     &pFrom->pSelect) != 0)
+					return WRC_Abort;
 				sqlite3SelectSetName(pFrom->pSelect,
 						     pTab->zName);
 				nCol = pTab->nCol;
@@ -5071,9 +5067,9 @@ selectAddSubqueryTypeInfo(Walker * pWalker, Select * p)
 			if (pSel) {
 				while (pSel->pPrior)
 					pSel = pSel->pPrior;
-				sqlite3SelectAddColumnTypeAndCollation(pParse,
-								       pTab,
-								       pSel);
+				sql_select_add_column_properties(pParse,
+								 pTab,
+								 pSel);
 			}
 		}
 	}
diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
index 91a338246..a5b39e0a5 100644
--- a/src/box/sql/sqliteInt.h
+++ b/src/box/sql/sqliteInt.h
@@ -3013,6 +3013,8 @@ struct Parse {
 	bool parse_only;
 	/** If parse_only is set to true, store parsed expression. */
 	struct Expr *parsed_expr;
+	/** If parse_only is set to true, store parsed SELECT. */
+	struct Select *parsed_select;
 };
 
 /*
@@ -3514,6 +3516,9 @@ void sqlite3NormalizeName(char *z);
 void sqlite3TokenInit(Token *, char *);
 int sqlite3KeywordCode(const unsigned char *, int);
 int sqlite3RunParser(Parse *, const char *, char **);
+int
+sql_view_compile(struct sqlite3 *db, const char *view_stmt,
+		 struct Select **select);
 void sqlite3FinishCoding(Parse *);
 int sqlite3GetTempReg(Parse *);
 void sqlite3ReleaseTempReg(Parse *, int);
@@ -3547,8 +3552,11 @@ void sqlite3CommitInternalChanges();
 void sqlite3DeleteColumnNames(sqlite3 *, Table *);
 bool table_column_is_in_pk(Table *, uint32_t);
 int sqlite3ColumnsFromExprList(Parse *, ExprList *, i16 *, Column **);
-void sqlite3SelectAddColumnTypeAndCollation(Parse *, Table *, Select *);
-Table *sqlite3ResultSetOfSelect(Parse *, Select *);
+void
+sql_select_add_column_properties(struct Parse *parse_context,
+				 struct Table *table, struct Select *select);
+Table *
+sql_result_set_of_select(struct Parse *parse_context, Select *select);
 Index *sqlite3PrimaryKeyIndex(Table *);
 i16 sqlite3ColumnOfIndex(Index *, i16);
 void sqlite3StartTable(Parse *, Token *, int);
@@ -3580,7 +3588,10 @@ int sqlite3FaultSim(int);
 #endif
 
 void sqlite3CreateView(Parse *, Token *, Token *, ExprList *, Select *, int);
-int sqlite3ViewGetColumnNames(Parse *, Table *);
+void
+sql_store_select(struct Parse *parse_context, struct Select *select);
+int
+sql_view_column_names(struct Parse *parse_context, struct Table *table);
 
 #if SQLITE_MAX_ATTACHED>30
 int sqlite3DbMaskAllZero(yDbMask);
diff --git a/src/box/sql/tokenize.c b/src/box/sql/tokenize.c
index 2894f8d7e..3822981d6 100644
--- a/src/box/sql/tokenize.c
+++ b/src/box/sql/tokenize.c
@@ -654,8 +654,7 @@ sqlite3RunParser(Parse * pParse, const char *zSql, char **pzErrMsg)
 }
 
 int
-sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result)
-{
+sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result) {
 	const char *outer = "SELECT ";
 	int len = strlen(outer) + strlen(expr);
 	char *stmt = (char *) region_alloc(&fiber()->gc, len + 1);
@@ -678,3 +677,30 @@ sql_expr_compile(sqlite3 *db, const char *expr, struct Expr **result)
 	sqlite3ParserReset(&parser);
 	return 0;
 }
+
+/**
+ * This routine executes parser on 'CREATE VIEW ...' statement
+ * and loads content of SELECT into internal struct.
+ *
+ * @param db Current SQL context.
+ * @param view_stmt String containing 'CREATE VIEW' statement.
+ * @param[out] select Fetched SELECT statement.
+ * @retval 0 on success, -1 otherwise.
+ */
+int
+sql_view_compile(struct sqlite3 *db, const char *view_stmt,
+		 struct Select **select)
+{
+	assert(select != NULL);
+	/* Surrogate parse context just to accept parser interface. */
+	struct Parse parser;
+	memset(&parser, 0, sizeof(parser));
+	parser.db = db;
+	parser.parse_only = true;
+	char *unused;
+	if (sqlite3RunParser(&parser, view_stmt, &unused) != SQLITE_OK) {
+		return -1;
+	}
+	*select = parser.parsed_select;
+	return 0;
+}
diff --git a/src/box/sql/update.c b/src/box/sql/update.c
index fe568ad4c..8cdeea994 100644
--- a/src/box/sql/update.c
+++ b/src/box/sql/update.c
@@ -162,7 +162,7 @@ sqlite3Update(Parse * pParse,		/* The parser context */
 	isView = space_is_view(pTab);
 	assert(pTrigger || tmask == 0);
 
-	if (sqlite3ViewGetColumnNames(pParse, pTab)) {
+	if (sql_view_column_names(pParse, pTab)) {
 		goto update_cleanup;
 	}
 	if (sqlite3IsReadOnly(pParse, pTab, tmask)) {
diff --git a/test/sql-tap/view.test.lua b/test/sql-tap/view.test.lua
index 8ba2044f0..fa1561be7 100755
--- a/test/sql-tap/view.test.lua
+++ b/test/sql-tap/view.test.lua
@@ -1,6 +1,6 @@
 #!/usr/bin/env tarantool
 test = require("sqltester")
-test:plan(65)
+test:plan(67)
 
 --!./tcltestrunner.lua
 -- 2002 February 26
@@ -903,20 +903,30 @@ test:do_catchsql_test(
 -- Ticket #1658
 --
 -- MUST_WORK_TEST temp views do not work
-if (0 > 0)
- then
-    test:do_catchsql_test(
+test:do_catchsql_test(
         "view-14.1",
         [[
-            CREATE TEMP VIEW t1 AS SELECT a,b FROM t1;
-            SELECT * FROM temp.t1;
+            CREATE VIEW v11 AS SELECT a,b FROM v11;
+            SELECT * FROM v11;
         ]], {
             -- <view-14.1>
-            1, "view t1 is circularly defined"
+            1, "view V11 is circularly defined"
             -- </view-14.1>
         })
 
-end
+test:do_catchsql_test(
+	"view-14.2",
+	[[
+	    DROP VIEW IF EXISTS v11;
+	    CREATE VIEW v11 AS SELECT * FROM v22;
+	    CREATE VIEW v22 AS SELECT * FROM v11;
+	    SELECT * FROM v11;
+	]], {
+	    -- <view-14.2>
+	    1, "view V11 is circularly defined"
+	    -- </view-14.2>
+	})
+
 -- Tickets #1688 #1709
 test:do_execsql2_test(
     "view-15.1",
-- 
2.15.1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [tarantool-patches] Re: [PATCH 1/3] sql: remove usless #ifdef directives
  2018-04-03 14:54 ` [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives Nikita Pettik
@ 2018-04-03 17:23   ` Vladislav Shpilevoy
  0 siblings, 0 replies; 5+ messages in thread
From: Vladislav Shpilevoy @ 2018-04-03 17:23 UTC (permalink / raw)
  To: tarantool-patches; +Cc: Nikita Pettik

Hello. Please consider a single comment: remove SQLITE_OMIT_VIEW from 
mkkeywordhash.c.

Other comments I will give to a next patch version, as we discussed 
verbally.


03.04.2018 17:54, Nikita Pettik пишет:
> Since in our SQL implemetation triggers, foreign keys and views are
> always available, there is no need in #ifdef directives which
> turn them off.
> Removed: SQLITE_OMIT_VIEW, SQLITE_OMIT_TRIGGER, SQLITE_OMIT_FOREIGN_KEY
> defines. Also, removed obsolete compelete.c source file.
> ---
>   src/box/sql/CMakeLists.txt |   1 -
>   src/box/sql/alter.c        |   2 -
>   src/box/sql/attach.c       |   6 -
>   src/box/sql/build.c        |  20 ---
>   src/box/sql/complete.c     | 333 ---------------------------------------------
>   src/box/sql/delete.c       |  18 ---
>   src/box/sql/expr.c         |   5 +-
>   src/box/sql/fkey.c         |   8 --
>   src/box/sql/insert.c       |  15 --
>   src/box/sql/parse.c        | 320 +++++++++++++++++++++----------------------
>   src/box/sql/parse.y        |   7 -
>   src/box/sql/pragma.c       |   8 --
>   src/box/sql/pragma.h       |   8 --
>   src/box/sql/resolve.c      |   3 -
>   src/box/sql/select.c       |  20 ++-
>   src/box/sql/sqliteInt.h    |  39 ------
>   src/box/sql/treeview.c     |   2 -
>   src/box/sql/trigger.c      |   3 -
>   src/box/sql/update.c       |  15 --
>   src/box/sql/vdbe.c         |   5 -
>   src/box/sql/vdbe.h         |   2 -
>   src/box/sql/vdbeInt.h      |   4 -
>   src/box/sql/vdbeaux.c      |   4 -
>   23 files changed, 169 insertions(+), 679 deletions(-)
>   delete mode 100644 src/box/sql/complete.c
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-04-03 17:23 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-04-03 14:54 [tarantool-patches] [PATCH 0/3] Rework VIEW processing Nikita Pettik
2018-04-03 14:54 ` [tarantool-patches] [PATCH 1/3] sql: remove usless #ifdef directives Nikita Pettik
2018-04-03 17:23   ` [tarantool-patches] " Vladislav Shpilevoy
2018-04-03 14:54 ` [tarantool-patches] [PATCH 2/3] sql: add view column aliases to space format Nikita Pettik
2018-04-03 14:54 ` [tarantool-patches] [PATCH 3/3] sql: load SELECT from 'CREATE VIEW ...' string Nikita Pettik

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox