[tarantool-patches] [PATCH v2 6/9] sql: cleanup code from obsolete macros

Stanislav Zudin szudin at tarantool.org
Wed May 29 17:01:28 MSK 2019


Removes the following unused macros:
SQL_EXPLAIN_ESTIMATED_ROWS
SQL_ENABLE_COLUMN_USED_MASK
SQL_DISABLE_DIRSYNC
SQL_DEBUG_SORTER_THREADS
SQL_DEFAULT_WORKER_THREADS
SQL_LIMIT_WORKER_THREADS
SQL_MAX_WORKER_THREADS

Updates tests.

Part of #3978
---
 src/box/sql/CMakeLists.txt               |   1 -
 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                      |  30 --
 src/box/sql/wherecode.c                  |   4 +-
 test/sql-tap/collation.test.lua          |   6 +-
 test/sql-tap/eqp.test.lua                | 246 ++++-----
 test/sql-tap/gh-2996-indexed-by.test.lua |  12 +-
 test/sql-tap/index6.test.lua             |   4 +-
 test/sql-tap/index7.test.lua             |   2 +-
 test/sql-tap/lua-tables.test.lua         |   4 +-
 test/sql-tap/tkt-385a5b56b9.test.lua     |  26 +-
 test/sql-tap/tkt-b75a9ca6b0.test.lua     |   4 +-
 test/sql-tap/tkt3442.test.lua            |   4 +-
 test/sql-tap/where3.test.lua             |   6 +-
 test/sql-tap/whereG.test.lua             |  16 +-
 test/sql/row-count.result                |   2 +-
 23 files changed, 213 insertions(+), 866 deletions(-)

diff --git a/src/box/sql/CMakeLists.txt b/src/box/sql/CMakeLists.txt
index b9dbe141a..7059b57cf 100644
--- a/src/box/sql/CMakeLists.txt
+++ b/src/box/sql/CMakeLists.txt
@@ -10,7 +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
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 807fdd440..1d1401f2c 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. */
@@ -956,17 +955,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.
  *
@@ -1307,7 +1295,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
@@ -4869,13 +4857,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 5c7605a31..020a4e4a8 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..1e8c721af 100644
--- a/src/box/sql/where.c
+++ b/src/box/sql/where.c
@@ -4561,12 +4561,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 +4635,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 */
 			}
 		}
 	}
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 4dedb38a7..c9a2b7dcb 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -253,14 +253,14 @@ 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,
diff --git a/test/sql-tap/collation.test.lua b/test/sql-tap/collation.test.lua
index 0bf54576d..79547361c 100755
--- a/test/sql-tap/collation.test.lua
+++ b/test/sql-tap/collation.test.lua
@@ -452,7 +452,7 @@ for _, data_collation in ipairs(data_collations) do
         test:do_execsql_test(
             extendex_prefix.."select_plan_contains_b-tree",
             string.format("explain query plan select b from t1 order by b %s;",data_collation[1]),
-            {0,0,0,"SCAN TABLE T1",
+            {0,0,0,"SCAN TABLE T1 (~1048576 rows)",
                 0,0,0,"USE TEMP B-TREE FOR ORDER BY"})
         test:do_execsql_test(
             extendex_prefix.."select",
@@ -465,7 +465,7 @@ for _, data_collation in ipairs(data_collations) do
         test:do_execsql_test(
             extendex_prefix.."select_from_index_plan_does_not_contain_b-tree",
             string.format("explain query plan select b from t1 order by b %s;",data_collation[1]),
-            {0,0,0,"SCAN TABLE T1 USING COVERING INDEX I"})
+            {0,0,0,"SCAN TABLE T1 USING COVERING INDEX I (~1048576 rows)"})
         test:do_execsql_test(
             extendex_prefix.."select_from_index",
             string.format("select b from t1 order by b %s;",data_collation[1]),
@@ -494,7 +494,7 @@ local like_testcases =
         {0, {"Aab", "aaa"}} },
     {"2.1.2",
         "EXPLAIN QUERY PLAN SELECT * FROM tx1 WHERE s1 LIKE 'A%';",
-        {0, {0, 0, 0, "SEARCH TABLE TX1 USING COVERING INDEX I1 (S1>? AND S1<?)"}}},
+        {0, {0, 0, 0, "SEARCH TABLE TX1 USING COVERING INDEX I1 (S1>? AND S1<?) (~16384 rows)"}}},
     {"2.2.0",
         "PRAGMA case_sensitive_like = true;",
         {0}},
