[tarantool-patches] [PATCH 6/8] Removes the following unused macros: SQL_EXPLAIN_ESTIMATED_ROWS SQL_ENABLE_COLUMN_USED_MASK SQL_DISABLE_DIRSYNC SQL_OMIT_AUTOMATIC_INDEX SQL_DEBUG_SORTER_THREADS SQL_DEFAULT_WORKER_THREADS SQL_LIMIT_WORKER_THREADS SQL_MAX_WORKER_THREADS

Stanislav Zudin szudin at tarantool.org
Mon Apr 29 20:26:09 MSK 2019


Part of #3978
---
 src/box/sql/CMakeLists.txt |   3 -
 src/box/sql/expr.c         |  14 -
 src/box/sql/main.c         |   8 -
 src/box/sql/os_unix.c      |   2 -
 src/box/sql/sqlInt.h       |  21 +-
 src/box/sql/util.c         |   5 -
 src/box/sql/vdbe.c         |  20 --
 src/box/sql/vdbeInt.h      |   3 -
 src/box/sql/vdbesort.c     | 639 +++----------------------------------
 src/box/sql/where.c        | 313 ------------------
 src/box/sql/wherecode.c    |   8 -
 11 files changed, 45 insertions(+), 991 deletions(-)

diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt
index b9dbe141a..f988dc3e7 100644
--- a/src/box/sql/CMakeLists.txt
+++ b/src/box/sql/CMakeLists.txt
@@ -10,9 +10,6 @@ set(SQL_BIN_DIR ${CMAKE_BINARY_DIR}/src/box/sql)
 include_directories(${SQL_SRC_DIR})
 include_directories(${SQL_BIN_DIR})
 
-add_definitions(-DSQL_MAX_WORKER_THREADS=0)
-add_definitions(-DSQL_OMIT_AUTOMATIC_INDEX)
-
 set(TEST_DEFINITIONS
     SQL_NO_SYNC=1
     SQL_TEST=1
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index 71d0cbf46..48d7185f3 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -2570,20 +2570,6 @@ sqlFindInIndex(Parse * pParse,	/* Parsing context */
 						parts[0].sort_order;
 
 					if (prRhsHasNull) {
-#ifdef SQL_ENABLE_COLUMN_USED_MASK
-							i64 mask =
-							    (1 << nExpr) - 1;
-							sqlVdbeAddOp4Dup8(v,
-									      OP_ColumnsUsed,
-									      iTab,
-									      0,
-									      0,
-									      (u8
-									       *)
-									      &
-									      mask,
-									      P4_INT64);
-#endif
 						*prRhsHasNull = ++pParse->nMem;
 						if (nExpr == 1) {
 							/* Tarantool: Check for null is performed on first key of the index.  */
diff --git a/src/box/sql/main.c b/src/box/sql/main.c
index c0c334f89..339b456df 100644
--- a/src/box/sql/main.c
+++ b/src/box/sql/main.c
@@ -533,7 +533,6 @@ static const int aHardLimit[] = {
 	SQL_MAX_ATTACHED,
 	SQL_MAX_LIKE_PATTERN_LENGTH,
 	SQL_MAX_TRIGGER_DEPTH,
-	SQL_MAX_WORKER_THREADS,
 };
 
 /*
@@ -569,9 +568,6 @@ static const int aHardLimit[] = {
 #if SQL_MAX_TRIGGER_DEPTH<1
 #error SQL_MAX_TRIGGER_DEPTH must be at least 1
 #endif
-#if SQL_MAX_WORKER_THREADS<0 || SQL_MAX_WORKER_THREADS>50
-#error SQL_MAX_WORKER_THREADS must be between 0 and 50
-#endif
 
 /*
  * Change the value of a limit.  Report the old value.
@@ -607,9 +603,6 @@ sql_limit(sql * db, int limitId, int newLimit)
 	       SQL_MAX_LIKE_PATTERN_LENGTH);
 	assert(aHardLimit[SQL_LIMIT_TRIGGER_DEPTH] ==
 	       SQL_MAX_TRIGGER_DEPTH);
-	assert(aHardLimit[SQL_LIMIT_WORKER_THREADS] ==
-	       SQL_MAX_WORKER_THREADS);
-	assert(SQL_LIMIT_WORKER_THREADS == (SQL_N_LIMIT - 1));
 
 	if (limitId < 0 || limitId >= SQL_N_LIMIT) {
 		return -1;
@@ -652,7 +645,6 @@ sql_init_db(sql **out_db)
 
 	assert(sizeof(db->aLimit) == sizeof(aHardLimit));
 	memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit));
-	db->aLimit[SQL_LIMIT_WORKER_THREADS] = SQL_DEFAULT_WORKER_THREADS;
 	db->aLimit[SQL_LIMIT_COMPOUND_SELECT] = SQL_DEFAULT_COMPOUND_SELECT;
 	db->szMmap = sqlGlobalConfig.szMmap;
 	db->nMaxSorterMmap = 0x7FFFFFFF;
diff --git a/src/box/sql/os_unix.c b/src/box/sql/os_unix.c
index 615d539b5..f9969b447 100644
--- a/src/box/sql/os_unix.c
+++ b/src/box/sql/os_unix.c
@@ -1937,7 +1937,6 @@ unixDelete(sql_vfs * NotUsed,	/* VFS containing this as the xDelete method */
 		}
 		return rc;
 	}
-#ifndef SQL_DISABLE_DIRSYNC
 	if ((dirSync & 1) != 0) {
 		int fd;
 		rc = openDirectory(zPath, &fd);
@@ -1953,7 +1952,6 @@ unixDelete(sql_vfs * NotUsed,	/* VFS containing this as the xDelete method */
 			rc = SQL_OK;
 		}
 	}
-#endif
 	return rc;
 }
 
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index f019cd291..4bf94fad2 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -341,7 +341,6 @@ struct sql_vfs {
 #define SQL_LIMIT_ATTACHED                  7
 #define SQL_LIMIT_LIKE_PATTERN_LENGTH       8
 #define SQL_LIMIT_TRIGGER_DEPTH             9
-#define SQL_LIMIT_WORKER_THREADS           10
 
 enum sql_ret_code {
 	/** Result of a routine is ok. */
@@ -945,17 +944,6 @@ sql_bind_parameter_lindex(sql_stmt * pStmt, const char *zName,
 #define SQL_DEFAULT_RECURSIVE_TRIGGERS 0
 #endif
 
-#ifndef SQL_MAX_WORKER_THREADS
-#define SQL_MAX_WORKER_THREADS 8
-#endif
-#ifndef SQL_DEFAULT_WORKER_THREADS
-#define SQL_DEFAULT_WORKER_THREADS 0
-#endif
-#if SQL_DEFAULT_WORKER_THREADS>SQL_MAX_WORKER_THREADS
-#undef SQL_MAX_WORKER_THREADS
-#define SQL_MAX_WORKER_THREADS SQL_DEFAULT_WORKER_THREADS
-#endif
-
 /**
  * Default count of allowed compound selects.
  *
@@ -1296,7 +1284,7 @@ typedef int VList;
  * The number of different kinds of things that can be limited
  * using the sql_limit() interface.
  */
-#define SQL_N_LIMIT (SQL_LIMIT_WORKER_THREADS+1)
+#define SQL_N_LIMIT (SQL_LIMIT_TRIGGER_DEPTH+1)
 
 /*
  * Lookaside malloc is a set of fixed-size buffers that can be used
@@ -4858,13 +4846,6 @@ int sqlMemdebugNoType(void *, u8);
 #define MEMTYPE_SCRATCH    0x04	/* Scratch allocations */
 #define MEMTYPE_PCACHE     0x08	/* Page cache allocations */
 
-/*
- * Threading interface
- */
-#if SQL_MAX_WORKER_THREADS>0
-int sqlThreadCreate(sqlThread **, void *(*)(void *), void *);
-int sqlThreadJoin(sqlThread *, void **);
-#endif
 
 int sqlExprVectorSize(Expr * pExpr);
 int sqlExprIsVector(Expr * pExpr);
diff --git a/src/box/sql/util.c b/src/box/sql/util.c
index 31378041d..39632e38d 100644
--- a/src/box/sql/util.c
+++ b/src/box/sql/util.c
@@ -1337,15 +1337,10 @@ sqlLogEstToInt(LogEst x)
 		n -= 2;
 	else if (n >= 1)
 		n -= 1;
-#if defined(SQL_EXPLAIN_ESTIMATED_ROWS)
-	if (x > 60)
-		return (u64) LARGEST_INT64;
-#else
 	/* The largest input possible to this routine is 310,
 	 * resulting in a maximum x of 31
 	 */
 	assert(x <= 60);
-#endif
 	return x >= 3 ? (n + 8) << (x - 3) : (n + 8) >> (3 - x);
 }
 
diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
index 624df25b8..738a0701b 100644
--- a/src/box/sql/vdbe.c
+++ b/src/box/sql/vdbe.c
@@ -3346,26 +3346,6 @@ case OP_Close: {
 	break;
 }
 
-#ifdef SQL_ENABLE_COLUMN_USED_MASK
-/* Opcode: ColumnsUsed P1 * * P4 *
- *
- * This opcode (which only exists if sql was compiled with
- * SQL_ENABLE_COLUMN_USED_MASK) identifies which columns of the
- * table or index for cursor P1 are used.  P4 is a 64-bit integer
- * (P4_INT64) in which the first 63 bits are one for each of the
- * first 63 columns of the table or index that are actually used
- * by the cursor.  The high-order bit is set if any column after
- * the 64th is used.
- */
-case OP_ColumnsUsed: {
-	VdbeCursor *pC;
-	pC = p->apCsr[pOp->p1];
-	assert(pC->eCurType==CURTYPE_TARANTOOL);
-	pC->maskUsed = *(u64*)pOp->p4.pI64;
-	break;
-}
-#endif
-
 /* Opcode: SeekGE P1 P2 P3 P4 P5
  * Synopsis: key=r[P3 at P4]
  *
diff --git a/src/box/sql/vdbeInt.h b/src/box/sql/vdbeInt.h
index a5933a5e7..a070e87f8 100644
--- a/src/box/sql/vdbeInt.h
+++ b/src/box/sql/vdbeInt.h
@@ -116,9 +116,6 @@ struct VdbeCursor {
 	const u8 *aRow;		/* Data for the current row, if all on one page */
 	u32 payloadSize;	/* Total number of bytes in the record */
 	u32 szRow;		/* Byte available in aRow */
-#ifdef SQL_ENABLE_COLUMN_USED_MASK
-	u64 maskUsed;		/* Mask of columns used by this cursor */
-#endif
 	u32 nRowField;		/* Number of fields in the current row */
 	/* Offsets for all fields in the record [nField+1]
 	 * Order of fields is the same as it was passes to create table statement
diff --git a/src/box/sql/vdbesort.c b/src/box/sql/vdbesort.c
index ddea6752c..a37fbd911 100644
--- a/src/box/sql/vdbesort.c
+++ b/src/box/sql/vdbesort.c
@@ -118,11 +118,6 @@
  * there are already N worker threads running, the main thread does the work
  * itself.
  *
- * The sorter is running in multi-threaded mode if (a) the library was built
- * with pre-processor symbol SQL_MAX_WORKER_THREADS set to a value greater
- * than zero, and (b) worker threads have been enabled at runtime by calling
- * "PRAGMA threads=N" with some value of N greater than 0.
- *
  * When Rewind() is called, any data remaining in memory is flushed to a
  * final PMA. So at this point the data is stored in some number of sorted
  * PMAs within temporary files on disk.
@@ -159,15 +154,6 @@
 #include "sqlInt.h"
 #include "vdbeInt.h"
 
-/*
- * If SQL_DEBUG_SORTER_THREADS is defined, this module outputs various
- * messages to stderr that may be helpful in understanding the performance
- * characteristics of the sorter in multi-threaded mode.
- */
-#if 0
-#define SQL_DEBUG_SORTER_THREADS 1
-#endif
-
 /*
  * Hard-coded maximum amount of data to accumulate in memory before flushing
  * to a level 0 PMA. The purpose of this limit is to prevent various integer
@@ -297,18 +283,14 @@ struct MergeEngine {
  *
  * Before a background thread is launched, variable bDone is set to 0. Then,
  * right before it exits, the thread itself sets bDone to 1. This is used for
- * two purposes:
+ * the following purpose:
  *
- *   1. When flushing the contents of memory to a level-0 PMA on disk, to
+ *      When flushing the contents of memory to a level-0 PMA on disk, to
  *      attempt to select a SortSubtask for which there is not already an
  *      active background thread (since doing so causes the main thread
  *      to block until it finishes).
  *
- *   2. If SQL_DEBUG_SORTER_THREADS is defined, to determine if a call
- *      to sqlThreadJoin() is likely to block. Cases that are likely to
- *      block provoke debugging output.
- *
- * In both cases, the effects of the main thread seeing (bDone==0) even
+ * The effects of the main thread seeing (bDone==0) even
  * after the thread has finished are not dire. So we don't worry about
  * memory barriers and such here.
  */
@@ -855,25 +837,6 @@ sqlVdbeSorterInit(sql * db,	/* Database connection (for malloc()) */
 	int i;			/* Used to iterate through aTask[] */
 	VdbeSorter *pSorter;	/* The new sorter */
 	int rc = SQL_OK;
-#if SQL_MAX_WORKER_THREADS==0
-#define nWorker 0
-#else
-	int nWorker;
-#endif
-
-	/* Initialize the upper limit on the number of worker threads */
-#if SQL_MAX_WORKER_THREADS>0
-	nWorker = db->aLimit[SQL_LIMIT_WORKER_THREADS];
-#endif
-
-	/* Do not allow the total number of threads (main thread + all workers)
-	 * to exceed the maximum merge count
-	 */
-#if SQL_MAX_WORKER_THREADS>=SORTER_MAX_MERGE_COUNT
-	if (nWorker >= SORTER_MAX_MERGE_COUNT) {
-		nWorker = SORTER_MAX_MERGE_COUNT - 1;
-	}
-#endif
 
 	assert(pCsr->key_def != NULL);
 	assert(pCsr->eCurType == CURTYPE_SORTER);
@@ -885,8 +848,8 @@ sqlVdbeSorterInit(sql * db,	/* Database connection (for malloc()) */
 	} else {
 		pSorter->key_def = pCsr->key_def;
 		pSorter->pgsz = pgsz = 1024;
-		pSorter->nTask = nWorker + 1;
-		pSorter->iPrev = (u8) (nWorker - 1);
+		pSorter->nTask = 1;
+		pSorter->iPrev = (u8) (-1);
 		pSorter->bUseThreads = (pSorter->nTask > 1);
 		pSorter->db = db;
 		for (i = 0; i < pSorter->nTask; i++) {
@@ -927,8 +890,6 @@ sqlVdbeSorterInit(sql * db,	/* Database connection (for malloc()) */
 	return rc;
 }
 
-#undef nWorker			/* Defined at the top of this function */
-
 /*
  * Free the list of sorted records starting at pRecord.
  */
@@ -951,18 +912,10 @@ static void
 vdbeSortSubtaskCleanup(sql * db, SortSubtask * pTask)
 {
 	sqlDbFree(db, pTask->pUnpacked);
-#if SQL_MAX_WORKER_THREADS>0
-	/* pTask->list.aMemory can only be non-zero if it was handed memory
-	 * from the main thread.  That only occurs SQL_MAX_WORKER_THREADS>0
-	 */
-	if (pTask->list.aMemory) {
-		sql_free(pTask->list.aMemory);
-	} else
-#endif
-	{
-		assert(pTask->list.aMemory == 0);
-		vdbeSorterRecordFree(0, pTask->list.pList);
-	}
+
+	assert(pTask->list.aMemory == 0);
+	vdbeSorterRecordFree(0, pTask->list.pList);
+
 	if (pTask->file.pFd) {
 		sqlOsCloseFree(pTask->file.pFd);
 	}
@@ -972,116 +925,7 @@ vdbeSortSubtaskCleanup(sql * db, SortSubtask * pTask)
 	memset(pTask, 0, sizeof(SortSubtask));
 }
 
-#ifdef SQL_DEBUG_SORTER_THREADS
-static void
-vdbeSorterWorkDebug(SortSubtask * pTask, const char *zEvent)
-{
-	i64 t;
-	int iTask = (pTask - pTask->pSorter->aTask);
-	sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
-	fprintf(stderr, "%lld:%d %s\n", t, iTask, zEvent);
-}
-
-static void
-vdbeSorterRewindDebug(const char *zEvent)
-{
-	i64 t;
-	sqlOsCurrentTimeInt64(sql_vfs_find(0), &t);
-	fprintf(stderr, "%lld:X %s\n", t, zEvent);
-}
-
-static void
-vdbeSorterPopulateDebug(SortSubtask * pTask, const char *zEvent)
-{
-	i64 t;
-	int iTask = (pTask - pTask->pSorter->aTask);
-	sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
-	fprintf(stderr, "%lld:bg%d %s\n", t, iTask, zEvent);
-}
-
-static void
-vdbeSorterBlockDebug(SortSubtask * pTask, int bBlocked, const char *zEvent)
-{
-	if (bBlocked) {
-		i64 t;
-		sqlOsCurrentTimeInt64(pTask->pSorter->db->pVfs, &t);
-		fprintf(stderr, "%lld:main %s\n", t, zEvent);
-	}
-}
-#else
-#define vdbeSorterWorkDebug(x,y)
-#define vdbeSorterRewindDebug(y)
-#define vdbeSorterPopulateDebug(x,y)
-#define vdbeSorterBlockDebug(x,y,z)
-#endif
-
-#if SQL_MAX_WORKER_THREADS>0
-/*
- * Join thread pTask->thread.
- */
-static int
-vdbeSorterJoinThread(SortSubtask * pTask)
-{
-	int rc = SQL_OK;
-	if (pTask->pThread) {
-#ifdef SQL_DEBUG_SORTER_THREADS
-		int bDone = pTask->bDone;
-#endif
-		void *pRet = SQL_INT_TO_PTR(SQL_ERROR);
-		vdbeSorterBlockDebug(pTask, !bDone, "enter");
-		(void)sqlThreadJoin(pTask->pThread, &pRet);
-		vdbeSorterBlockDebug(pTask, !bDone, "exit");
-		rc = SQL_PTR_TO_INT(pRet);
-		assert(pTask->bDone == 1);
-		pTask->bDone = 0;
-		pTask->pThread = 0;
-	}
-	return rc;
-}
-
-/*
- * Launch a background thread to run xTask(pIn).
- */
-static int
-vdbeSorterCreateThread(SortSubtask * pTask,	/* Thread will use this task object */
-		       void *(*xTask) (void *),	/* Routine to run in a separate thread */
-		       void *pIn	/* Argument passed into xTask() */
-    )
-{
-	assert(pTask->pThread == 0 && pTask->bDone == 0);
-	return sqlThreadCreate(&pTask->pThread, xTask, pIn);
-}
-
-/*
- * Join all outstanding threads launched by SorterWrite() to create
- * level-0 PMAs.
- */
-static int
-vdbeSorterJoinAll(VdbeSorter * pSorter, int rcin)
-{
-	int rc = rcin;
-	int i;
-
-	/* This function is always called by the main user thread.
-	 *
-	 * If this function is being called after SorterRewind() has been called,
-	 * it is possible that thread pSorter->aTask[pSorter->nTask-1].pThread
-	 * is currently attempt to join one of the other threads. To avoid a race
-	 * condition where this thread also attempts to join the same object, join
-	 * thread pSorter->aTask[pSorter->nTask-1].pThread first.
-	 */
-	for (i = pSorter->nTask - 1; i >= 0; i--) {
-		SortSubtask *pTask = &pSorter->aTask[i];
-		int rc2 = vdbeSorterJoinThread(pTask);
-		if (rc == SQL_OK)
-			rc = rc2;
-	}
-	return rc;
-}
-#else
 #define vdbeSorterJoinAll(x,rcin) (rcin)
-#define vdbeSorterJoinThread(pTask) SQL_OK
-#endif
 
 /*
  * Allocate a new MergeEngine object capable of handling up to
@@ -1137,15 +981,6 @@ static void
 vdbeIncrFree(IncrMerger * pIncr)
 {
 	if (pIncr) {
-#if SQL_MAX_WORKER_THREADS>0
-		if (pIncr->bUseThread) {
-			vdbeSorterJoinThread(pIncr->pTask);
-			if (pIncr->aFile[0].pFd)
-				sqlOsCloseFree(pIncr->aFile[0].pFd);
-			if (pIncr->aFile[1].pFd)
-				sqlOsCloseFree(pIncr->aFile[1].pFd);
-		}
-#endif
 		vdbeMergeEngineFree(pIncr->pMerger);
 		sql_free(pIncr);
 	}
@@ -1160,13 +995,6 @@ sqlVdbeSorterReset(sql * db, VdbeSorter * pSorter)
 	int i;
 	(void)vdbeSorterJoinAll(pSorter, SQL_OK);
 	assert(pSorter->bUseThreads || pSorter->pReader == 0);
-#if SQL_MAX_WORKER_THREADS>0
-	if (pSorter->pReader) {
-		vdbePmaReaderClear(pSorter->pReader);
-		sqlDbFree(db, pSorter->pReader);
-		pSorter->pReader = 0;
-	}
-#endif
 	vdbeMergeEngineFree(pSorter->pMerger);
 	pSorter->pMerger = 0;
 	for (i = 0; i < pSorter->nTask; i++) {
@@ -1516,7 +1344,6 @@ vdbeSorterListToPMA(SortSubtask * pTask, SorterList * pList)
 	    pList->szPMA + sqlVarintLen(pList->szPMA) + pTask->file.iEof;
 #endif
 
-	vdbeSorterWorkDebug(pTask, "enter");
 	memset(&writer, 0, sizeof(PmaWriter));
 	assert(pList->szPMA > 0);
 
@@ -1558,7 +1385,6 @@ vdbeSorterListToPMA(SortSubtask * pTask, SorterList * pList)
 		rc = vdbePmaWriterFinish(&writer, &pTask->file.iEof);
 	}
 
-	vdbeSorterWorkDebug(pTask, "exit");
 	assert(rc != SQL_OK || pList->pList == 0);
 	assert(rc != SQL_OK || pTask->file.iEof == iSz);
 	return rc;
@@ -1648,22 +1474,6 @@ vdbeMergeEngineStep(MergeEngine * pMerger,	/* The merge engine to advance to the
 	return (rc == SQL_OK ? pTask->pUnpacked->errCode : rc);
 }
 
-#if SQL_MAX_WORKER_THREADS>0
-/*
- * The main routine for background threads that write level-0 PMAs.
- */
-static void *
-vdbeSorterFlushThread(void *pCtx)
-{
-	SortSubtask *pTask = (SortSubtask *) pCtx;
-	int rc;			/* Return code */
-	assert(pTask->bDone == 0);
-	rc = vdbeSorterListToPMA(pTask, &pTask->list);
-	pTask->bDone = 1;
-	return SQL_INT_TO_PTR(rc);
-}
-#endif				/* SQL_MAX_WORKER_THREADS>0 */
-
 /*
  * Flush the current contents of VdbeSorter.list to a new PMA, possibly
  * using a background thread.
@@ -1671,76 +1481,8 @@ vdbeSorterFlushThread(void *pCtx)
 static int
 vdbeSorterFlushPMA(VdbeSorter * pSorter)
 {
-#if SQL_MAX_WORKER_THREADS==0
 	pSorter->bUsePMA = 1;
 	return vdbeSorterListToPMA(&pSorter->aTask[0], &pSorter->list);
-#else
-	int rc = SQL_OK;
-	int i;
-	SortSubtask *pTask = 0;	/* Thread context used to create new PMA */
-	int nWorker = (pSorter->nTask - 1);
-
-	/* Set the flag to indicate that at least one PMA has been written.
-	 * Or will be, anyhow.
-	 */
-	pSorter->bUsePMA = 1;
-
-	/* Select a sub-task to sort and flush the current list of in-memory
-	 * records to disk. If the sorter is running in multi-threaded mode,
-	 * round-robin between the first (pSorter->nTask-1) tasks. Except, if
-	 * the background thread from a sub-tasks previous turn is still running,
-	 * skip it. If the first (pSorter->nTask-1) sub-tasks are all still busy,
-	 * fall back to using the final sub-task. The first (pSorter->nTask-1)
-	 * sub-tasks are prefered as they use background threads - the final
-	 * sub-task uses the main thread.
-	 */
-	for (i = 0; i < nWorker; i++) {
-		int iTest = (pSorter->iPrev + i + 1) % nWorker;
-		pTask = &pSorter->aTask[iTest];
-		if (pTask->bDone) {
-			rc = vdbeSorterJoinThread(pTask);
-		}
-		if (rc != SQL_OK || pTask->pThread == 0)
-			break;
-	}
-
-	if (rc == SQL_OK) {
-		if (i == nWorker) {
-			/* Use the foreground thread for this operation */
-			rc = vdbeSorterListToPMA(&pSorter->aTask[nWorker],
-						 &pSorter->list);
-		} else {
-			/* Launch a background thread for this operation */
-			u8 *aMem = pTask->list.aMemory;
-			void *pCtx = (void *)pTask;
-
-			assert(pTask->pThread == 0 && pTask->bDone == 0);
-			assert(pTask->list.pList == 0);
-			assert(pTask->list.aMemory == 0
-			       || pSorter->list.aMemory != 0);
-
-			pSorter->iPrev = (u8) (pTask - pSorter->aTask);
-			pTask->list = pSorter->list;
-			pSorter->list.pList = 0;
-			pSorter->list.szPMA = 0;
-			if (aMem) {
-				pSorter->list.aMemory = aMem;
-				pSorter->nMemory = sqlMallocSize(aMem);
-			} else if (pSorter->list.aMemory) {
-				pSorter->list.aMemory =
-				    sqlMalloc(pSorter->nMemory);
-				if (!pSorter->list.aMemory)
-					return SQL_NOMEM;
-			}
-
-			rc = vdbeSorterCreateThread(pTask,
-						    vdbeSorterFlushThread,
-						    pCtx);
-		}
-	}
-
-	return rc;
-#endif				/* SQL_MAX_WORKER_THREADS!=0 */
 }
 
 /*
@@ -1876,8 +1618,6 @@ vdbeIncrPopulate(IncrMerger * pIncr)
 	PmaWriter writer;
 	assert(pIncr->bEof == 0);
 
-	vdbeSorterPopulateDebug(pTask, "enter");
-
 	vdbePmaWriterInit(pOut->pFd, &writer, pTask->pSorter->pgsz, iStart);
 	while (rc == SQL_OK) {
 		int dummy;
@@ -1904,36 +1644,9 @@ vdbeIncrPopulate(IncrMerger * pIncr)
 	rc2 = vdbePmaWriterFinish(&writer, &pOut->iEof);
 	if (rc == SQL_OK)
 		rc = rc2;
-	vdbeSorterPopulateDebug(pTask, "exit");
 	return rc;
 }
 
-#if SQL_MAX_WORKER_THREADS>0
-/*
- * The main routine for background threads that populate aFile[1] of
- * multi-threaded IncrMerger objects.
- */
-static void *
-vdbeIncrPopulateThread(void *pCtx)
-{
-	IncrMerger *pIncr = (IncrMerger *) pCtx;
-	void *pRet = SQL_INT_TO_PTR(vdbeIncrPopulate(pIncr));
-	pIncr->pTask->bDone = 1;
-	return pRet;
-}
-
-/*
- * Launch a background thread to populate aFile[1] of pIncr.
- */
-static int
-vdbeIncrBgPopulate(IncrMerger * pIncr)
-{
-	void *p = (void *)pIncr;
-	assert(pIncr->bUseThread);
-	return vdbeSorterCreateThread(pIncr->pTask, vdbeIncrPopulateThread, p);
-}
-#endif
-
 /*
  * This function is called when the PmaReader corresponding to pIncr has
  * finished reading the contents of aFile[0]. Its purpose is to "refill"
@@ -1954,33 +1667,10 @@ vdbeIncrBgPopulate(IncrMerger * pIncr)
 static int
 vdbeIncrSwap(IncrMerger * pIncr)
 {
-	int rc = SQL_OK;
-
-#if SQL_MAX_WORKER_THREADS>0
-	if (pIncr->bUseThread) {
-		rc = vdbeSorterJoinThread(pIncr->pTask);
-
-		if (rc == SQL_OK) {
-			SorterFile f0 = pIncr->aFile[0];
-			pIncr->aFile[0] = pIncr->aFile[1];
-			pIncr->aFile[1] = f0;
-		}
-
-		if (rc == SQL_OK) {
-			if (pIncr->aFile[0].iEof == pIncr->iStartOff) {
-				pIncr->bEof = 1;
-			} else {
-				rc = vdbeIncrBgPopulate(pIncr);
-			}
-		}
-	} else
-#endif
-	{
-		rc = vdbeIncrPopulate(pIncr);
-		pIncr->aFile[0] = pIncr->aFile[1];
-		if (pIncr->aFile[0].iEof == pIncr->iStartOff) {
-			pIncr->bEof = 1;
-		}
+	int rc = vdbeIncrPopulate(pIncr);
+	pIncr->aFile[0] = pIncr->aFile[1];
+	if (pIncr->aFile[0].iEof == pIncr->iStartOff) {
+		pIncr->bEof = 1;
 	}
 
 	return rc;
@@ -2015,18 +1705,6 @@ vdbeIncrMergerNew(SortSubtask * pTask,	/* The thread that will be using the new
 	return rc;
 }
 
-#if SQL_MAX_WORKER_THREADS>0
-/*
- * Set the "use-threads" flag on object pIncr.
- */
-static void
-vdbeIncrMergerSetThreads(IncrMerger * pIncr)
-{
-	pIncr->bUseThread = 1;
-	pIncr->pTask->file2.iEof -= pIncr->mxSz;
-}
-#endif				/* SQL_MAX_WORKER_THREADS>0 */
-
 /*
  * Recompute pMerger->aTree[iOut] by comparing the next keys on the
  * two PmaReaders that feed that entry.  Neither of the PmaReaders
@@ -2077,38 +1755,20 @@ vdbeMergeEngineCompare(MergeEngine * pMerger,	/* Merge engine containing PmaRead
 	pMerger->aTree[iOut] = iRes;
 }
 
-/*
- * Allowed values for the eMode parameter to vdbeMergeEngineInit()
- * and vdbePmaReaderIncrMergeInit().
- *
- * Only INCRINIT_NORMAL is valid in single-threaded builds (when
- * SQL_MAX_WORKER_THREADS==0).  The other values are only used
- * when there exists one or more separate worker threads.
- */
-#define INCRINIT_NORMAL 0
-#define INCRINIT_TASK   1
-#define INCRINIT_ROOT   2
-
 /*
  * Forward reference required as the vdbeIncrMergeInit() and
  * vdbePmaReaderIncrInit() routines are called mutually recursively when
  * building a merge tree.
  */
-static int vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode);
+static int vdbePmaReaderIncrInit(PmaReader * pReader);
 
 /*
  * Initialize the MergeEngine object passed as the second argument. Once this
  * function returns, the first key of merged data may be read from the
  * MergeEngine object in the usual fashion.
  *
- * If argument eMode is INCRINIT_ROOT, then it is assumed that any IncrMerge
- * objects attached to the PmaReader objects that the merger reads from have
- * already been populated, but that they have not yet populated aFile[0] and
- * set the PmaReader objects up to read from it. In this case all that is
- * required is to call vdbePmaReaderNext() on each PmaReader to point it at
- * its first key.
  *
- * Otherwise, if eMode is any value other than INCRINIT_ROOT, then use
+ * Use
  * vdbePmaReaderIncrMergeInit() to initialize each PmaReader that feeds data
  * to pMerger.
  *
@@ -2116,36 +1776,19 @@ static int vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode);
  */
 static int
 vdbeMergeEngineInit(SortSubtask * pTask,	/* Thread that will run pMerger */
-		    MergeEngine * pMerger,	/* MergeEngine to initialize */
-		    int eMode	/* One of the INCRINIT_XXX constants */
+		    MergeEngine * pMerger 	/* MergeEngine to initialize */
     )
 {
 	int rc = SQL_OK;	/* Return code */
 	int i;			/* For looping over PmaReader objects */
 	int nTree = pMerger->nTree;
 
-	/* eMode is always INCRINIT_NORMAL in single-threaded mode */
-	assert(SQL_MAX_WORKER_THREADS > 0 || eMode == INCRINIT_NORMAL);
-
 	/* Verify that the MergeEngine is assigned to a single thread */
 	assert(pMerger->pTask == 0);
 	pMerger->pTask = pTask;
 
 	for (i = 0; i < nTree; i++) {
-		if (SQL_MAX_WORKER_THREADS > 0 && eMode == INCRINIT_ROOT) {
-			/* PmaReaders should be normally initialized in order, as if they are
-			 * reading from the same temp file this makes for more linear file IO.
-			 * However, in the INCRINIT_ROOT case, if PmaReader aReadr[nTask-1] is
-			 * in use it will block the vdbePmaReaderNext() call while it uses
-			 * the main thread to fill its buffer. So calling PmaReaderNext()
-			 * on this PmaReader before any of the multi-threaded PmaReaders takes
-			 * better advantage of multi-processor hardware.
-			 */
-			rc = vdbePmaReaderNext(&pMerger->aReadr[nTree - i - 1]);
-		} else {
-			rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i],
-						   INCRINIT_NORMAL);
-		}
+		rc = vdbePmaReaderIncrInit(&pMerger->aReadr[i]);
 		if (rc != SQL_OK)
 			return rc;
 	}
@@ -2157,50 +1800,27 @@ vdbeMergeEngineInit(SortSubtask * pTask,	/* Thread that will run pMerger */
 }
 
 /*
- * The PmaReader passed as the first argument is guaranteed to be an
+ * The PmaReader is guaranteed to be an
  * incremental-reader (pReadr->pIncr!=0). This function serves to open
  * and/or initialize the temp file related fields of the IncrMerge
  * object at (pReadr->pIncr).
  *
- * If argument eMode is set to INCRINIT_NORMAL, then all PmaReaders
- * in the sub-tree headed by pReadr are also initialized. Data is then
+ * All PmaReaders
+ * in the sub-tree headed by pReadr are also initialized. Data is
  * loaded into the buffers belonging to pReadr and it is set to point to
  * the first key in its range.
  *
- * If argument eMode is set to INCRINIT_TASK, then pReadr is guaranteed
- * to be a multi-threaded PmaReader and this function is being called in a
- * background thread. In this case all PmaReaders in the sub-tree are
- * initialized as for INCRINIT_NORMAL and the aFile[1] buffer belonging to
- * pReadr is populated. However, pReadr itself is not set up to point
- * to its first key. A call to vdbePmaReaderNext() is still required to do
- * that.
- *
- * The reason this function does not call vdbePmaReaderNext() immediately
- * in the INCRINIT_TASK case is that vdbePmaReaderNext() assumes that it has
- * to block on thread (pTask->thread) before accessing aFile[1]. But, since
- * this entire function is being run by thread (pTask->thread), that will
- * lead to the current background thread attempting to join itself.
- *
- * Finally, if argument eMode is set to INCRINIT_ROOT, it may be assumed
- * that pReadr->pIncr is a multi-threaded IncrMerge objects, and that all
- * child-trees have already been initialized using IncrInit(INCRINIT_TASK).
- * In this case vdbePmaReaderNext() is called on all child PmaReaders and
- * the current PmaReader set to point to the first key in its range.
- *
  * SQL_OK is returned if successful, or an sql error code otherwise.
  */
 static int
-vdbePmaReaderIncrMergeInit(PmaReader * pReadr, int eMode)
+vdbePmaReaderIncrMergeInit(PmaReader * pReadr)
 {
 	int rc = SQL_OK;
 	IncrMerger *pIncr = pReadr->pIncr;
 	SortSubtask *pTask = pIncr->pTask;
 	sql *db = pTask->pSorter->db;
 
-	/* eMode is always INCRINIT_NORMAL in single-threaded mode */
-	assert(SQL_MAX_WORKER_THREADS > 0 || eMode == INCRINIT_NORMAL);
-
-	rc = vdbeMergeEngineInit(pTask, pIncr->pMerger, eMode);
+	rc = vdbeMergeEngineInit(pTask, pIncr->pMerger);
 
 	/* Set up the required files for pIncr. A multi-theaded IncrMerge object
 	 * requires two temp files to itself, whereas a single-threaded object
@@ -2208,74 +1828,27 @@ vdbePmaReaderIncrMergeInit(PmaReader * pReadr, int eMode)
 	 */
 	if (rc == SQL_OK) {
 		int mxSz = pIncr->mxSz;
-#if SQL_MAX_WORKER_THREADS>0
-		if (pIncr->bUseThread) {
-			rc = vdbeSorterOpenTempFile(db, mxSz,
-						    &pIncr->aFile[0].pFd);
-			if (rc == SQL_OK) {
-				rc = vdbeSorterOpenTempFile(db, mxSz,
-							    &pIncr->aFile[1].
-							    pFd);
-			}
-		} else
-#endif
-			/*if( !pIncr->bUseThread ) */  {
-			if (pTask->file2.pFd == 0) {
-				assert(pTask->file2.iEof > 0);
-				rc = vdbeSorterOpenTempFile(db,
-							    pTask->file2.iEof,
-							    &pTask->file2.pFd);
-				pTask->file2.iEof = 0;
-			}
-			if (rc == SQL_OK) {
-				pIncr->aFile[1].pFd = pTask->file2.pFd;
-				pIncr->iStartOff = pTask->file2.iEof;
-				pTask->file2.iEof += mxSz;
-			}
-			}
-	}
-#if SQL_MAX_WORKER_THREADS>0
-	if (rc == SQL_OK && pIncr->bUseThread) {
-		/* Use the current thread to populate aFile[1], even though this
-		 * PmaReader is multi-threaded. If this is an INCRINIT_TASK object,
-		 * then this function is already running in background thread
-		 * pIncr->pTask->thread.
-		 *
-		 * If this is the INCRINIT_ROOT object, then it is running in the
-		 * main VDBE thread. But that is Ok, as that thread cannot return
-		 * control to the VDBE or proceed with anything useful until the
-		 * first results are ready from this merger object anyway.
-		 */
-		assert(eMode == INCRINIT_ROOT || eMode == INCRINIT_TASK);
-		rc = vdbeIncrPopulate(pIncr);
+		if (pTask->file2.pFd == 0) {
+			assert(pTask->file2.iEof > 0);
+			rc = vdbeSorterOpenTempFile(db,
+						    pTask->file2.iEof,
+						    &pTask->file2.pFd);
+			pTask->file2.iEof = 0;
+		}
+		if (rc == SQL_OK) {
+			pIncr->aFile[1].pFd = pTask->file2.pFd;
+			pIncr->iStartOff = pTask->file2.iEof;
+			pTask->file2.iEof += mxSz;
+		}
 	}
-#endif
 
-	if (rc == SQL_OK
-	    && (SQL_MAX_WORKER_THREADS == 0 || eMode != INCRINIT_TASK)) {
+	if (rc == SQL_OK) {
 		rc = vdbePmaReaderNext(pReadr);
 	}
 
 	return rc;
 }
 
-#if SQL_MAX_WORKER_THREADS>0
-/*
- * The main routine for vdbePmaReaderIncrMergeInit() operations run in
- * background threads.
- */
-static void *
-vdbePmaReaderBgIncrInit(void *pCtx)
-{
-	PmaReader *pReader = (PmaReader *) pCtx;
-	void *pRet =
-	    SQL_INT_TO_PTR(vdbePmaReaderIncrMergeInit(pReader, INCRINIT_TASK)
-	    );
-	pReader->pIncr->pTask->bDone = 1;
-	return pRet;
-}
-#endif
-
 /*
  * If the PmaReader passed as the first argument is not an incremental-reader
  * (if pReadr->pIncr==0), then this function is a no-op. Otherwise, it invokes
@@ -2288,23 +1861,12 @@ vdbePmaReaderBgIncrInit(void *pCtx)
  * using the current thread.
  */
 static int
-vdbePmaReaderIncrInit(PmaReader * pReadr, int eMode)
+vdbePmaReaderIncrInit(PmaReader * pReadr)
 {
 	IncrMerger *pIncr = pReadr->pIncr;	/* Incremental merger */
 	int rc = SQL_OK;	/* Return code */
 	if (pIncr) {
-#if SQL_MAX_WORKER_THREADS>0
-		assert(pIncr->bUseThread == 0 || eMode == INCRINIT_TASK);
-		if (pIncr->bUseThread) {
-			void *pCtx = (void *)pReadr;
-			rc = vdbeSorterCreateThread(pIncr->pTask,
-						    vdbePmaReaderBgIncrInit,
-						    pCtx);
-		} else
-#endif
-		{
-			rc = vdbePmaReaderIncrMergeInit(pReadr, eMode);
-		}
+		rc = vdbePmaReaderIncrMergeInit(pReadr);
 	}
 	return rc;
 }
@@ -2451,23 +2013,10 @@ vdbeSorterMergeTreeBuild(VdbeSorter * pSorter,	/* The VDBE cursor that implement
 	int rc = SQL_OK;
 	int iTask;
 
-#if SQL_MAX_WORKER_THREADS>0
-	/* If the sorter uses more than one task, then create the top-level
-	 * MergeEngine here. This MergeEngine will read data from exactly
-	 * one PmaReader per sub-task.
-	 */
-	assert(pSorter->bUseThreads || pSorter->nTask == 1);
-	if (pSorter->nTask > 1) {
-		pMain = vdbeMergeEngineNew(pSorter->nTask);
-		if (pMain == 0)
-			rc = SQL_NOMEM;
-	}
-#endif
-
 	for (iTask = 0; rc == SQL_OK && iTask < pSorter->nTask; iTask++) {
 		SortSubtask *pTask = &pSorter->aTask[iTask];
-		assert(pTask->nPMA > 0 || SQL_MAX_WORKER_THREADS > 0);
-		if (SQL_MAX_WORKER_THREADS == 0 || pTask->nPMA) {
+		assert(pTask->nPMA > 0);
+		if (pTask->nPMA) {
 			MergeEngine *pRoot = 0;	/* Root node of tree for this task */
 			int nDepth = vdbeSorterTreeDepth(pTask->nPMA);
 			i64 iReadOff = 0;
@@ -2505,18 +2054,8 @@ vdbeSorterMergeTreeBuild(VdbeSorter * pSorter,	/* The VDBE cursor that implement
 			}
 
 			if (rc == SQL_OK) {
-#if SQL_MAX_WORKER_THREADS>0
-				if (pMain != 0) {
-					rc = vdbeIncrMergerNew(pTask, pRoot,
-							       &pMain->
-							       aReadr[iTask].
-							       pIncr);
-				} else
-#endif
-				{
-					assert(pMain == 0);
-					pMain = pRoot;
-				}
+				assert(pMain == 0);
+				pMain = pRoot;
 			} else {
 				vdbeMergeEngineFree(pRoot);
 			}
@@ -2546,88 +2085,12 @@ vdbeSorterSetupMerge(VdbeSorter * pSorter)
 	int rc;			/* Return code */
 	SortSubtask *pTask0 = &pSorter->aTask[0];
 	MergeEngine *pMain = 0;
-#if SQL_MAX_WORKER_THREADS
-	sql *db = pTask0->pSorter->db;
-	int i;
-	SorterCompare xCompare = vdbeSorterGetCompare(pSorter);
-	for (i = 0; i < pSorter->nTask; i++) {
-		pSorter->aTask[i].xCompare = xCompare;
-	}
-#endif
 
 	rc = vdbeSorterMergeTreeBuild(pSorter, &pMain);
 	if (rc == SQL_OK) {
-#if SQL_MAX_WORKER_THREADS
-		assert(pSorter->bUseThreads == 0 || pSorter->nTask > 1);
-		if (pSorter->bUseThreads) {
-			int iTask;
-			PmaReader *pReadr = 0;
-			SortSubtask *pLast =
-			    &pSorter->aTask[pSorter->nTask - 1];
-			rc = vdbeSortAllocUnpacked(pLast);
-			if (rc == SQL_OK) {
-				pReadr =
-				    (PmaReader *) sqlDbMallocZero(db,
-								      sizeof
-								      (PmaReader));
-				pSorter->pReader = pReadr;
-				if (pReadr == 0)
-					rc = SQL_NOMEM;
-			}
-			if (rc == SQL_OK) {
-				rc = vdbeIncrMergerNew(pLast, pMain,
-						       &pReadr->pIncr);
-				if (rc == SQL_OK) {
-					vdbeIncrMergerSetThreads(pReadr->pIncr);
-					for (iTask = 0;
-					     iTask < (pSorter->nTask - 1);
-					     iTask++) {
-						IncrMerger *pIncr;
-						if ((pIncr =
-						     pMain->aReadr[iTask].
-						     pIncr)) {
-							vdbeIncrMergerSetThreads
-							    (pIncr);
-							assert(pIncr->pTask !=
-							       pLast);
-						}
-					}
-					for (iTask = 0;
-					     rc == SQL_OK
-					     && iTask < pSorter->nTask;
-					     iTask++) {
-						/* Check that:
-						 *
-						 *   a) The incremental merge object is configured to use the
-						 *      right task, and
-						 *   b) If it is using task (nTask-1), it is configured to run
-						 *      in single-threaded mode. This is important, as the
-						 *      root merge (INCRINIT_ROOT) will be using the same task
-						 *      object.
-						 */
-						PmaReader *p =
-						    &pMain->aReadr[iTask];
-						assert(p->pIncr == 0 || ((p->pIncr->pTask == &pSorter->aTask[iTask])	/* a */
-									 &&(iTask != pSorter->nTask - 1 || p->pIncr->bUseThread == 0)	/* b */
-						       ));
-						rc = vdbePmaReaderIncrInit(p,
-									   INCRINIT_TASK);
-					}
-				}
-				pMain = 0;
-			}
-			if (rc == SQL_OK) {
-				rc = vdbePmaReaderIncrMergeInit(pReadr,
-								INCRINIT_ROOT);
-			}
-		} else
-#endif
-		{
-			rc = vdbeMergeEngineInit(pTask0, pMain,
-						 INCRINIT_NORMAL);
-			pSorter->pMerger = pMain;
-			pMain = 0;
-		}
+		rc = vdbeMergeEngineInit(pTask0, pMain);
+		pSorter->pMerger = pMain;
+		pMain = 0;
 	}
 
 	if (rc != SQL_OK) {
@@ -2676,8 +2139,6 @@ sqlVdbeSorterRewind(const VdbeCursor * pCsr, int *pbEof)
 	/* Join all threads */
 	rc = vdbeSorterJoinAll(pSorter, rc);
 
-	vdbeSorterRewindDebug("rewind");
-
 	/* Assuming no errors have occurred, set up a merger structure to
 	 * incrementally read and merge all remaining PMAs.
 	 */
@@ -2687,7 +2148,6 @@ sqlVdbeSorterRewind(const VdbeCursor * pCsr, int *pbEof)
 		*pbEof = 0;
 	}
 
-	vdbeSorterRewindDebug("rewinddone");
 	return rc;
 }
 
@@ -2708,12 +2168,6 @@ sqlVdbeSorterNext(sql * db, const VdbeCursor * pCsr, int *pbEof)
 		assert(pSorter->pReader == 0 || pSorter->pMerger == 0);
 		assert(pSorter->bUseThreads == 0 || pSorter->pReader);
 		assert(pSorter->bUseThreads == 1 || pSorter->pMerger);
-#if SQL_MAX_WORKER_THREADS>0
-		if (pSorter->bUseThreads) {
-			rc = vdbePmaReaderNext(pSorter->pReader);
-			*pbEof = (pSorter->pReader->pFd == 0);
-		} else
-#endif
 			/*if( !pSorter->bUseThreads ) */  {
 			assert(pSorter->pMerger != 0);
 			assert(pSorter->pMerger->pTask == (&pSorter->aTask[0]));
@@ -2743,11 +2197,6 @@ vdbeSorterRowkey(const VdbeSorter * pSorter,	/* Sorter object */
 	void *pKey;
 	if (pSorter->bUsePMA) {
 		PmaReader *pReader;
-#if SQL_MAX_WORKER_THREADS>0
-		if (pSorter->bUseThreads) {
-			pReader = pSorter->pReader;
-		} else
-#endif
 			/*if( !pSorter->bUseThreads ) */  {
 			pReader =
 			    &pSorter->pMerger->aReadr[pSorter->pMerger->
diff --git a/src/box/sql/where.c b/src/box/sql/where.c
index efd4f4f4b..c38b60b0f 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -684,225 +684,6 @@ translateColumnToCopy(Vdbe * v,		/* The VDBE containing code to translate */
 	}
 }
 
-#ifndef SQL_OMIT_AUTOMATIC_INDEX
-/*
- * Return TRUE if the WHERE clause term pTerm is of a form where it
- * could be used with an index to access pSrc, assuming an appropriate
- * index existed.
- */
-static int
-termCanDriveIndex(WhereTerm * pTerm,	/* WHERE clause term to check */
-		  struct SrcList_item *pSrc,	/* Table we are trying to access */
-		  Bitmask notReady	/* Tables in outer loops of the join */
-    )
-{
-	if (pTerm->leftCursor != pSrc->iCursor)
-		return 0;
-	if ((pTerm->eOperator & WO_EQ) == 0)
-		return 0;
-	if ((pTerm->prereqRight & notReady) != 0)
-		return 0;
-	if (pTerm->u.leftColumn < 0)
-		return 0;
-	enum field_type type = pSrc->pTab->def->fields[pTerm->u.leftColumn].type;
-	enum field_type expr_type = expr_cmp_mutual_type(pTerm->pExpr);
-	if (!field_type1_contains_type2(expr_type, type))
-		return 0;
-	return 1;
-}
-#endif
-
-#ifndef SQL_OMIT_AUTOMATIC_INDEX
-/*
- * Generate code to construct the Index object for an automatic index
- * and to set up the WhereLevel object pLevel so that the code generator
- * makes use of the automatic index.
- */
-static void
-constructAutomaticIndex(Parse * pParse,			/* The parsing context */
-			WhereClause * pWC,		/* The WHERE clause */
-			struct SrcList_item *pSrc,	/* The FROM clause term to get the next index */
-			Bitmask notReady,		/* Mask of cursors that are not available */
-			WhereLevel * pLevel)		/* Write new index here */
-{
-	int nKeyCol;		/* Number of columns in the constructed index */
-	WhereTerm *pTerm;	/* A single term of the WHERE clause */
-	WhereTerm *pWCEnd;	/* End of pWC->a[] */
-	Index *pIdx;		/* Object describing the transient index */
-	Vdbe *v;		/* Prepared statement under construction */
-	int addrInit;		/* Address of the initialization bypass jump */
-	Table *pTable;		/* The table being indexed */
-	int addrTop;		/* Top of the index fill loop */
-	int regRecord;		/* Register holding an index record */
-	int n;			/* Column counter */
-	int i;			/* Loop counter */
-	int mxBitCol;		/* Maximum column in pSrc->colUsed */
-	struct coll *pColl;		/* Collating sequence to on a column */
-	WhereLoop *pLoop;	/* The Loop object */
-	char *zNotUsed;		/* Extra space on the end of pIdx */
-	Bitmask idxCols;	/* Bitmap of columns used for indexing */
-	Bitmask extraCols;	/* Bitmap of additional columns */
-	u8 sentWarning = 0;	/* True if a warnning has been issued */
-	int iContinue = 0;	/* Jump here to skip excluded rows */
-	struct SrcList_item *pTabItem;	/* FROM clause term being indexed */
-	int addrCounter = 0;	/* Address where integer counter is initialized */
-	int regBase;		/* Array of registers where record is assembled */
-
-	/* Generate code to skip over the creation and initialization of the
-	 * transient index on 2nd and subsequent iterations of the loop.
-	 */
-	v = pParse->pVdbe;
-	assert(v != 0);
-	addrInit = sqlVdbeAddOp0(v, OP_Once);
-	VdbeCoverage(v);
-
-	/* Count the number of columns that will be added to the index
-	 * and used to match WHERE clause constraints
-	 */
-	nKeyCol = 0;
-	pTable = pSrc->pTab;
-	pWCEnd = &pWC->a[pWC->nTerm];
-	pLoop = pLevel->pWLoop;
-	idxCols = 0;
-	for (pTerm = pWC->a; pTerm < pWCEnd; pTerm++) {
-		if (termCanDriveIndex(pTerm, pSrc, notReady)) {
-			int iCol = pTerm->u.leftColumn;
-			Bitmask cMask =
-			    iCol >= BMS ? MASKBIT(BMS - 1) : MASKBIT(iCol);
-			testcase(iCol == BMS);
-			testcase(iCol == BMS - 1);
-			if (!sentWarning) {
-				sql_log(SQL_WARNING_AUTOINDEX,
-					    "automatic index on %s(%s)",
-					    pTable->def->name,
-					    pTable->aCol[iCol].zName);
-				sentWarning = 1;
-			}
-			if ((idxCols & cMask) == 0) {
-				if (whereLoopResize
-				    (pParse->db, pLoop, nKeyCol + 1)) {
-					goto end_auto_index_create;
-				}
-				pLoop->aLTerm[nKeyCol++] = pTerm;
-				idxCols |= cMask;
-			}
-		}
-	}
-	assert(nKeyCol > 0);
-	pLoop->nEq = pLoop->nLTerm = nKeyCol;
-	pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED
-	    | WHERE_AUTO_INDEX;
-
-	/* Count the number of additional columns needed to create a
-	 * covering index.  A "covering index" is an index that contains all
-	 * columns that are needed by the query.  With a covering index, the
-	 * original table never needs to be accessed.  Automatic indices must
-	 * be a covering index because the index will not be updated if the
-	 * original table changes and the index and table cannot both be used
-	 * if they go out of sync.
-	 */
-	extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS - 1));
-	mxBitCol = MIN(BMS - 1, pTable->def->field_count);
-	testcase(pTable->def->field_count == BMS - 1);
-	testcase(pTable->def->field_count == BMS - 2);
-	for (i = 0; i < mxBitCol; i++) {
-		if (extraCols & MASKBIT(i))
-			nKeyCol++;
-	}
-	if (pSrc->colUsed & MASKBIT(BMS - 1)) {
-		nKeyCol += pTable->def->field_count - BMS + 1;
-	}
-
-	/* Construct the Index object to describe this index */
-	pIdx = sqlDbMallocZero(pParse->db, sizeof(*pIdx));
-	if (pIdx == 0)
-		goto end_auto_index_create;
-	pLoop->pIndex = pIdx;
-	pIdx->zName = "auto-index";
-	pIdx->pTable = pTable;
-	n = 0;
-	idxCols = 0;
-	for (pTerm = pWC->a; pTerm < pWCEnd; pTerm++) {
-		if (termCanDriveIndex(pTerm, pSrc, notReady)) {
-			int iCol = pTerm->u.leftColumn;
-			Bitmask cMask =
-			    iCol >= BMS ? MASKBIT(BMS - 1) : MASKBIT(iCol);
-			testcase(iCol == BMS - 1);
-			testcase(iCol == BMS);
-			if ((idxCols & cMask) == 0) {
-				Expr *pX = pTerm->pExpr;
-				idxCols |= cMask;
-				pIdx->aiColumn[n] = pTerm->u.leftColumn;
-				n++;
-			}
-		}
-	}
-	assert((u32) n == pLoop->nEq);
-
-	/* Add additional columns needed to make the automatic index into
-	 * a covering index
-	 */
-	for (i = 0; i < mxBitCol; i++) {
-		if (extraCols & MASKBIT(i)) {
-			pIdx->aiColumn[n] = i;
-			n++;
-		}
-	}
-	if (pSrc->colUsed & MASKBIT(BMS - 1)) {
-		for (i = BMS - 1; i < (int)pTable->def->field_count; i++) {
-			pIdx->aiColumn[n] = i;
-			n++;
-		}
-	}
-	assert(n == nKeyCol);
-	pIdx->aiColumn[n] = XN_ROWID;
-
-	/* Create the automatic index */
-	assert(pLevel->iIdxCur >= 0);
-	pLevel->iIdxCur = pParse->nTab++;
-	sqlVdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol + 1);
-	sql_vdbe_set_p4_key_def(pParse, pIdx->key_def);
-	VdbeComment((v, "for %s", pTable->def->name));
-
-	/* Fill the automatic index with content */
-	sqlExprCachePush(pParse);
-	pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
-	if (pTabItem->fg.viaCoroutine) {
-		int regYield = pTabItem->regReturn;
-		addrCounter = sqlVdbeAddOp2(v, OP_Integer, 0, 0);
-		sqlVdbeAddOp3(v, OP_InitCoroutine, regYield, 0,
-				  pTabItem->addrFillSub);
-		addrTop = sqlVdbeAddOp1(v, OP_Yield, regYield);
-		VdbeCoverage(v);
-		VdbeComment((v, "next row of \"%s\"", pTabItem->pTab->zName));
-	} else {
-		addrTop = sqlVdbeAddOp1(v, OP_Rewind, pLevel->iTabCur);
-		VdbeCoverage(v);
-	}
-	regRecord = sqlGetTempReg(pParse);
-	regBase = sql_generate_index_key(pParse, pIdx, pLevel->iTabCur,
-					 regRecord, NULL, 0);
-	sqlVdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
-	if (pTabItem->fg.viaCoroutine) {
-		sqlVdbeChangeP2(v, addrCounter, regBase + n);
-		translateColumnToCopy(v, addrTop, pLevel->iTabCur,
-				      pTabItem->regResult, 1);
-		sqlVdbeGoto(v, addrTop);
-		pTabItem->fg.viaCoroutine = 0;
-	} else {
-		sqlVdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop + 1);
-		VdbeCoverage(v);
-	}
-	sqlVdbeChangeP5(v, SQL_STMTSTATUS_AUTOINDEX);
-	sqlVdbeJumpHere(v, addrTop);
-	sqlReleaseTempReg(pParse, regRecord);
-	sqlExprCachePop(pParse);
-
-	/* Jump here when skipping the initialization */
-	sqlVdbeJumpHere(v, addrInit);
-}
-#endif				/* SQL_OMIT_AUTOMATIC_INDEX */
-
 /*
  * Estimate the location of a particular key among all keys in an
  * index.  Store the results in aStat as follows:
@@ -2828,61 +2609,6 @@ tnt_error:
 		probe = fake_index;
 	}
 
-#ifndef SQL_OMIT_AUTOMATIC_INDEX
-	/* Automatic indexes */
-	LogEst rSize = pTab->nRowLogEst;
-	LogEst rLogSize = estLog(rSize);
-	struct session *user_session = current_session();
-	if (!pBuilder->pOrSet	/* Not part of an OR optimization */
-	    && (pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE) == 0 && (user_session->sql_flags & SQL_AutoIndex) != 0 && pSrc->pIBIndex == 0	/* Has no INDEXED BY clause */
-	    && !pSrc->fg.notIndexed	/* Has no NOT INDEXED clause */
-	    && HasRowid(pTab)	/* Not WITHOUT ROWID table. (FIXME: Why not?) */
-	    &&!pSrc->fg.isCorrelated	/* Not a correlated subquery */
-	    && !pSrc->fg.isRecursive	/* Not a recursive common table expression. */
-	    ) {
-		/* Generate auto-index WhereLoops */
-		WhereTerm *pTerm;
-		WhereTerm *pWCEnd = pWC->a + pWC->nTerm;
-		for (pTerm = pWC->a; rc == SQL_OK && pTerm < pWCEnd; pTerm++) {
-			if (pTerm->prereqRight & pNew->maskSelf)
-				continue;
-			if (termCanDriveIndex(pTerm, pSrc, 0)) {
-				pNew->nEq = 1;
-				pNew->nSkip = 0;
-				pNew->pIndex = 0;
-				pNew->nLTerm = 1;
-				pNew->aLTerm[0] = pTerm;
-				/* TUNING: One-time cost for computing the automatic index is
-				 * estimated to be X*N*log2(N) where N is the number of rows in
-				 * the table being indexed and where X is 7 (LogEst=28) for normal
-				 * tables or 1.375 (LogEst=4) for views and subqueries.  The value
-				 * of X is smaller for views and subqueries so that the query planner
-				 * will be more aggressive about generating automatic indexes for
-				 * those objects, since there is no opportunity to add schema
-				 * indexes on subqueries and views.
-				 */
-				pNew->rSetup = rLogSize + rSize + 4;
-				if (!pTab->def->opts.is_view &&
-				    pTab->def->id == 0)
-					pNew->rSetup += 24;
-				if (pNew->rSetup < 0)
-					pNew->rSetup = 0;
-				/* TUNING: Each index lookup yields 20 rows in the table.  This
-				 * is more than the usual guess of 10 rows, since we have no way
-				 * of knowing how selective the index will ultimately be.  It would
-				 * not be unreasonable to make this value much larger.
-				 */
-				pNew->nOut = 43;
-				assert(43 == sqlLogEst(20));
-				pNew->rRun =
-				    sqlLogEstAdd(rLogSize, pNew->nOut);
-				pNew->wsFlags = WHERE_AUTO_INDEX;
-				pNew->prereq = mPrereq | pTerm->prereqRight;
-				rc = whereLoopInsert(pBuilder, pNew);
-			}
-		}
-	}
-#endif				/* SQL_OMIT_AUTOMATIC_INDEX */
 	/*
 	 * If there was an INDEXED BY clause, then only that one
 	 * index is considered.
@@ -4561,12 +4287,6 @@ sqlWhereBegin(Parse * pParse,	/* The parser context */
 			VdbeComment((v, "%s", space->def->name));
 			assert(pTabItem->iCursor == pLevel->iTabCur);
 			sqlVdbeChangeP5(v, bFordelete);
-#ifdef SQL_ENABLE_COLUMN_USED_MASK
-			sqlVdbeAddOp4Dup8(v, OP_ColumnsUsed,
-					      pTabItem->iCursor, 0, 0,
-					      (const u8 *)&pTabItem->colUsed,
-					      P4_INT64);
-#endif
 		}
 		if (pLoop->wsFlags & WHERE_INDEXED) {
 			struct index_def *idx_def = pLoop->index_def;
@@ -4641,30 +4361,6 @@ sqlWhereBegin(Parse * pParse,	/* The parser context */
 					sqlVdbeChangeP5(v, OPFLAG_SEEKEQ);	/* Hint to COMDB2 */
 				}
 				VdbeComment((v, "%s", idx_def->name));
-#ifdef SQL_ENABLE_COLUMN_USED_MASK
-				{
-					u64 colUsed = 0;
-					int ii, jj;
-					for (ii = 0; ii < pIx->nColumn; ii++) {
-						jj = pIx->aiColumn[ii];
-						if (jj < 0)
-							continue;
-						if (jj > 63)
-							jj = 63;
-						if ((pTabItem->
-						     colUsed & MASKBIT(jj)) ==
-						    0)
-							continue;
-						colUsed |=
-						    ((u64) 1) << (ii <
-								  63 ? ii : 63);
-					}
-					sqlVdbeAddOp4Dup8(v, OP_ColumnsUsed,
-							      iIndexCur, 0, 0,
-							      (u8 *) & colUsed,
-							      P4_INT64);
-				}
-#endif				/* SQL_ENABLE_COLUMN_USED_MASK */
 			}
 		}
 	}
@@ -4679,15 +4375,6 @@ sqlWhereBegin(Parse * pParse,	/* The parser context */
 	notReady = ~(Bitmask) 0;
 	for (ii = 0; ii < nTabList; ii++) {
 		pLevel = &pWInfo->a[ii];
-#ifndef SQL_OMIT_AUTOMATIC_INDEX
-		if ((pLevel->pWLoop->wsFlags & WHERE_AUTO_INDEX) != 0) {
-			constructAutomaticIndex(pParse, &pWInfo->sWC,
-						&pTabList->a[pLevel->iFrom],
-						notReady, pLevel);
-			if (db->mallocFailed)
-				goto whereBeginError;
-		}
-#endif
 		sqlWhereExplainOneScan(pParse, pTabList, pLevel, ii,
 					       pLevel->iFrom, wctrlFlags);
 		pLevel->addrBody = sqlVdbeCurrentAddr(v);
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 4dedb38a7..01fa138f6 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -253,14 +253,6 @@ sqlWhereExplainOneScan(Parse * pParse,	/* Parse context */
 				       " USING INTEGER PRIMARY KEY (rowid%s?)",
 				       zRangeOp);
 		}
-#ifdef SQL_EXPLAIN_ESTIMATED_ROWS
-		if (pLoop->nOut >= 10) {
-			sqlXPrintf(&str, " (~%llu rows)",
-				       sqlLogEstToInt(pLoop->nOut));
-		} else {
-			sqlStrAccumAppend(&str, " (~1 row)", 9);
-		}
-#endif
 		zMsg = sqlStrAccumFinish(&str);
 		ret =
 		    sqlVdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,
-- 
2.17.1





More information about the Tarantool-patches mailing list