diff --git a/test/sql-tap/eqp.test.lua b/test/sql-tap/eqp.test.lua
index 2aa2d9675..b8c3c6607 100755
--- a/test/sql-tap/eqp.test.lua
+++ b/test/sql-tap/eqp.test.lua
@@ -30,7 +30,7 @@ local testprefix = "eqp"
 --
 
 test:do_execsql_test(
-    1.1,
+    "1.1",
     [[
         CREATE TABLE t1(idt1  INT primary key, a INT, b INT, ex TEXT);
         CREATE INDEX i1 ON t1(a);
@@ -40,67 +40,67 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test(
-    1.2,
+    "1.2",
     [[
         SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2;
     ]], {
         -- <1.2>
-        {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
-        {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (B=?)"},
-        {0, 1, 0, "SCAN TABLE T2"}
+        {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
+        {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (B=?) (~10 rows)"},
+        {0, 1, 0, "SCAN TABLE T2 (~1048576 rows)"}
         -- </1.2>
     })
 
 test:do_eqp_test(
-    1.3,
+    "1.3",
     [[
         SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2;
     ]], {
         -- <1.3>
-        {0, 0, 0, "SCAN TABLE T2"},
-        {0, 1, 1, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
-        {0, 1, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (B=?)"}
+        {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
+        {0, 1, 1, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
+        {0, 1, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (B=?) (~10 rows)"}
         -- </1.3>
     })
 
 test:do_eqp_test(
-    1.3,
+    "1.3",
     [[
         SELECT a FROM t1 ORDER BY a
     ]], {
         -- <1.3>
-        {0, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1"}
+        {0, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1 (~1048576 rows)"}
         -- </1.3>
     })
 
 test:do_eqp_test(
-    1.4,
+    "1.4",
     [[
         SELECT a FROM t1 ORDER BY +a
     ]], {
         -- <1.4>
-        {0, 0, 0, "SCAN TABLE T1"},
+        {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"}
         -- </1.4>
     })
 
 test:do_eqp_test(
-    1.5,
+    "1.5",
     [[
         SELECT a FROM t1 WHERE a=4
     ]], {
         -- <1.5>
-        {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"}
+        {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"}
         -- </1.5>
     })
 
 test:do_eqp_test(
-    1.6,
+    "1.6",
     [[
         SELECT DISTINCT count(*) FROM t3 GROUP BY a;
     ]], {
         -- <1.6>
-        {0, 0, 0, "SCAN TABLE T3"},
+        {0, 0, 0, "SCAN TABLE T3 (~1048576 rows)"},
         {0, 0, 0, "USE TEMP B-TREE FOR GROUP BY"},
         {0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
         
@@ -108,40 +108,40 @@ test:do_eqp_test(
     })
 
 test:do_eqp_test(
-    1.7,
+    "1.7",
     [[
         SELECT * FROM t3 JOIN (SELECT 1)
     ]], {
         -- <1.7>
-        {0, 0, 1, "SCAN SUBQUERY 1"},
-        {0, 1, 0, "SCAN TABLE T3"},
+        {0, 0, 1, "SCAN SUBQUERY 1 (~1 row)"},
+        {0, 1, 0, "SCAN TABLE T3 (~1048576 rows)"},
         
         -- </1.7>
     })
 
 test:do_eqp_test(
-    1.8,
+    "1.8",
     [[
         SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2)
     ]], {
         -- <1.8>
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)"},
-        {0, 0, 1, "SCAN SUBQUERY 1"},
-        {0, 1, 0, "SCAN TABLE T3"},
+        {0, 0, 1, "SCAN SUBQUERY 1 (~1 row)"},
+        {0, 1, 0, "SCAN TABLE T3 (~1048576 rows)"},
         
         -- </1.8>
     })
 
 test:do_eqp_test(
-    1.9,
+    "1.9",
     [[
         SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17)
     ]], {
         -- <1.9>
-        {3, 0, 0, "SCAN TABLE T3"},
+        {3, 0, 0, "SCAN TABLE T3 (~1048576 rows)"},
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)"},
-        {0, 0, 1,"SCAN SUBQUERY 1"},
-        {0, 1, 0,"SCAN TABLE T3"},
+        {0, 0, 1,"SCAN SUBQUERY 1 (~1 row)"},
+        {0, 1, 0,"SCAN TABLE T3 (~1048576 rows)"},
 
         -- </1.9>
     })
@@ -152,24 +152,24 @@ test:do_eqp_test(
         SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17)
     ]], {
         -- <1.10>
-        {3, 0, 0, "SCAN TABLE T3"},
+        {3, 0, 0, "SCAN TABLE T3 (~1048576 rows)"},
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)"},
-        {0, 0, 1, "SCAN SUBQUERY 1"},
-        {0, 1, 0, "SCAN TABLE T3"},
+        {0, 0, 1, "SCAN SUBQUERY 1 (~1 row)"},
+        {0, 1, 0, "SCAN TABLE T3 (~1048576 rows)"},
         
         -- </1.10>
     })
 
 test:do_eqp_test(
-    1.11,
+    "1.11",
     [[
         SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17)
     ]], {
         -- <1.11>
-        {3, 0, 0, "SCAN TABLE T3"},
+        {3, 0, 0, "SCAN TABLE T3 (~1048576 rows)"},
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)"},
-        {0, 0, 1, "SCAN SUBQUERY 1"},
-        {0, 1, 0, "SCAN TABLE T3"},
+        {0, 0, 1, "SCAN SUBQUERY 1 (~1 row)"},
+        {0, 1, 0, "SCAN TABLE T3 (~1048576 rows)"},
         
         -- </1.11>
     })
@@ -179,7 +179,7 @@ test:do_eqp_test(
 --
 test:drop_all_tables()
 test:do_execsql_test(
-    2.1,
+    "2.1",
     [[
         CREATE TABLE t1(idt1  INT primary key, x INT, y INT, ex TEXT);
 
@@ -188,13 +188,13 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test("2.2.1", "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1", {
-    {0, 0, 0, "SCAN TABLE T1"},
+    {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
     {0, 0, 0, "USE TEMP B-TREE FOR GROUP BY"},
     {0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
 test:do_eqp_test("2.2.2", "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1", {
-    {0, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+    {0, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
     {0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
@@ -204,34 +204,34 @@ test:do_eqp_test("2.2.2", "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORD
 --    {0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
 --})
 test:do_eqp_test("2.2.4", "SELECT DISTINCT * FROM t1, t2", {
-    {0, 0, 0, "SCAN TABLE T1"},
+    {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
     -- changed after reordering indexes
     -- actually it does not matter (in fact, it seems like pk should have been used in both cases)
     --{0, 1, 1, "SCAN TABLE T2 USING COVERING INDEX t2i1"},
-    {0, 1, 1, "SCAN TABLE T2"},
+    {0, 1, 1, "SCAN TABLE T2 (~1048576 rows)"},
     --{0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
 })
 test:do_eqp_test("2.2.5", "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x", {
-    {0, 0, 0, "SCAN TABLE T1"},
-    {0, 1, 1, "SCAN TABLE T2"},
+    {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
+    {0, 1, 1, "SCAN TABLE T2 (~1048576 rows)"},
     --{0, 0, 0, "USE TEMP B-TREE FOR DISTINCT"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
 test:do_eqp_test("2.2.6", "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x", {
-    {0, 0, 1, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
-    {0, 1, 0, "SCAN TABLE T1"},
+    {0, 0, 1, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
+    {0, 1, 0, "SCAN TABLE T1 (~1048576 rows)"},
 })
 test:do_eqp_test("2.3.1", "SELECT max(x) FROM t2", {
-    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2I1"},
+    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
 })
 test:do_eqp_test("2.3.2", "SELECT min(x) FROM t2", {
-    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2I1"},
+    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
 })
 test:do_eqp_test("2.3.3", "SELECT min(x), max(x) FROM t2", {
-    {0, 0, 0, "SCAN TABLE T2"},
+    {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
 })
 test:do_eqp_test("2.4.1", "SELECT * FROM t1 WHERE idt1=?", {
-    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (IDT1=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (IDT1=?) (~1 row)"},
 })
 ---------------------------------------------------------------------------
 -- Test cases eqp-3.* - tests for select statements that use sub-selects.
@@ -242,9 +242,9 @@ test:do_eqp_test(
         SELECT (SELECT x FROM t1 AS sub) FROM t1;
     ]], {
         -- <3.1.1>
-        {0, 0, 0, "SCAN TABLE T1"},
+        {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "EXECUTE SCALAR SUBQUERY 1"},
-        {1, 0, 0, "SCAN TABLE T1 AS SUB"},
+        {1, 0, 0, "SCAN TABLE T1 AS SUB (~1048576 rows)"},
         
         -- </3.1.1>
     })
@@ -255,9 +255,9 @@ test:do_eqp_test(
         SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub);
     ]], {
         -- <3.1.2>
-        {0, 0, 0, "SCAN TABLE T1"},
+        {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "EXECUTE SCALAR SUBQUERY 1"},
-        {1, 0, 0, "SCAN TABLE T1 AS SUB"},
+        {1, 0, 0, "SCAN TABLE T1 AS SUB (~1048576 rows)"},
         
         -- </3.1.2>
     })
@@ -268,9 +268,9 @@ test:do_eqp_test(
         SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y);
     ]], {
         -- <3.1.3>
-        {0, 0, 0, "SCAN TABLE T1"},
+        {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "EXECUTE SCALAR SUBQUERY 1"},
-        {1, 0, 0, "SCAN TABLE T1 AS SUB"},
+        {1, 0, 0, "SCAN TABLE T1 AS SUB (~1048576 rows)"},
         {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
         
         -- </3.1.3>
@@ -282,9 +282,9 @@ test:do_eqp_test(
         SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x);
     ]], {
         -- <3.1.4>
-        {0, 0, 0, "SCAN TABLE T1"},
+        {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "EXECUTE SCALAR SUBQUERY 1"},
-        {1, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {1, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         
         -- </3.1.4>
     })
@@ -292,9 +292,9 @@ test:do_eqp_test(
 test:do_eqp_test("3.2.1", [[
   SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5
 ]], {
-    {1, 0, 0, "SCAN TABLE T1"}, 
+    {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
     {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"}, 
-    {0, 0, 0, "SCAN SUBQUERY 1"}, 
+    {0, 0, 0, "SCAN SUBQUERY 1 (~1 row)"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
 test:do_eqp_test("3.2.2", [[
@@ -303,33 +303,33 @@ test:do_eqp_test("3.2.2", [[
     (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2
   ORDER BY x2.y LIMIT 5
 ]], {
-    {1, 0, 0, "SCAN TABLE T1"}, 
+    {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
     {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"}, 
-    {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
-    {0, 0, 0, "SCAN SUBQUERY 1 AS X1"}, 
-    {0, 1, 1, "SCAN SUBQUERY 2 AS X2"}, 
+    {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
+    {0, 0, 0, "SCAN SUBQUERY 1 AS X1 (~1 row)"},
+    {0, 1, 1, "SCAN SUBQUERY 2 AS X2 (~1 row)"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
 test:do_eqp_test("3.3.1", [[
   SELECT * FROM t1 WHERE y IN (SELECT y FROM t2)
 ]], {
-    {0, 0, 0, "SCAN TABLE T1"}, 
+    {0, 0, 0, "SCAN TABLE T1 (~983040 rows)"},
     {0, 0, 0, "EXECUTE LIST SUBQUERY 1"}, 
-    {1, 0, 0, "SCAN TABLE T2"},
+    {1, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
 })
 test:do_eqp_test("3.3.2", [[
   SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x)
 ]], {
-    {0, 0, 0, "SCAN TABLE T1"}, 
+    {0, 0, 0, "SCAN TABLE T1 (~983040 rows)"},
     {0, 0, 0, "EXECUTE CORRELATED LIST SUBQUERY 1"}, 
-    {1, 0, 0, "SCAN TABLE T2"},
+    {1, 0, 0, "SCAN TABLE T2 (~983040 rows)"},
 })
 test:do_eqp_test("3.3.3", [[
   SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x)
 ]], {
-    {0, 0, 0, "SCAN TABLE T1"}, 
+    {0, 0, 0, "SCAN TABLE T1 (~983040 rows)"},
     {0, 0, 0, "EXECUTE CORRELATED SCALAR SUBQUERY 1"}, 
-    {1, 0, 0, "SCAN TABLE T2"},
+    {1, 0, 0, "SCAN TABLE T2 (~983040 rows)"},
 })
 ---------------------------------------------------------------------------
 -- Test cases eqp-4.* - tests for composite select statements.
@@ -340,8 +340,8 @@ test:do_eqp_test(
         SELECT * FROM t1 UNION ALL SELECT * FROM t2
     ]], {
         -- <4.1.1>
-        {1, 0, 0, "SCAN TABLE T1"},
-        {2, 0, 0, "SCAN TABLE T2"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
+        {2, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)"},
         
         -- </4.1.1>
@@ -353,9 +353,9 @@ test:do_eqp_test(
         SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2
     ]], {
         -- <4.1.2>
-        {1, 0, 0, "SCAN TABLE T1"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
-        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)"},
         
         -- </4.1.2>
@@ -367,9 +367,9 @@ test:do_eqp_test(
         SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2
     ]], {
         -- <4.1.3>
-        {1, 0, 0, "SCAN TABLE T1"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
-        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         {2, 0, 0, "USE TEMP B-TREE FOR RIGHT PART OF ORDER BY"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (UNION)"},
         
@@ -382,9 +382,9 @@ test:do_eqp_test(
         SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2
     ]], {
         -- <4.1.4>
-        {1, 0, 0, "SCAN TABLE T1"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
-        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         {2, 0, 0, "USE TEMP B-TREE FOR RIGHT PART OF ORDER BY"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)"},
         
@@ -397,9 +397,9 @@ test:do_eqp_test(
         SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2
     ]], {
         -- <4.1.5>
-        {1, 0, 0, "SCAN TABLE T1"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {1, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
-        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {2, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         {2, 0, 0, "USE TEMP B-TREE FOR RIGHT PART OF ORDER BY"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)"}
         -- </4.1.5>
@@ -470,8 +470,8 @@ test:do_eqp_test(
         SELECT x FROM t1 UNION SELECT x FROM t2
     ]], {
         -- <4.3.1>
-        {1, 0, 0, "SCAN TABLE T1"},
-        {2, 0, 0, "SCAN TABLE T2"},
+        {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
+        {2, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)"},
         
         -- </4.3.1>
@@ -483,10 +483,10 @@ test:do_eqp_test(
         SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1
     ]], {
         -- <4.3.2>
-        {2, 0, 0, "SCAN TABLE T1"},
-        {3, 0, 0, "SCAN TABLE T2"},
+        {2, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
+        {3, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)"},
-        {4, 0, 0, "SCAN TABLE T1"},
+        {4, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)"}
         -- </4.3.2>
     })
@@ -497,11 +497,11 @@ test:do_eqp_test(
         SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1
     ]], {
         -- <4.3.3>
-        {2, 0, 0, "SCAN TABLE T1"},
+        {2, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {2, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
-        {3, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1"},
+        {3, 0, 0, "SCAN TABLE T2 USING COVERING INDEX T2I1 (~1048576 rows)"},
         {1, 0, 0, "COMPOUND SUBQUERIES 2 AND 3 (UNION)"},
-        {4, 0, 0, "SCAN TABLE T1"},
+        {4, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
         {4, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
         {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 4 (UNION)"}
         -- </4.3.3>
@@ -523,7 +523,7 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test("5.1.1", "SELECT a, b FROM t1 WHERE a=1", {
-    {0, 0, 0, "SCAN TABLE T1"},
+    {0, 0, 0, "SCAN TABLE T1 (~524288 rows)"},
 })
 -- EVIDENCE-OF: R-55852-17599 sql> CREATE INDEX i1 ON t1(a);
 -- sql> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
@@ -536,7 +536,7 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test("5.2.1", "SELECT a, b FROM t1 WHERE a=1", {
-    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
 })
 -- EVIDENCE-OF: R-21179-11011 sql> CREATE INDEX i2 ON t1(a, b);
 -- sql> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1;
@@ -551,7 +551,7 @@ test:do_execsql_test(
 test:do_eqp_test("5.3.1", "SELECT a, b FROM t1 WHERE a=1", {
     -- It is equal for tarantol wheather to use i1 or i2
     -- because both of them are covering
-    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
     --{0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
 })
 -- EVIDENCE-OF: R-09991-48941 sql> EXPLAIN QUERY PLAN
@@ -566,8 +566,8 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test("5.4.1", "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2", {
-    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=? AND B>?)"},
-    {0, 1, 1, "SCAN TABLE T2"},
+    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=? AND B>?) (~2 rows)"},
+    {0, 1, 1, "SCAN TABLE T2 (~1048576 rows)"},
 })
 -- EVIDENCE-OF: R-33626-61085 sql> EXPLAIN QUERY PLAN
 -- SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2;
@@ -575,8 +575,8 @@ test:do_eqp_test("5.4.1", "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2
 -- 0|1|0|SCAN TABLE T2
 --
 test:do_eqp_test(5.5, "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2", {
-    {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=? AND B>?)"},
-    {0, 1, 0, "SCAN TABLE T2"},
+    {0, 0, 1, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=? AND B>?) (~2 rows)"},
+    {0, 1, 0, "SCAN TABLE T2 (~1048576 rows)"},
 })
 -- EVIDENCE-OF: R-04002-25654 sql> CREATE INDEX i3 ON t1(b);
 -- sql> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2;
@@ -593,8 +593,8 @@ test:do_eqp_test("5.6.1", "SELECT a, b FROM t1 WHERE a=1 OR b=2", {
     -- It is equal for tarantol wheather to use i1 or i2
     -- because both of them are covering
     --{0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=?)"},
-    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
-    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I3 (B=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I3 (B=?) (~10 rows)"},
 })
 -- EVIDENCE-OF: R-24577-38891 sql> EXPLAIN QUERY PLAN
 -- SELECT c, d FROM t2 ORDER BY c;
@@ -602,7 +602,7 @@ test:do_eqp_test("5.6.1", "SELECT a, b FROM t1 WHERE a=1 OR b=2", {
 -- 0|0|0|USE TEMP B-TREE FOR ORDER BY
 --
 test:do_eqp_test(5.7, "SELECT c, d FROM t2 ORDER BY c", {
-    {0, 0, 0, "SCAN TABLE T2"},
+    {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
     {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
 })
 -- EVIDENCE-OF: R-58157-12355 sql> CREATE INDEX i4 ON t2(c);
@@ -616,7 +616,7 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test("5.8.1", "SELECT c, d FROM t2 ORDER BY c", {
-    {0, 0, 0, "SCAN TABLE T2 USING COVERING INDEX I4"},
+    {0, 0, 0, "SCAN TABLE T2 USING COVERING INDEX I4 (~1048576 rows)"},
 })
 -- EVIDENCE-OF: R-13931-10421 sql> EXPLAIN QUERY PLAN SELECT
 -- (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2;
@@ -626,17 +626,17 @@ test:do_eqp_test("5.8.1", "SELECT c, d FROM t2 ORDER BY c", {
 -- 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2
 -- 2|0|0|SEARCH TABLE T1 USING COVERING INDEX i3 (b=?)
 --
-test:do_eqp_test(5.9, [[
+test:do_eqp_test("5.9", [[
   SELECT (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2
 ]], {
-    {0, 0, 0, "SCAN TABLE T2"},
+    {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
     {0, 0, 0, "EXECUTE SCALAR SUBQUERY 1"},
     -- It is equally for tarantol wheather to use i1 or i2
     -- because both of them are covering
     --{1, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I2 (A=?)"},
-    {1, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?)"},
+    {1, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I1 (A=?) (~10 rows)"},
     {0, 0, 0, "EXECUTE CORRELATED SCALAR SUBQUERY 2"},
-    {2, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I3 (B=?)"},
+    {2, 0, 0, "SEARCH TABLE T1 USING COVERING INDEX I3 (B=?) (~10 rows)"},
 })
 -- EVIDENCE-OF: R-50892-45943 sql> EXPLAIN QUERY PLAN
 -- SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x;
@@ -644,11 +644,11 @@ test:do_eqp_test(5.9, [[
 -- 0|0|0|SCAN SUBQUERY 1
 -- 0|0|0|USE TEMP B-TREE FOR GROUP BY
 --
-test:do_eqp_test(5.10, [[
+test:do_eqp_test("5.10", [[
   SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x
 ]], {
-    {1, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1"},
-    {0, 0, 0, "SCAN SUBQUERY 1"},
+    {1, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1 (~1048576 rows)"},
+    {0, 0, 0, "SCAN SUBQUERY 1 (~1 row)"},
     {0, 0, 0, "USE TEMP B-TREE FOR GROUP BY"},
 })
 -- EVIDENCE-OF: R-46219-33846 sql> EXPLAIN QUERY PLAN
@@ -656,9 +656,9 @@ test:do_eqp_test(5.10, [[
 -- 0|0|0|SEARCH TABLE T2 USING COVERING INDEX i4 (c=?)
 -- 0|1|1|SCAN TABLE T1
 --
-test:do_eqp_test(5.11, "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1", {
-    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX I4 (C=?)"},
-    {0, 1, 1, "SCAN TABLE T1"},
+test:do_eqp_test("5.11", "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1", {
+    {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX I4 (C=?) (~10 rows)"},
+    {0, 1, 1, "SCAN TABLE T1 (~1048576 rows)"},
 })
 -- EVIDENCE-OF: R-37879-39987 sql> EXPLAIN QUERY PLAN
 -- SELECT a FROM t1 UNION SELECT c FROM t2;
@@ -666,9 +666,9 @@ test:do_eqp_test(5.11, "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1", {
 -- 2|0|0|SCAN TABLE T2
 -- 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)
 --
-test:do_eqp_test(5.12, "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2", {
-    {1, 0, 0, "SCAN TABLE T1"},
-    {2, 0, 0, "SCAN TABLE T2"},
+test:do_eqp_test("5.12", "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2", {
+    {1, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
+    {2, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
     {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)"},
 })
 -- EVIDENCE-OF: R-44864-63011 sql> EXPLAIN QUERY PLAN
@@ -677,9 +677,9 @@ test:do_eqp_test(5.12, "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2", {
 -- 2|0|0|SCAN TABLE T2 2|0|0|USE TEMP B-TREE FOR ORDER BY
 -- 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)
 --
-test:do_eqp_test(5.13, "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1", {
-    {1, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1"},
-    {2, 0, 0, "SCAN TABLE T2"},
+test:do_eqp_test("5.13", "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1", {
+    {1, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1 (~1048576 rows)"},
+    {2, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
     {2, 0, 0, "USE TEMP B-TREE FOR ORDER BY"},
     {0, 0, 0, "COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)"},
 })
@@ -725,24 +725,24 @@ test:do_eqp_test(5.13, "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1", {
 --
 test:drop_all_tables()
 test:do_execsql_test(
-    7.0,
+    "7.0",
     [[
         CREATE TABLE t1(idt1  INT primary key, a INT, b INT, ex VARCHAR(100));
         CREATE TABLE t2(idt2  INT primary key, a INT, b INT, ex VARCHAR(100));
         CREATE INDEX i1 ON t2(a);
     ]])
 
-test:do_eqp_test(7.1, "SELECT count(*) FROM t1", {
+test:do_eqp_test("7.1", "SELECT count(*) FROM t1", {
     {0, 0, 0, "B+tree count T1"},
 })
-test:do_eqp_test(7.2, "SELECT count(*) FROM t2", {
+test:do_eqp_test("7.2", "SELECT count(*) FROM t2", {
     {0, 0, 0, "B+tree count T2"},
 })
 -- MUST_WORK_TEST
 if (0 > 0)
  then
     test:do_execsql_test(
-        7.3,
+        "7.3",
         [[
            INSERT INTO t1(a,b) VALUES(1, 2);
            INSERT INTO t1(a,b) VALUES(3, 4);
@@ -756,10 +756,10 @@ if (0 > 0)
 
     --db("close")
     --sql("db", "test.db")
-    test:do_eqp_test(7.4, "SELECT count(*) FROM t1", {
+    test:do_eqp_test("7.4", "SELECT count(*) FROM t1", {
        {0, 0, 0, "SCAN TABLE T1"}
    })
-    test:do_eqp_test(7.5, "SELECT count(*) FROM t2", {
+    test:do_eqp_test("7.5", "SELECT count(*) FROM t2", {
        {0, 0, 0, "SCAN TABLE T2 USING COVERING INDEX I1"}
    })
     ---------------------------------------------------------------------------
@@ -768,14 +768,14 @@ if (0 > 0)
 end
 test:drop_all_tables()
 test:do_execsql_test(
-    8.0,
+    "8.0",
     [[
         CREATE TABLE t1(a INT , b INT , c INT , PRIMARY KEY(b, c));
         CREATE TABLE t2(id  INT primary key, a INT , b INT , c INT );
     ]])
 
 test:do_eqp_test("8.1.1", "SELECT * FROM t2", {
-    {0, 0, 0, "SCAN TABLE T2"},
+    {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"},
 })
 -- test:do_eqp_test 8.1.2 "SELECT * FROM t2 WHERE rowid=?" {
 --     {0, 0, 0, "SEARCH TABLE T2 USING INTEGER PRIMARY KEY (rowid=?)"},
@@ -784,13 +784,13 @@ test:do_eqp_test("8.1.3", "SELECT count(*) FROM t2", {
     {0, 0, 0, "B+tree count T2"},
 })
 test:do_eqp_test("8.2.1", "SELECT * FROM t1", {
-    {0, 0, 0, "SCAN TABLE T1"},
+    {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"},
 })
 test:do_eqp_test("8.2.2", "SELECT * FROM t1 WHERE b=?", {
-    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (B=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (B=?) (~10 rows)"},
 })
 test:do_eqp_test("8.2.3", "SELECT * FROM t1 WHERE b=? AND c=?", {
-    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (B=? AND C=?)"},
+    {0, 0, 0, "SEARCH TABLE T1 USING PRIMARY KEY (B=? AND C=?) (~1 row)"},
 })
 test:do_eqp_test("8.2.4", "SELECT count(*) FROM t1", {
     {0, 0, 0, "B+tree count T1"},
diff --git a/test/sql-tap/gh-2996-indexed-by.test.lua b/test/sql-tap/gh-2996-indexed-by.test.lua
index 1039ac15c..4c5a4d053 100755
--- a/test/sql-tap/gh-2996-indexed-by.test.lua
+++ b/test/sql-tap/gh-2996-indexed-by.test.lua
@@ -37,7 +37,7 @@ test:do_eqp_test(
     "indexed-by-1.1",
     "SELECT b FROM t1 WHERE b <= 5", {
         -- <indexed-by-1.1>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B<?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B<?) (~262144 rows)' }
         -- <indexed-by-1.1>
     })
 
@@ -45,7 +45,7 @@ test:do_eqp_test(
     "indexed-by-1.2",
     "SELECT b FROM t1 INDEXED BY t1ix1 WHERE b <= 5", {
         -- <indexed-by-1.2>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B<?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B<?) (~262144 rows)' }
         -- <indexed-by-1.2>
     })
 
@@ -82,7 +82,7 @@ test:do_eqp_test(
     "indexed-by-1.5",
     "DELETE FROM t1 WHERE b <= 5", {
         -- <indexed-by-1.5>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B<?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B<?) (~262144 rows)' }
         -- <indexed-by-1.5>
     })
 
@@ -90,7 +90,7 @@ test:do_eqp_test(
     "indexed-by-1.6",
     "DELETE FROM t1 INDEXED BY t1ix1  WHERE b <= 5", {
         -- <indexed-by-1.6>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B<?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B<?) (~262144 rows)' }
         -- <indexed-by-1.6>
     })
 
@@ -124,7 +124,7 @@ test:do_eqp_test(
     "indexed-by-1.9",
     "UPDATE t1 SET b = 20 WHERE b = 10", {
         -- <indexed-by-1.9>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B=?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX2 (B=?) (~10 rows)' }
         -- <indexed-by-1.9>
     })
 
@@ -132,7 +132,7 @@ test:do_eqp_test(
     "indexed-by-1.10",
     "UPDATE t1 INDEXED BY t1ix1 SET b = 20 WHERE b = 10", {
         -- <indexed-by-1.10>
-        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B=?)' }
+        { 0, 0, 0, 'SEARCH TABLE T1 USING COVERING INDEX T1IX1 (B=?) (~10 rows)' }
         -- <indexed-by-1.10>
     })
 
diff --git a/test/sql-tap/index6.test.lua b/test/sql-tap/index6.test.lua
index 416b800e1..15ae49245 100755
--- a/test/sql-tap/index6.test.lua
+++ b/test/sql-tap/index6.test.lua
@@ -334,8 +334,8 @@ test:do_eqp_test(
         SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a)
     ]], {
         -- <index6-8.1>
-    {0, 0, 0, "SCAN TABLE T8A"},
-    {0, 1, 1, "SEARCH TABLE T8B USING COVERING INDEX I8C (Y=?)"}
+    {0, 0, 0, "SCAN TABLE T8A (~1048576 rows)"},
+    {0, 1, 1, "SEARCH TABLE T8B USING COVERING INDEX I8C (Y=?) (~9 rows)"}
         -- </index6-8.1>
     })
 
diff --git a/test/sql-tap/index7.test.lua b/test/sql-tap/index7.test.lua
index 22072ec93..ed2b17c74 100755
--- a/test/sql-tap/index7.test.lua
+++ b/test/sql-tap/index7.test.lua
@@ -279,7 +279,7 @@ test:do_eqp_test(
         SELECT * FROM v4 WHERE d='xyz' AND c='def'
     ]], {
         -- <index7-6.4>
-    {0, 0, 0, "SEARCH TABLE T4 USING COVERING INDEX I4 (C=?)"}
+    {0, 0, 0, "SEARCH TABLE T4 USING COVERING INDEX I4 (C=?) (~9 rows)"}
         -- </index7-6.4>
     })
 
diff --git a/test/sql-tap/lua-tables.test.lua b/test/sql-tap/lua-tables.test.lua
index 7ba1d7ac5..07e0f6a1e 100755
--- a/test/sql-tap/lua-tables.test.lua
+++ b/test/sql-tap/lua-tables.test.lua
@@ -149,7 +149,7 @@ test:do_eqp_test(
     [[
         SELECT * FROM test WHERE id = 2;
     ]], {
-        {0, 0, 0, 'SEARCH TABLE TEST USING PRIMARY KEY (ID=?)'}
+        {0, 0, 0, 'SEARCH TABLE TEST USING PRIMARY KEY (ID=?) (~1 row)'}
     })
 
 test:do_eqp_test(
@@ -157,7 +157,7 @@ test:do_eqp_test(
     [[
         SELECT * FROM test WHERE a = 5;
     ]], {
-        {0, 0, 0, 'SEARCH TABLE TEST USING COVERING INDEX secondary (A=?)'}
+        {0, 0, 0, 'SEARCH TABLE TEST USING COVERING INDEX secondary (A=?) (~1 row)'}
     })
 
 -- Make sure that without format it is impossible to create
diff --git a/test/sql-tap/tkt-385a5b56b9.test.lua b/test/sql-tap/tkt-385a5b56b9.test.lua
index ffbb1a941..653d68222 100755
--- a/test/sql-tap/tkt-385a5b56b9.test.lua
+++ b/test/sql-tap/tkt-385a5b56b9.test.lua
@@ -19,7 +19,7 @@ test:plan(9)
 -- ["source",[["testdir"],"\/tester.tcl"]]
 testprefix = "tkt-385a5b56b9"
 test:do_execsql_test(
-    1.0,
+    "1.0",
     [[
         CREATE TABLE t1(id INT primary key, x INT, y INT);
         INSERT INTO t1 VALUES(1, 1, NULL);
@@ -28,7 +28,7 @@ test:do_execsql_test(
     ]])
 
 test:do_execsql_test(
-    1.1,
+    "1.1",
     [[
         SELECT DISTINCT x, y FROM t1 
     ]], {
@@ -38,13 +38,13 @@ test:do_execsql_test(
     })
 
 test:do_execsql_test(
-    1.2,
+    "1.2",
     [[
         CREATE UNIQUE INDEX i1 ON t1(x, y)
     ]])
 
 test:do_execsql_test(
-    1.3,
+    "1.3",
     [[
         SELECT DISTINCT x, y FROM t1 
     ]], {
@@ -55,7 +55,7 @@ test:do_execsql_test(
 
 ---------------------------------------------------------------------------
 test:do_execsql_test(
-    2.0,
+    "2.0",
     [[
         CREATE TABLE t2(x INT primary key, y INT NOT NULL);
         CREATE UNIQUE INDEX t2x ON t2(x);
@@ -63,41 +63,41 @@ test:do_execsql_test(
     ]])
 
 test:do_eqp_test(
-    2.1,
+    "2.1",
     " SELECT DISTINCT x FROM t2 ", {
         -- <2.1>
-        {0, 0, 0, "SCAN TABLE T2"}
+        {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"}
         -- </2.1>
     })
 
 test:do_eqp_test(
-    2.2,
+    "2.2",
     " SELECT DISTINCT y FROM t2 ", {
         -- <2.2>
         -- changed after reordering indexes
         -- actually it does not matter, because each y val is
         -- distinct even in pk
         --{0, 0, 0, "SCAN TABLE t2 USING COVERING INDEX t2y"}
-        {0, 0, 0, "SCAN TABLE T2"}
+        {0, 0, 0, "SCAN TABLE T2 (~1048576 rows)"}
         -- </2.2>
     })
 
 test:do_eqp_test(
-    2.3,
+    "2.3",
     " SELECT DISTINCT x, y FROM t2 WHERE y=10 ", {
         -- <2.3>
-        {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2Y (Y=?)"}
+        {0, 0, 0, "SEARCH TABLE T2 USING COVERING INDEX T2Y (Y=?) (~1 row)"}
         -- </2.3>
     })
 
 test:do_eqp_test(
-    2.4,
+    "2.4",
     " SELECT DISTINCT x, y FROM t2 WHERE x=10 ", {
         -- <2.4>
         -- changed after reordering indexes + add pk to x affected
         -- actually it does not matter
         --{0, 0, 0, "SEARCH TABLE t2 USING INDEX t2x (x=?)"}
-        {0, 0, 0, "SEARCH TABLE T2 USING PRIMARY KEY (X=?)"}
+        {0, 0, 0, "SEARCH TABLE T2 USING PRIMARY KEY (X=?) (~1 row)"}
         -- </2.4>
     })
 
diff --git a/test/sql-tap/tkt-b75a9ca6b0.test.lua b/test/sql-tap/tkt-b75a9ca6b0.test.lua
index ea684a73d..89817d2af 100755
--- a/test/sql-tap/tkt-b75a9ca6b0.test.lua
+++ b/test/sql-tap/tkt-b75a9ca6b0.test.lua
@@ -39,8 +39,8 @@ test:do_execsql_test(
         CREATE INDEX i1 ON t1(x, y);
     ]])
 
-local idxscan = {0, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1"}
-local tblscan = {0, 0, 0, "SCAN TABLE T1"}
+local idxscan = {0, 0, 0, "SCAN TABLE T1 USING COVERING INDEX I1 (~1048576 rows)"}
+local tblscan = {0, 0, 0, "SCAN TABLE T1 (~1048576 rows)"}
 local grpsort = {0, 0, 0, "USE TEMP B-TREE FOR GROUP BY"}
 local sort = {0, 0, 0, "USE TEMP B-TREE FOR ORDER BY"}
 local eqps = {
diff --git a/test/sql-tap/tkt3442.test.lua b/test/sql-tap/tkt3442.test.lua
index bdfdf8e17..5b26122ef 100755
--- a/test/sql-tap/tkt3442.test.lua
+++ b/test/sql-tap/tkt3442.test.lua
@@ -55,7 +55,7 @@ test:do_test(
         return EQP(" SELECT node FROM listhash WHERE id='5000' LIMIT 1; ")
     end, {
         -- <tkt3442-1.2>
-        0, 0, 0, "SEARCH TABLE LISTHASH USING COVERING INDEX IDIDX (ID=?)"
+        0, 0, 0, "SEARCH TABLE LISTHASH USING COVERING INDEX IDIDX (ID=?) (~1 row)"
         -- </tkt3442-1.2>
     })
 
@@ -65,7 +65,7 @@ test:do_test(
         return EQP([[ SELECT node FROM listhash WHERE id=5000 LIMIT 1; ]])
     end, {
         -- <tkt3442-1.3>
-        0, 0, 0, "SCAN TABLE LISTHASH"
+        0, 0, 0, "SCAN TABLE LISTHASH (~262144 rows)"
         -- </tkt3442-1.3>
     })
 
diff --git a/test/sql-tap/where3.test.lua b/test/sql-tap/where3.test.lua
index 86329d096..ae9e37f61 100755
--- a/test/sql-tap/where3.test.lua
+++ b/test/sql-tap/where3.test.lua
@@ -407,7 +407,7 @@ if 0
             SELECT * FROM t400, t401, t402 WHERE t402.z LIKE 'abc%';
         ]], {
             -- <where3-4.0>
-            0, 0, 2, "SCAN TABLE T402", 0, 1, 0, "SCAN TABLE T400", 0, 2, 1, "SCAN TABLE T401"
+            0, 0, 2, "SCAN TABLE T402 (~983040 rows)", 0, 1, 0, "SCAN TABLE T400 (~1048576 rows)", 0, 2, 1, "SCAN TABLE T401 (~1048576 rows)"
             -- </where3-4.0>
         })
 
@@ -418,7 +418,7 @@ if 0
             SELECT * FROM t400, t401, t402 WHERE t401.r LIKE 'abc%';
         ]], {
             -- <where3-4.1>
-            0, 0, 1, "SCAN TABLE T401", 0, 1, 0, "SCAN TABLE T400", 0, 2, 2, "SCAN TABLE T402"
+            0, 0, 1, "SCAN TABLE T401 (~983040 rows)", 0, 1, 0, "SCAN TABLE T400 (~1048576 rows)", 0, 2, 2, "SCAN TABLE T402 (~1048576 rows)"
             -- </where3-4.1>
         })
 
@@ -429,7 +429,7 @@ if 0
             SELECT * FROM t400, t401, t402 WHERE t400.c LIKE 'abc%';
         ]], {
             -- <where3-4.2>
-            0, 0, 0, "SCAN TABLE T400", 0, 1, 1, "SCAN TABLE T401", 0, 2, 2, "SCAN TABLE T402"
+            0, 0, 0, "SCAN TABLE T400 (~983040 rows)", 0, 1, 1, "SCAN TABLE T401 (~1048576 rows)", 0, 2, 2, "SCAN TABLE T402 (~1048576 rows)"
             -- </where3-4.2>
         })
 
diff --git a/test/sql-tap/whereG.test.lua b/test/sql-tap/whereG.test.lua
index e9a39c5ce..177d9d14e 100755
--- a/test/sql-tap/whereG.test.lua
+++ b/test/sql-tap/whereG.test.lua
@@ -278,7 +278,7 @@ test:do_execsql_test(
 --
 -- reset_db
 test:do_execsql_test(
-    5.1,
+    "5.1",
     [[
         DROP TABLE IF EXISTS t1;
         CREATE TABLE t1(a INT , b INT , c INT , PRIMARY KEY (a,b));
@@ -323,7 +323,7 @@ test:do_execsql_test(
 --
 
 test:do_execsql_test(
-    6.0,
+    "6.0",
     [[
         DROP TABLE IF EXISTS t1;
         CREATE TABLE t1(i int PRIMARY KEY, x INT , y INT , z INT );
@@ -343,7 +343,7 @@ test:do_execsql_test(
 -- Crash discovered by AFL
 -- MUST_WORK_TEST
 test:do_execsql_test(
-    7.0,
+    "7.0",
     [[
         DROP TABLE IF EXISTS t1;
         CREATE TABLE t1(a INT , b INT , PRIMARY KEY(a,b));
@@ -359,7 +359,7 @@ test:do_execsql_test(
     })
 
 test:do_execsql_test(
-    7.1,
+    "7.1",
     [[
         SELECT unlikely(a), x FROM t1, t2 ORDER BY 1, 2;
     ]], {
@@ -369,7 +369,7 @@ test:do_execsql_test(
     })
 
 test:do_execsql_test(
-    7.2,
+    "7.2",
     [[
         SELECT likelihood(a,0.5), x FROM t1, t2 ORDER BY 1, 2;
     ]], {
@@ -379,7 +379,7 @@ test:do_execsql_test(
     })
 
 test:do_execsql_test(
-    7.3,
+    "7.3",
     [[
         SELECT coalesce(a,a), x FROM t1, t2 ORDER BY 1, 2;
     ]], {
@@ -444,7 +444,7 @@ test:do_execsql_test(
     [[
         EXPLAIN QUERY PLAN SELECT name FROM people WHERE height>=180;
     ]],
-    {0,0,0,"SCAN TABLE PEOPLE"})
+    {0,0,0,"SCAN TABLE PEOPLE (~983040 rows)"})
 
 test:do_execsql_test(
     "7.3",
@@ -454,7 +454,7 @@ test:do_execsql_test(
     ]],
     -- {0,0,0,"SEARCH TABLE PEOPLE USING COVERING INDEX PEOPLE_IDX1" ..
     --     " (ANY(ROLE) AND HEIGHT>?)"}
-    {0,0,0,"SCAN TABLE PEOPLE" }
+    {0,0,0,"SCAN TABLE PEOPLE (~983040 rows)" }
     )
 
 test:finish_test()
diff --git a/test/sql/row-count.result b/test/sql/row-count.result
index da9b70e79..e7841caa1 100644
--- a/test/sql/row-count.result
+++ b/test/sql/row-count.result
@@ -303,7 +303,7 @@ box.execute("EXPLAIN QUERY PLAN INSERT INTO t1 VALUES ('b'), ('c'), ('d');")
   - name: detail
     type: TEXT
   rows:
-  - [0, 0, 0, 'SCAN TABLE T2']
+  - [0, 0, 0, 'SCAN TABLE T2 (~262144 rows)']
 ...
 box.execute("SELECT ROW_COUNT();")
 ---
-- 
2.17.1





More information about the Tarantool-patches mailing list