text: /*
   * Copyright 2010-2017, Tarantool AUTHORS, please see AUTHORS file.
   *
   * Redistribution and use in source and binary forms, with or
   * without modification, are permitted provided that the following
   * conditions are met:
   *
   * 1. Redistributions of source code must retain the above
   *    copyright notice, this list of conditions and the
   *    following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above
   *    copyright notice, this list of conditions and the following
   *    disclaimer in the documentation and/or other materials
   *    provided with the distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
   * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
   * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
   * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   */
  
  /*
   * This file contains C code routines that are called by the parser
   * to handle SELECT statements in sql.
   */
  #include "coll/coll.h"
  #include "sqlInt.h"
  #include "tarantoolInt.h"
  #include "vdbeInt.h"
  #include "box/box.h"
  #include "box/coll_id_cache.h"
  #include "box/schema.h"
  
  /*
   * Trace output macros
   */
  #ifdef SQL_DEBUG
  /***/ int sqlSelectTrace = 0;
  #define SELECTTRACE(K,P,S,X)  \
    if(sqlSelectTrace&(K))   \
      sqlDebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\
          (S)->zSelName,(S)),\
      sqlDebugPrintf X
  #else
  #define SELECTTRACE(K,P,S,X)
  #endif
  
  /*
   * An instance of the following object is used to record information about
   * how to process the DISTINCT keyword, to simplify passing that information
   * into the selectInnerLoop() routine.
   */
  typedef struct DistinctCtx DistinctCtx;
  struct DistinctCtx {
  	u8 isTnct;		/* True if the DISTINCT keyword is present */
  	u8 eTnctType;		/* One of the WHERE_DISTINCT_* operators */
  	/**
  	 * Ephemeral table's cursor used for DISTINCT processing.
  	 * It is used for reading from ephemeral space.
  	 */
  	int cur_eph;
  	/**
  	 * Register, containing a pointer to ephemeral space.
  	 * It is used for insertions while procesing DISTINCT.
  	 */
  	int reg_eph;
  	int addrTnct;		/* Address of OP_OpenEphemeral opcode for cur_eph */
  };
  
  /*
   * An instance of the following object is used to record information about
   * the ORDER BY (or GROUP BY) clause of query is being coded.
   */
  typedef struct SortCtx SortCtx;
  struct SortCtx {
  	ExprList *pOrderBy;	/* The ORDER BY (or GROUP BY clause) */
  	int nOBSat;		/* Number of ORDER BY terms satisfied by indices */
  	int iECursor;		/* Cursor number for the sorter */
  	/** Register, containing pointer to ephemeral space. */
  	int reg_eph;
  	int regReturn;		/* Register holding block-output return address */
  	int labelBkOut;		/* Start label for the block-output subroutine */
  	int addrSortIndex;	/* Address of the OP_SorterOpen or OP_OpenEphemeral */
  	int labelDone;		/* Jump here when done, ex: LIMIT reached */
  	u8 sortFlags;		/* Zero or more SORTFLAG_* bits */
  	u8 bOrderedInnerLoop;	/* ORDER BY correctly sorts the inner loop */
  };
  #define SORTFLAG_UseSorter  0x01	/* Use SorterOpen instead of OpenEphemeral */
  #define SORTFLAG_DESC 0xF0
  
  /*
   * Delete all the content of a Select structure.  Deallocate the structure
   * itself only if bFree is true.
   */
  static void
  clearSelect(sql * db, Select * p, int bFree)
  {
  	while (p) {
  		Select *pPrior = p->pPrior;
  		sql_expr_list_delete(db, p->pEList);
  		sqlSrcListDelete(db, p->pSrc);
  		sql_expr_delete(db, p->pWhere, false);
  		sql_expr_list_delete(db, p->pGroupBy);
  		sql_expr_delete(db, p->pHaving, false);
  		sql_expr_list_delete(db, p->pOrderBy);
  		sql_expr_delete(db, p->pLimit, false);
  		sql_expr_delete(db, p->pOffset, false);
  		if (p->pWith)
  			sqlWithDelete(db, p->pWith);
  		if (bFree)
  			sqlDbFree(db, p);
  		p = pPrior;
  		bFree = 1;
  	}
  }
  
  /*
   * Initialize a SelectDest structure.
   */
  void
  sqlSelectDestInit(SelectDest * pDest, int eDest, int iParm, int reg_eph)
  {
  	pDest->eDest = (u8) eDest;
  	pDest->iSDParm = iParm;
  	pDest->reg_eph = reg_eph;
  	pDest->dest_type = NULL;
  	pDest->iSdst = 0;
  	pDest->nSdst = 0;
  }
  
  /*
   * Allocate a new Select structure and return a pointer to that
   * structure.
   */
  Select *
  sqlSelectNew(Parse * pParse,	/* Parsing context */
  		 ExprList * pEList,	/* which columns to include in the result */
  		 SrcList * pSrc,	/* the FROM clause -- which tables to scan */
  		 Expr * pWhere,		/* the WHERE clause */
  		 ExprList * pGroupBy,	/* the GROUP BY clause */
  		 Expr * pHaving,	/* the HAVING clause */
  		 ExprList * pOrderBy,	/* the ORDER BY clause */
  		 u32 selFlags,		/* Flag parameters, such as SF_Distinct */
  		 Expr * pLimit,		/* LIMIT value.  NULL means not used */
  		 Expr * pOffset)	/* OFFSET value.  NULL means no offset */
  {
  	Select *pNew;
  	Select standin;
  	sql *db = pParse->db;
  	pNew = sqlDbMallocRawNN(db, sizeof(*pNew));
  	if (pNew == 0) {
  		assert(db->mallocFailed);
  		pNew = &standin;
  	}
  	if (pEList == 0) {
  		struct Expr *expr = sql_expr_new_anon(db, TK_ASTERISK);
  		if (expr == NULL)
  			pParse->is_aborted = true;
  		pEList = sql_expr_list_append(db, NULL, expr);
  	}
  	pNew->pEList = pEList;
  	pNew->op = TK_SELECT;
  	pNew->selFlags = selFlags;
  	pNew->iLimit = 0;
  	pNew->iOffset = 0;
  #ifdef SQL_DEBUG
  	pNew->zSelName[0] = 0;
  	if ((pParse->sql_flags & SQL_SelectTrace) != 0)
  		sqlSelectTrace = 0xfff;
  	else
  		sqlSelectTrace = 0;
  #endif
  	pNew->addrOpenEphm[0] = -1;
  	pNew->addrOpenEphm[1] = -1;
  	pNew->nSelectRow = 0;
  	if (pSrc == 0)
  		pSrc = sqlDbMallocZero(db, sizeof(*pSrc));
  	pNew->pSrc = pSrc;
  	pNew->pWhere = pWhere;
  	pNew->pGroupBy = pGroupBy;
  	pNew->pHaving = pHaving;
  	pNew->pOrderBy = pOrderBy;
  	pNew->pPrior = 0;
  	pNew->pNext = 0;
  	pNew->pLimit = pLimit;
  	pNew->pOffset = pOffset;
  	pNew->pWith = 0;
  	assert(pOffset == 0 || pLimit != 0 || pParse->is_aborted
  	       || db->mallocFailed != 0);
  	if (db->mallocFailed) {
  		clearSelect(db, pNew, pNew != &standin);
  		pNew = 0;
  	} else {
  		assert(pNew->pSrc != 0 || pParse->is_aborted);
  	}
  	assert(pNew != &standin);
  	return pNew;
  }
  
  #ifdef SQL_DEBUG
  /*
   * Set the name of a Select object
   */
  void
  sqlSelectSetName(Select * p, const char *zName)
  {
  	if (p && zName) {
  		sql_snprintf(sizeof(p->zSelName), p->zSelName, "%s", zName);
  	}
  }
  #endif
  
  void
  sql_select_delete(sql *db, Select *p)
  {
  	if (p)
  		clearSelect(db, p, 1);
  }
  
  int
  sql_src_list_entry_count(const struct SrcList *list)
  {
  	assert(list != NULL);
  	return list->nSrc;
  }
  
  const char *
  sql_src_list_entry_name(const struct SrcList *list, int i)
  {
  	assert(list != NULL);
  	assert(i >= 0 && i < list->nSrc);
  	return list->a[i].zName;
  }
  
  /*
   * Return a pointer to the right-most SELECT statement in a compound.
   */
  static Select *
  findRightmost(Select * p)
  {
  	while (p->pNext)
  		p = p->pNext;
  	return p;
  }
  
  
  /**
   * Work the same as sql_src_list_append(), but before adding to
   * list provide check on name duplicates: only values with unique
   * names are appended. Moreover, names of tables are not
   * normalized: it is parser's business and in struct Select they
   * are already in uppercased or unquoted form.
   *
   * @param db Database handler.
   * @param list List of entries.
   * @param new_name Name of entity to be added.
   * @retval @list with new element on success, old one otherwise.
   */
  static struct SrcList *
  src_list_append_unique(struct sql *db, struct SrcList *list,
  		       const char *new_name)
  {
  	assert(list != NULL);
  	assert(new_name != NULL);
  
  	for (int i = 0; i < list->nSrc; ++i) {
  		const char *name = list->a[i].zName;
  		if (name != NULL && strcmp(new_name, name) == 0)
  			return list;
  	}
  	struct SrcList *new_list =
  		sql_src_list_enlarge(db, list, 1, list->nSrc);
  	if (new_list == NULL) {
  		sqlSrcListDelete(db, list);
  		return NULL;
  	}
  	list = new_list;
  	struct SrcList_item *pItem = &list->a[list->nSrc - 1];
  	pItem->zName = sqlDbStrNDup(db, new_name, strlen(new_name));
  	if (pItem->zName == NULL) {
  		diag_set(OutOfMemory, strlen(new_name), "sqlDbStrNDup",
  			 "pItem->zName");
  		sqlSrcListDelete(db, list);
  		return NULL;
  	}
  	return list;
  }
  
  static int
  select_collect_table_names(struct Walker *walker, struct Select *select)
  {
  	assert(walker != NULL);
  	assert(select != NULL);
  	for (int i = 0; i < select->pSrc->nSrc; ++i) {
  		if (select->pSrc->a[i].zName == NULL)
  			continue;
  		walker->u.pSrcList =
  			src_list_append_unique(sql_get(), walker->u.pSrcList,
  					       select->pSrc->a[i].zName);
  		if (walker->u.pSrcList == NULL)
  			return WRC_Abort;
  	}
  	return WRC_Continue;
  }
  
  struct SrcList *
  sql_select_expand_from_tables(struct Select *select)
  {
  	assert(select != NULL);
  	struct Walker walker;
  	struct SrcList *table_names = sql_src_list_new(sql_get());
  	if (table_names == NULL)
  		return NULL;
  	memset(&walker, 0, sizeof(walker));
  	walker.xExprCallback = sqlExprWalkNoop;
  	walker.xSelectCallback = select_collect_table_names;
  	walker.u.pSrcList = table_names;
  	if (sqlWalkSelect(&walker, select) != 0) {
  		sqlSrcListDelete(sql_get(), walker.u.pSrcList);
  		return NULL;
  	}
  	return walker.u.pSrcList;
  }
  
  /*
   * Given 1 to 3 identifiers preceding the JOIN keyword, determine the
   * type of join.  Return an integer constant that expresses that type
   * in terms of the following bit values:
   *
   *     JT_INNER
   *     JT_CROSS
   *     JT_OUTER
   *     JT_NATURAL
   *     JT_LEFT
   *     JT_RIGHT
   *
   * A full outer join is the combination of JT_LEFT and JT_RIGHT.
   *
   * If an illegal or unsupported join type is seen, then still return
   * a join type, but put an error in the pParse structure.
   */
  int
  sqlJoinType(Parse * pParse, Token * pA, Token * pB, Token * pC)
  {
  	int jointype = 0;
  	Token *apAll[3];
  	Token *p;
  	/*   0123456789 123456789 123456789 123 */
  	static const char zKeyText[] = "naturaleftouterightfullinnercross";
  	static const struct {
  		u8 i;		/* Beginning of keyword text in zKeyText[] */
  		u8 nChar;	/* Length of the keyword in characters */
  		u8 code;	/* Join type mask */
  	} aKeyword[] = {
  		/* natural */  {
  		0, 7, JT_NATURAL},
  		    /* left    */  {
  		6, 4, JT_LEFT | JT_OUTER},
  		    /* outer   */  {
  		10, 5, JT_OUTER},
  		    /* right   */  {
  		14, 5, JT_RIGHT | JT_OUTER},
  		    /* full    */  {
  		19, 4, JT_LEFT | JT_RIGHT | JT_OUTER},
  		    /* inner   */  {
  		23, 5, JT_INNER},
  		    /* cross   */  {
  	28, 5, JT_INNER | JT_CROSS},};
  	int i, j;
  	apAll[0] = pA;
  	apAll[1] = pB;
  	apAll[2] = pC;
  	for (i = 0; i < 3 && apAll[i]; i++) {
  		p = apAll[i];
  		for (j = 0; j < ArraySize(aKeyword); j++) {
  			if (p->n == aKeyword[j].nChar
  			    && sqlStrNICmp((char *)p->z,
  					       &zKeyText[aKeyword[j].i],
  					       p->n) == 0) {
  				jointype |= aKeyword[j].code;
  				break;
  			}
  		}
  		testcase(j == 0 || j == 1 || j == 2 || j == 3 || j == 4
  			 || j == 5 || j == 6);
  		if (j >= ArraySize(aKeyword)) {
  			jointype |= JT_ERROR;
  			break;
  		}
  	}
  	if ((jointype & (JT_INNER | JT_OUTER)) == (JT_INNER | JT_OUTER) ||
  	    (jointype & JT_ERROR) != 0) {
  		assert(pB != 0);
  		const char *err;
  		if (pC == NULL) {
  			err = tt_sprintf("unknown or unsupported join type: "\
  					 "%.*s %.*s", pA->n, pA->z, pB->n,
  					 pB->z);
  		} else {
  			err = tt_sprintf("unknown or unsupported join type: "\
  					 "%.*s %.*s %.*s", pA->n, pA->z, pB->n,
  					 pB->z, pC->n, pC->z);
  		}
  		diag_set(ClientError, ER_SQL_PARSER_GENERIC, err);
  		pParse->is_aborted = true;
  		jointype = JT_INNER;
  	} else if ((jointype & JT_OUTER) != 0
  		   && (jointype & (JT_LEFT | JT_RIGHT)) != JT_LEFT) {
  		diag_set(ClientError, ER_UNSUPPORTED, "Tarantool",
  			 "RIGHT and FULL OUTER JOINs");
  		pParse->is_aborted = true;
  		jointype = JT_INNER;
  	}
  	return jointype;
  }
  
  /*
   * Return the index of a column in a table.  Return -1 if the column
   * is not contained in the table.
   */
  static int
  columnIndex(struct space_def *def, const char *zCol)
  {
  	for (uint32_t i = 0; i < def->field_count; i++) {
  		if (strcmp(def->fields[i].name, zCol) == 0)
  			return i;
  	}
  	return -1;
  }
  
  /*
   * Search the first N tables in pSrc, from left to right, looking for a
   * table that has a column named zCol.
   *
   * When found, set *piTab and *piCol to the table index and column index
   * of the matching column and return TRUE.
   *
   * If not found, return FALSE.
   */
  static int
  tableAndColumnIndex(SrcList * pSrc,	/* Array of tables to search */
  		    int N,		/* Number of tables in pSrc->a[] to search */
  		    const char *zCol,	/* Name of the column we are looking for */
  		    int *piTab,		/* Write index of pSrc->a[] here */
  		    int *piCol)		/* Write index of pSrc->a[*piTab].pTab->aCol[] here */
  {
  	int i;			/* For looping over tables in pSrc */
  	int iCol;		/* Index of column matching zCol */
  
  	assert((piTab == 0) == (piCol == 0));	/* Both or neither are NULL */
  	for (i = 0; i < N; i++) {
  		iCol = columnIndex(pSrc->a[i].space->def, zCol);
  		if (iCol >= 0) {
  			if (piTab) {
  				*piTab = i;
  				*piCol = iCol;
  			}
  			return 1;
  		}
  	}
  	return 0;
  }
  
  /*
   * This function is used to add terms implied by JOIN syntax to the
   * WHERE clause expression of a SELECT statement. The new term, which
   * is ANDed with the existing WHERE clause, is of the form:
   *
   *    (tab1.col1 = tab2.col2)
   *
   * where tab1 is the iSrc'th table in SrcList pSrc and tab2 is the
   * (iSrc+1)'th. Column col1 is column iColLeft of tab1, and col2 is
   * column iColRight of tab2.
   */
  static void
  addWhereTerm(Parse * pParse,	/* Parsing context */
  	     SrcList * pSrc,	/* List of tables in FROM clause */
  	     int iLeft,		/* Index of first table to join in pSrc */
  	     int iColLeft,	/* Index of column in first table */
  	     int iRight,	/* Index of second table in pSrc */
  	     int iColRight,	/* Index of column in second table */
  	     int isOuterJoin,	/* True if this is an OUTER join */
  	     Expr ** ppWhere)	/* IN/OUT: The WHERE clause to add to */
  {
  	struct sql *db = pParse->db;
  	Expr *pEq;
  
  	assert(iLeft < iRight);
  	assert(pSrc->nSrc > iRight);
  	assert(pSrc->a[iLeft].space != NULL);
  	assert(pSrc->a[iRight].space != NULL);
  
  	struct Expr *pE1 = sql_expr_new_column(db, pSrc, iLeft, iColLeft);
  	struct Expr *pE2 = sql_expr_new_column(db, pSrc, iRight, iColRight);
  	if (pE1 == NULL || pE2 == NULL)
  		pParse->is_aborted = true;
  	pEq = sqlPExpr(pParse, TK_EQ, pE1, pE2);
  	if (pEq && isOuterJoin) {
  		ExprSetProperty(pEq, EP_FromJoin);
  		assert(!ExprHasProperty(pEq, EP_TokenOnly | EP_Reduced));
  		ExprSetVVAProperty(pEq, EP_NoReduce);
  		pEq->iRightJoinTable = (i16) pE2->iTable;
  	}
  	*ppWhere = sql_and_expr_new(db, *ppWhere, pEq);
  	if (*ppWhere == NULL)
  		pParse->is_aborted = true;
  }
  
  /*
   * Set the EP_FromJoin property on all terms of the given expression.
   * And set the Expr.iRightJoinTable to iTable for every term in the
   * expression.
   *
   * The EP_FromJoin property is used on terms of an expression to tell
   * the LEFT OUTER JOIN processing logic that this term is part of the
   * join restriction specified in the ON or USING clause and not a part
   * of the more general WHERE clause.  These terms are moved over to the
   * WHERE clause during join processing but we need to remember that they
   * originated in the ON or USING clause.
   *
   * The Expr.iRightJoinTable tells the WHERE clause processing that the
   * expression depends on table iRightJoinTable even if that table is not
   * explicitly mentioned in the expression.  That information is needed
   * for cases like this:
   *
   *    SELECT * FROM t1 LEFT JOIN t2 ON t1.a=t2.b AND t1.x=5
   *
   * The where clause needs to defer the handling of the t1.x=5
   * term until after the t2 loop of the join.  In that way, a
   * NULL t2 row will be inserted whenever t1.x!=5.  If we do not
   * defer the handling of t1.x=5, it will be processed immediately
   * after the t1 loop and rows with t1.x!=5 will never appear in
   * the output, which is incorrect.
   */
  static void
  setJoinExpr(Expr * p, int iTable)
  {
  	while (p) {
  		ExprSetProperty(p, EP_FromJoin);
  		assert(!ExprHasProperty(p, EP_TokenOnly | EP_Reduced));
  		ExprSetVVAProperty(p, EP_NoReduce);
  		p->iRightJoinTable = (i16) iTable;
  		if (p->op == TK_FUNCTION && p->x.pList) {
  			int i;
  			for (i = 0; i < p->x.pList->nExpr; i++) {
  				setJoinExpr(p->x.pList->a[i].pExpr, iTable);
  			}
  		}
  		setJoinExpr(p->pLeft, iTable);
  		p = p->pRight;
  	}
  }
  
  /*
   * This routine processes the join information for a SELECT statement.
   * ON and USING clauses are converted into extra terms of the WHERE clause.
   * NATURAL joins also create extra WHERE clause terms.
   *
   * The terms of a FROM clause are contained in the Select.pSrc structure.
   * The left most table is the first entry in Select.pSrc.  The right-most
   * table is the last entry.  The join operator is held in the entry to
   * the left.  Thus entry 0 contains the join operator for the join between
   * entries 0 and 1.  Any ON or USING clauses associated with the join are
   * also attached to the left entry.
   *
   * This routine returns the number of errors encountered.
   */
  static int
  sqlProcessJoin(Parse * pParse, Select * p)
  {
  	SrcList *pSrc;		/* All tables in the FROM clause */
  	int i, j;		/* Loop counters */
  	struct SrcList_item *pLeft;	/* Left table being joined */
  	struct SrcList_item *pRight;	/* Right table being joined */
  
  	pSrc = p->pSrc;
  	pLeft = &pSrc->a[0];
  	pRight = &pLeft[1];
  	for (i = 0; i < pSrc->nSrc - 1; i++, pRight++, pLeft++) {
  		struct space *left_space = pLeft->space;
  		struct space *right_space = pRight->space;
  		int isOuter;
  
  		if (NEVER(left_space == NULL || right_space == NULL))
  			continue;
  		isOuter = (pRight->fg.jointype & JT_OUTER) != 0;
  
  		/* When the NATURAL keyword is present, add WHERE clause terms for
  		 * every column that the two tables have in common.
  		 */
  		if (pRight->fg.jointype & JT_NATURAL) {
  			if (pRight->pOn || pRight->pUsing) {
  				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  					 "a NATURAL join may not have "
  					 "an ON or USING clause");
  				pParse->is_aborted = true;
  				return 1;
  			}
  			for (j = 0; j < (int)right_space->def->field_count; j++) {
  				char *zName;	/* Name of column in the right table */
  				int iLeft;	/* Matching left table */
  				int iLeftCol;	/* Matching column in the left table */
  
  				zName = right_space->def->fields[j].name;
  				if (tableAndColumnIndex
  				    (pSrc, i + 1, zName, &iLeft, &iLeftCol)) {
  					addWhereTerm(pParse, pSrc, iLeft,
  						     iLeftCol, i + 1, j,
  						     isOuter, &p->pWhere);
  				}
  			}
  		}
  
  		/* Disallow both ON and USING clauses in the same join
  		 */
  		if (pRight->pOn && pRight->pUsing) {
  			diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  				 "cannot have both ON and USING clauses in "\
  				 "the same join");
  			pParse->is_aborted = true;
  			return 1;
  		}
  
  		/* Add the ON clause to the end of the WHERE clause, connected by
  		 * an AND operator.
  		 */
  		if (pRight->pOn) {
  			if (isOuter)
  				setJoinExpr(pRight->pOn, pRight->iCursor);
  			p->pWhere = sql_and_expr_new(pParse->db, p->pWhere,
  						     pRight->pOn);
  			if (p->pWhere == NULL)
  				pParse->is_aborted = true;
  			pRight->pOn = 0;
  		}
  
  		/* Create extra terms on the WHERE clause for each column named
  		 * in the USING clause.  Example: If the two tables to be joined are
  		 * A and B and the USING clause names X, Y, and Z, then add this
  		 * to the WHERE clause:    A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
  		 * Report an error if any column mentioned in the USING clause is
  		 * not contained in both tables to be joined.
  		 */
  		if (pRight->pUsing) {
  			const char *err = "cannot join using column %s - "\
  					  "column not present in both tables";
  			IdList *pList = pRight->pUsing;
  			for (j = 0; j < pList->nId; j++) {
  				char *zName;	/* Name of the term in the USING clause */
  				int iLeft;	/* Table on the left with matching column name */
  				int iLeftCol;	/* Column number of matching column on the left */
  				int iRightCol;	/* Column number of matching column on the right */
  
  				zName = pList->a[j].zName;
  				iRightCol = columnIndex(right_space->def, zName);
  				if (iRightCol < 0
  				    || !tableAndColumnIndex(pSrc, i + 1, zName,
  							    &iLeft, &iLeftCol)
  				    ) {
  					err = tt_sprintf(err, zName);
  					diag_set(ClientError,
  						 ER_SQL_PARSER_GENERIC, err);
  					pParse->is_aborted = true;
  					return 1;
  				}
  				addWhereTerm(pParse, pSrc, iLeft, iLeftCol,
  					     i + 1, iRightCol, isOuter,
  					     &p->pWhere);
  			}
  		}
  	}
  	return 0;
  }
  
  /**
   * Given an expression list, generate a key_info structure that
   * records the collating sequence for each expression in that
   * expression list.
   *
   * If the ExprList is an ORDER BY or GROUP BY clause then the
   * resulting key_info structure is appropriate for initializing
   * a virtual index to implement that clause.  If the ExprList is
   * the result set of a SELECT then the key_info structure is
   * appropriate for initializing a virtual index to implement a
   * DISTINCT test.
   *
   * Space to hold the key_info structure is obtained from malloc.
   * The calling function is responsible for seeing that this
   * structure is eventually freed.
   *
   * @param parse Parsing context.
   * @param list Expression list.
   * @param start No of leading parts to skip.
   *
   * @retval Allocated key_info, NULL in case of OOM.
   */
  static struct sql_key_info *
  sql_expr_list_to_key_info(struct Parse *parse, struct ExprList *list, int start);
  
  
  /*
   * Generate code that will push the record in registers regData
   * through regData+nData-1 onto the sorter.
   */
  static void
  pushOntoSorter(Parse * pParse,		/* Parser context */
  	       SortCtx * pSort,		/* Information about the ORDER BY clause */
  	       Select * pSelect,	/* The whole SELECT statement */
  	       int regData,		/* First register holding data to be sorted */
  	       int regOrigData,		/* First register holding data before packing */
  	       int nData,		/* Number of elements in the data array */
  	       int nPrefixReg)		/* No. of reg prior to regData available for use */
  {
  	Vdbe *v = pParse->pVdbe;	/* Stmt under construction */
  	int bSeq = ((pSort->sortFlags & SORTFLAG_UseSorter) == 0);
  	int nExpr = pSort->pOrderBy->nExpr;	/* No. of ORDER BY terms */
  	int nBase = nExpr + bSeq + nData;	/* Fields in sorter record */
  	int regBase;		/* Regs for sorter record */
  	int regRecord = ++pParse->nMem;	/* Assembled sorter record */
  	int nOBSat = pSort->nOBSat;	/* ORDER BY terms to skip */
  	int iLimit;		/* LIMIT counter */
  
  	assert(bSeq == 0 || bSeq == 1);
  	assert(nData == 1 || regData == regOrigData || regOrigData == 0);
  	if (nPrefixReg) {
  		assert(nPrefixReg == nExpr + bSeq);
  		regBase = regData - nExpr - bSeq;
  	} else {
  		regBase = pParse->nMem + 1;
  		pParse->nMem += nBase;
  	}
  	assert(pSelect->iOffset == 0 || pSelect->iLimit != 0);
  	iLimit = pSelect->iOffset ? pSelect->iOffset + 1 : pSelect->iLimit;
  	pSort->labelDone = sqlVdbeMakeLabel(v);
  	sqlExprCodeExprList(pParse, pSort->pOrderBy, regBase, regOrigData,
  				SQL_ECEL_DUP | (regOrigData ? SQL_ECEL_REF
  						   : 0));
  	if (bSeq) {
  		sqlVdbeAddOp2(v, OP_Sequence, pSort->iECursor,
  				  regBase + nExpr);
  	}
  	if (nPrefixReg == 0 && nData > 0) {
  		sqlExprCodeMove(pParse, regData, regBase + nExpr + bSeq,
  				    nData);
  	}
  	sqlVdbeAddOp3(v, OP_MakeRecord, regBase + nOBSat, nBase - nOBSat,
  			  regRecord);
  	if (nOBSat > 0) {
  		int regPrevKey;	/* The first nOBSat columns of the previous row */
  		int addrFirst;	/* Address of the OP_IfNot opcode */
  		int addrJmp;	/* Address of the OP_Jump opcode */
  		VdbeOp *pOp;	/* Opcode that opens the sorter */
  		int nKey;	/* Number of sorting key columns, including OP_Sequence */
  
  		regPrevKey = pParse->nMem + 1;
  		pParse->nMem += pSort->nOBSat;
  		nKey = nExpr - pSort->nOBSat + bSeq;
  		if (bSeq) {
  			int r1 = sqlGetTempReg(pParse);
  			sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  			addrFirst = sqlVdbeAddOp3(v, OP_Eq, r1, 0, regBase + nExpr);
  			sqlReleaseTempReg(pParse, r1);
  		} else {
  			addrFirst =
  			    sqlVdbeAddOp1(v, OP_SequenceTest,
  					      pSort->iECursor);
  		}
  		VdbeCoverage(v);
  		sqlVdbeAddOp3(v, OP_Compare, regPrevKey, regBase,
  				  pSort->nOBSat);
  		pOp = sqlVdbeGetOp(v, pSort->addrSortIndex);
  		if (pParse->db->mallocFailed)
  			return;
  		pOp->p2 = nKey + nData;
  		struct sql_key_info *key_info = pOp->p4.key_info;
  		for (uint32_t i = 0; i < key_info->part_count; i++)
  			key_info->parts[i].sort_order = SORT_ORDER_ASC;
  		sqlVdbeChangeP4(v, -1, (char *)key_info, P4_KEYINFO);
  		pOp->p4.key_info = sql_expr_list_to_key_info(pParse,
  							     pSort->pOrderBy,
  							     nOBSat);
  		addrJmp = sqlVdbeCurrentAddr(v);
  		sqlVdbeAddOp3(v, OP_Jump, addrJmp + 1, 0, addrJmp + 1);
  		VdbeCoverage(v);
  		pSort->labelBkOut = sqlVdbeMakeLabel(v);
  		pSort->regReturn = ++pParse->nMem;
  		sqlVdbeAddOp2(v, OP_Gosub, pSort->regReturn,
  				  pSort->labelBkOut);
  		sqlVdbeAddOp1(v, OP_ResetSorter, pSort->iECursor);
  		if (iLimit) {
  			int r1 = sqlGetTempReg(pParse);
  			sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  			sqlVdbeAddOp3(v, OP_Eq, r1, pSort->labelDone, iLimit);
  			sqlReleaseTempReg(pParse, r1);
  		}
  		sqlVdbeJumpHere(v, addrFirst);
  		sqlExprCodeMove(pParse, regBase, regPrevKey, pSort->nOBSat);
  		sqlVdbeJumpHere(v, addrJmp);
  	}
  	if (pSort->sortFlags & SORTFLAG_UseSorter) {
  		sqlVdbeAddOp2(v, OP_SorterInsert, pSort->iECursor,
  				  regRecord);
  	} else {
  		sqlVdbeAddOp2(v, OP_IdxInsert, regRecord, pSort->reg_eph);
  	}
  
  	if (iLimit) {
  		int addr;
  		int r1 = 0;
  		/* Fill the sorter until it contains LIMIT+OFFSET entries.  (The iLimit
  		 * register is initialized with value of LIMIT+OFFSET.)  After the sorter
  		 * fills up, delete the least entry in the sorter after each insert.
  		 * Thus we never hold more than the LIMIT+OFFSET rows in memory at once
  		 */
  		addr = sqlVdbeAddOp1(v, OP_IfNotZero, iLimit);
  		VdbeCoverage(v);
  		if (pSort->sortFlags & SORTFLAG_DESC) {
  			int iNextInstr = sqlVdbeCurrentAddr(v) + 1;
  			sqlVdbeAddOp2(v, OP_Rewind, pSort->iECursor, iNextInstr);
  		} else {
  			sqlVdbeAddOp1(v, OP_Last, pSort->iECursor);
  		}
  		if (pSort->bOrderedInnerLoop) {
  			r1 = ++pParse->nMem;
  			sqlVdbeAddOp3(v, OP_Column, pSort->iECursor, nExpr,
  					  r1);
  			VdbeComment((v, "seq"));
  		}
  		sqlVdbeAddOp1(v, OP_Delete, pSort->iECursor);
  		if (pSort->bOrderedInnerLoop) {
  			/* If the inner loop is driven by an index such that values from
  			 * the same iteration of the inner loop are in sorted order, then
  			 * immediately jump to the next iteration of an inner loop if the
  			 * entry from the current iteration does not fit into the top
  			 * LIMIT+OFFSET entries of the sorter.
  			 */
  			int iBrk = sqlVdbeCurrentAddr(v) + 2;
  			sqlVdbeAddOp3(v, OP_Eq, regBase + nExpr, iBrk, r1);
  			sqlVdbeChangeP5(v, SQL_NULLEQ);
  			VdbeCoverage(v);
  		}
  		sqlVdbeJumpHere(v, addr);
  	}
  }
  
  /*
   * Add code to implement the OFFSET
   */
  static void
  codeOffset(Vdbe * v,		/* Generate code into this VM */
  	   int iOffset,		/* Register holding the offset counter */
  	   int iContinue)	/* Jump here to skip the current record */
  {
  	if (iOffset > 0) {
  		sqlVdbeAddOp3(v, OP_IfPos, iOffset, iContinue, 1);
  		VdbeCoverage(v);
  		VdbeComment((v, "OFFSET"));
  	}
  }
  
  /**
   * Add code that will check to make sure the @n registers starting
   * at @reg_data form a distinct entry. @cursor is a sorting index
   * that holds previously seen combinations of the @n values.
   * A new entry is made in @cursor if the current n values are new.
   *
   * A jump to @addr_repeat is made and the @n+1 values are popped
   * from the stack if the top n elements are not distinct.
   *
   * @param parse Parsing and code generating context.
   * @param cursor A sorting index cursor used to test for
   *               distinctness.
   * @param reg_eph Register holding ephemeral space's pointer.
   * @param addr_repeat Jump here if not distinct.
   * @param n Number of elements in record.
   * @param reg_data First register holding the data.
   */
  static void
  vdbe_insert_distinct(struct Parse *parse, int cursor, int reg_eph,
  		     int addr_repeat, int n, int reg_data)
  {
  	struct Vdbe *v = parse->pVdbe;
  	int r1 = sqlGetTempReg(parse);
  	sqlVdbeAddOp4Int(v, OP_Found, cursor, addr_repeat, reg_data, n);
  	sqlVdbeAddOp3(v, OP_MakeRecord, reg_data, n, r1);
  	sqlVdbeAddOp2(v, OP_IdxInsert, r1, reg_eph);
  	sqlReleaseTempReg(parse, r1);
  }
  
  /*
   * This routine generates the code for the inside of the inner loop
   * of a SELECT.
   *
   * If srcTab is negative, then the pEList expressions
   * are evaluated in order to get the data for this row.  If srcTab is
   * zero or more, then data is pulled from srcTab and pEList is used only
   * to get the number of columns and the collation sequence for each column.
   */
  static void
  selectInnerLoop(Parse * pParse,		/* The parser context */
  		Select * p,		/* The complete select statement being coded */
  		ExprList * pEList,	/* List of values being extracted */
  		int srcTab,		/* Pull data from this table */
  		SortCtx * pSort,	/* If not NULL, info on how to process ORDER BY */
  		DistinctCtx * pDistinct,	/* If not NULL, info on how to process DISTINCT */
  		SelectDest * pDest,	/* How to dispose of the results */
  		int iContinue,		/* Jump here to continue with next row */
  		int iBreak)		/* Jump here to break out of the inner loop */
  {
  	Vdbe *v = pParse->pVdbe;
  	int i;
  	int hasDistinct;		/* True if the DISTINCT keyword is present */
  	int eDest = pDest->eDest;	/* How to dispose of results */
  	int iParm = pDest->iSDParm;	/* First argument to disposal method */
  	int nResultCol;			/* Number of result columns */
  	int nPrefixReg = 0;		/* Number of extra registers before regResult */
  
  	/* Usually, regResult is the first cell in an array of memory cells
  	 * containing the current result row. In this case regOrig is set to the
  	 * same value. However, if the results are being sent to the sorter, the
  	 * values for any expressions that are also part of the sort-key are omitted
  	 * from this array. In this case regOrig is set to zero.
  	 */
  	int regResult;		/* Start of memory holding current results */
  	int regOrig;		/* Start of memory holding full result (or 0) */
  
  	assert(v);
  	assert(pEList != 0);
  	hasDistinct = pDistinct ? pDistinct->eTnctType : WHERE_DISTINCT_NOOP;
  	if (pSort && pSort->pOrderBy == 0)
  		pSort = 0;
  	if (pSort == 0 && !hasDistinct) {
  		assert(iContinue != 0);
  		codeOffset(v, p->iOffset, iContinue);
  	}
  
  	/* Pull the requested columns.
  	 */
  	nResultCol = pEList->nExpr;
  
  	if (pDest->iSdst == 0) {
  		if (pSort) {
  			nPrefixReg = pSort->pOrderBy->nExpr;
  			if (!(pSort->sortFlags & SORTFLAG_UseSorter))
  				nPrefixReg++;
  			pParse->nMem += nPrefixReg;
  		}
  		pDest->iSdst = pParse->nMem + 1;
  		pParse->nMem += nResultCol;
  	} else if (pDest->iSdst + nResultCol > pParse->nMem) {
  		/* This is an error condition that can result, for example, when a SELECT
  		 * on the right-hand side of an INSERT contains more result columns than
  		 * there are columns in the table on the left.  The error will be caught
  		 * and reported later.  But we need to make sure enough memory is allocated
  		 * to avoid other spurious errors in the meantime.
  		 */
  		pParse->nMem += nResultCol;
  	}
  	pDest->nSdst = nResultCol;
  	regOrig = regResult = pDest->iSdst;
  	if (srcTab >= 0) {
  		for (i = 0; i < nResultCol; i++) {
  			sqlVdbeAddOp3(v, OP_Column, srcTab, i,
  					  regResult + i);
  			VdbeComment((v, "%s", pEList->a[i].zName));
  		}
  	} else if (eDest != SRT_Exists) {
  		/* If the destination is an EXISTS(...) expression, the actual
  		 * values returned by the SELECT are not required.
  		 */
  		u8 ecelFlags;
  		if (eDest == SRT_Mem || eDest == SRT_Output
  		    || eDest == SRT_Coroutine) {
  			ecelFlags = SQL_ECEL_DUP;
  		} else {
  			ecelFlags = 0;
  		}
  		if (pSort && hasDistinct == 0 && eDest != SRT_EphemTab
  		    && eDest != SRT_Table) {
  			/* For each expression in pEList that is a copy of an expression in
  			 * the ORDER BY clause (pSort->pOrderBy), set the associated
  			 * iOrderByCol value to one more than the index of the ORDER BY
  			 * expression within the sort-key that pushOntoSorter() will generate.
  			 * This allows the pEList field to be omitted from the sorted record,
  			 * saving space and CPU cycles.
  			 */
  			ecelFlags |= (SQL_ECEL_OMITREF | SQL_ECEL_REF);
  			/*
  			 * Format for ephemeral space has been
  			 * already set with field count calculated
  			 * as orderBy->nExpr + pEList->nExpr + 1,
  			 * where pEList is a select list.
  			 * Since we want to reduce number of fields
  			 * in format of ephemeral space, we should
  			 * fix corresponding opcode's argument.
  			 * Otherwise, tuple format won't match
  			 * space format.
  			 */
  			uint32_t excess_field_count = 0;
  			for (i = pSort->nOBSat; i < pSort->pOrderBy->nExpr;
  			     i++) {
  				int j = pSort->pOrderBy->a[i].u.x.iOrderByCol;
  				if (j > 0) {
  					excess_field_count++;
  					pEList->a[j - 1].u.x.iOrderByCol =
  						(u16) (i + 1 - pSort->nOBSat);
  				}
  			}
  			struct VdbeOp *open_eph_op =
  				sqlVdbeGetOp(v, pSort->addrSortIndex);
  			assert(open_eph_op->p2 - excess_field_count > 0);
  			sqlVdbeChangeP2(v, pSort->addrSortIndex,
  					open_eph_op->p2 -
  					excess_field_count);
  			regOrig = 0;
  			assert(eDest == SRT_Set || eDest == SRT_Mem
  			       || eDest == SRT_Coroutine
  			       || eDest == SRT_Output);
  		}
  		nResultCol =
  		    sqlExprCodeExprList(pParse, pEList, regResult, 0,
  					    ecelFlags);
  	}
  
  	/* If the DISTINCT keyword was present on the SELECT statement
  	 * and this row has been seen before, then do not make this row
  	 * part of the result.
  	 */
  	if (hasDistinct) {
  		switch (pDistinct->eTnctType) {
  		case WHERE_DISTINCT_ORDERED:{
  				VdbeOp *pOp;	/* No longer required OpenEphemeral instr. */
  				int iJump;	/* Jump destination */
  				int regPrev;	/* Previous row content */
  
  				/* Allocate space for the previous row */
  				regPrev = pParse->nMem + 1;
  				pParse->nMem += nResultCol;
  
  				/*
  				 * Actually, for DISTINCT handling
  				 * two op-codes were emitted here:
  				 * OpenTEphemeral & IteratorOpen.
  				 * So, we need to Noop one and
  				 * re-use second for Null op-code.
  				 *
  				 * Change to an OP_Null sets the
  				 * MEM_Cleared bit on the first
  				 * register of the previous value. 
  				 * This will cause the OP_Ne below
  				 * to always fail on the first
  				 * iteration of the loop even if
  				 * the first row is all NULLs.
  				 */
  				sqlVdbeChangeToNoop(v, pDistinct->addrTnct);
  				pOp = sqlVdbeGetOp(v, pDistinct->addrTnct + 1);
  				pOp->opcode = OP_Null;
  				pOp->p1 = 1;
  				pOp->p2 = regPrev;
  
  				iJump = sqlVdbeCurrentAddr(v) + nResultCol;
  				for (i = 0; i < nResultCol; i++) {
  					bool is_found;
  					uint32_t id;
  					struct coll *coll;
  					if (sql_expr_coll(pParse,
  							  pEList->a[i].pExpr,
  							  &is_found, &id,
  							  &coll) != 0)
  						break;
  					if (i < nResultCol - 1) {
  						sqlVdbeAddOp3(v, OP_Ne,
  								  regResult + i,
  								  iJump,
  								  regPrev + i);
  						VdbeCoverage(v);
  					} else {
  						sqlVdbeAddOp3(v, OP_Eq,
  								  regResult + i,
  								  iContinue,
  								  regPrev + i);
  						VdbeCoverage(v);
  					}
  					if (coll != NULL) {
  						sqlVdbeChangeP4(v, -1,
  								    (const char *)coll,
  								    P4_COLLSEQ);
  					}
  					sqlVdbeChangeP5(v, SQL_NULLEQ);
  				}
  				assert(sqlVdbeCurrentAddr(v) == iJump
  				       || pParse->db->mallocFailed);
  				sqlVdbeAddOp3(v, OP_Copy, regResult,
  						  regPrev, nResultCol - 1);
  				break;
  			}
  
  		case WHERE_DISTINCT_UNIQUE:{
  			/**
  			 * To handle DISTINCT two op-codes are
  			 * emitted: OpenTEphemeral & IteratorOpen.
  			 * addrTnct is address of first insn in
  			 * a couple. To evict ephemral space,
  			 * need to noop both op-codes.
  			 */
  			sqlVdbeChangeToNoop(v, pDistinct->addrTnct);
  			sqlVdbeChangeToNoop(v, pDistinct->addrTnct + 1);
  			break;
  			}
  
  		default:{
  			assert(pDistinct->eTnctType ==
  			       WHERE_DISTINCT_UNORDERED);
  			vdbe_insert_distinct(pParse, pDistinct->cur_eph,
  					     pDistinct->reg_eph, iContinue,
  					     nResultCol, regResult);
  			break;
  		}
  		}
  		if (pSort == 0) {
  			codeOffset(v, p->iOffset, iContinue);
  		}
  	}
  
  	switch (eDest) {
  		/* In this mode, write each query result to the key of the temporary
  		 * table iParm.
  		 */
  	case SRT_Union:{
  			int r1;
  			r1 = sqlGetTempReg(pParse);
  			sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
  					  nResultCol, r1);
  			sqlVdbeAddOp2(v, OP_IdxInsert,  r1, pDest->reg_eph);
  			sqlReleaseTempReg(pParse, r1);
  			break;
  		}
  
  		/* Construct a record from the query result, but instead of
  		 * saving that record, use it as a key to delete elements from
  		 * the temporary table iParm.
  		 */
  	case SRT_Except:{
  			sqlVdbeAddOp3(v, OP_IdxDelete, iParm, regResult,
  					  nResultCol);
  			break;
  		}
  
  		/* Store the result as data using a unique key.
  		 */
  	case SRT_Fifo:
  	case SRT_DistFifo:
  	case SRT_Table:
  	case SRT_EphemTab:{
  			int r1 = sqlGetTempRange(pParse, nPrefixReg + 1);
  			testcase(eDest == SRT_Table);
  			testcase(eDest == SRT_EphemTab);
  			testcase(eDest == SRT_Fifo);
  			testcase(eDest == SRT_DistFifo);
  			sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
  					  nResultCol, r1 + nPrefixReg);
  			/* Set flag to save memory allocating one by malloc. */
  			sqlVdbeChangeP5(v, 1);
  
  			if (eDest == SRT_DistFifo) {
  				/* If the destination is DistFifo, then cursor (iParm+1) is open
  				 * on an ephemeral index. If the current row is already present
  				 * in the index, do not write it to the output. If not, add the
  				 * current row to the index and proceed with writing it to the
  				 * output table as well.
  				 */
  				int addr = sqlVdbeCurrentAddr(v) + 6;
  				sqlVdbeAddOp4Int(v, OP_Found, iParm + 1,
  						     addr, r1, 0);
  				VdbeCoverage(v);
  				sqlVdbeAddOp2(v, OP_IdxInsert, r1,
  						  pDest->reg_eph + 1);
  				assert(pSort == 0);
  			}
  
  			if (pSort) {
  				pushOntoSorter(pParse, pSort, p,
  					       r1 + nPrefixReg, regResult, 1,
  					       nPrefixReg);
  			} else {
  				int regRec = sqlGetTempReg(pParse);
  				/* Last column is required for ID. */
  				int regCopy = sqlGetTempRange(pParse, nResultCol + 1);
  				sqlVdbeAddOp2(v, OP_NextIdEphemeral, pDest->reg_eph,
  						  regCopy + nResultCol);
  				/* Positioning ID column to be last in inserted tuple.
  				 * NextId -> regCopy + n + 1
  				 * Copy [regResult, regResult + n] -> [regCopy, regCopy + n]
  				 * MakeRecord -> [regCopy, regCopy + n + 1] -> regRec
  				 * IdxInsert -> regRec
  				 */
  				sqlVdbeAddOp3(v, OP_Copy, regResult, regCopy, nResultCol - 1);
  				sqlVdbeAddOp3(v, OP_MakeRecord, regCopy, nResultCol + 1, regRec);
  				/* Set flag to save memory allocating one by malloc. */
  				sqlVdbeChangeP5(v, 1);
  				sqlVdbeAddOp2(v, OP_IdxInsert, regRec, pDest->reg_eph);
  				sqlReleaseTempReg(pParse, regRec);
  				sqlReleaseTempRange(pParse, regCopy, nResultCol + 1);
  			}
  			sqlReleaseTempRange(pParse, r1, nPrefixReg + 1);
  			break;
  		}
  		/* If we are creating a set for an "expr IN (SELECT ...)" construct,
  		 * then there should be a single item on the stack.  Write this
  		 * item into the set table with bogus data.
  		 */
  	case SRT_Set:{
  			if (pSort) {
  				/* At first glance you would think we could optimize out the
  				 * ORDER BY in this case since the order of entries in the set
  				 * does not matter.  But there might be a LIMIT clause, in which
  				 * case the order does matter.
  				 */
  				pushOntoSorter(pParse, pSort, p, regResult,
  					       regOrig, nResultCol, nPrefixReg);
  			} else {
  				int r1 = sqlGetTempReg(pParse);
  				enum field_type *types =
  					field_type_sequence_dup(pParse,
  								pDest->dest_type,
  								nResultCol);
  				sqlVdbeAddOp4(v, OP_MakeRecord, regResult,
  						  nResultCol, r1, (char *)types,
  						  P4_DYNAMIC);
  				sql_expr_type_cache_change(pParse,
  							   regResult,
  							   nResultCol);
  				sqlVdbeAddOp2(v, OP_IdxInsert, r1, pDest->reg_eph);
  				sqlReleaseTempReg(pParse, r1);
  			}
  			break;
  		}
  
  		/* If any row exist in the result set, record that fact and abort.
  		 */
  	case SRT_Exists:{
  			sqlVdbeAddOp2(v, OP_Bool, true, iParm);
  			/* The LIMIT clause will terminate the loop for us */
  			break;
  		}
  
  		/* If this is a scalar select that is part of an expression, then
  		 * store the results in the appropriate memory cell or array of
  		 * memory cells and break out of the scan loop.
  		 */
  	case SRT_Mem:{
  			if (pSort) {
  				assert(nResultCol <= pDest->nSdst);
  				pushOntoSorter(pParse, pSort, p, regResult,
  					       regOrig, nResultCol, nPrefixReg);
  			} else {
  				assert(nResultCol == pDest->nSdst);
  				assert(regResult == iParm);
  				/* The LIMIT clause will jump out of the loop for us */
  			}
  			break;
  		}
  
  	case SRT_Coroutine:	/* Send data to a co-routine */
  	case SRT_Output:{	/* Return the results */
  			testcase(eDest == SRT_Coroutine);
  			testcase(eDest == SRT_Output);
  			if (pSort) {
  				pushOntoSorter(pParse, pSort, p, regResult,
  					       regOrig, nResultCol, nPrefixReg);
  			} else if (eDest == SRT_Coroutine) {
  				sqlVdbeAddOp1(v, OP_Yield, pDest->iSDParm);
  			} else {
  				sqlVdbeAddOp2(v, OP_ResultRow, regResult,
  						  nResultCol);
  				sql_expr_type_cache_change(pParse,
  							   regResult,
  							   nResultCol);
  			}
  			break;
  		}
  
  		/* Write the results into a priority queue that is order according to
  		 * pDest->pOrderBy (in pSO).  pDest->iSDParm (in iParm) is the cursor for an
  		 * index with pSO->nExpr+2 columns.  Build a key using pSO for the first
  		 * pSO->nExpr columns, then make sure all keys are unique by adding a
  		 * final OP_Sequence column.  The last column is the record as a blob.
  		 */
  	case SRT_DistQueue:
  	case SRT_Queue:{
  			int nKey;
  			int r1, r2, r3;
  			int addrTest = 0;
  			ExprList *pSO;
  			pSO = pDest->pOrderBy;
  			assert(pSO);
  			nKey = pSO->nExpr;
  			r1 = sqlGetTempReg(pParse);
  			r2 = sqlGetTempRange(pParse, nKey + 2);
  			r3 = r2 + nKey + 1;
  			if (eDest == SRT_DistQueue) {
  				/* If the destination is DistQueue, then cursor (iParm+1) is open
  				 * on a second ephemeral index that holds all values every previously
  				 * added to the queue.
  				 */
  				addrTest =
  				    sqlVdbeAddOp4Int(v, OP_Found, iParm + 1,
  							 0, regResult,
  							 nResultCol);
  				VdbeCoverage(v);
  			}
  			sqlVdbeAddOp3(v, OP_MakeRecord, regResult,
  					  nResultCol, r3);
  			if (eDest == SRT_DistQueue) {
  				sqlVdbeAddOp2(v, OP_IdxInsert, r3,
  						  pDest->reg_eph + 1);
  			}
  			for (i = 0; i < nKey; i++) {
  				sqlVdbeAddOp2(v, OP_SCopy,
  						  regResult +
  						  pSO->a[i].u.x.iOrderByCol - 1,
  						  r2 + i);
  			}
  			sqlVdbeAddOp2(v, OP_Sequence, iParm, r2 + nKey);
  			sqlVdbeAddOp3(v, OP_MakeRecord, r2, nKey + 2, r1);
  			sqlVdbeAddOp2(v, OP_IdxInsert, r1, pDest->reg_eph);
  			if (addrTest)
  				sqlVdbeJumpHere(v, addrTest);
  			sqlReleaseTempReg(pParse, r1);
  			sqlReleaseTempRange(pParse, r2, nKey + 2);
  			break;
  		}
  
  		/* Discard the results.  This is used for SELECT statements inside
  		 * the body of a TRIGGER.  The purpose of such selects is to call
  		 * user-defined functions that have side effects.  We do not care
  		 * about the actual results of the select.
  		 */
  	default:{
  			assert(eDest == SRT_Discard);
  			break;
  		}
  	}
  
  	/* Jump to the end of the loop if the LIMIT is reached.  Except, if
  	 * there is a sorter, in which case the sorter has already limited
  	 * the output for us.
  	 */
  	if (pSort == 0 && p->iLimit) {
  		sqlVdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, iBreak);
  		VdbeCoverage(v);
  	}
  }
  
  static inline size_t
  sql_key_info_sizeof(uint32_t part_count)
  {
  	return sizeof(struct sql_key_info) +
  		part_count * sizeof(struct key_part_def);
  }
  
  struct sql_key_info *
  sql_key_info_new(sql *db, uint32_t part_count)
  {
  	struct sql_key_info *key_info = sqlDbMallocRawNN(db,
  				sql_key_info_sizeof(part_count));
  	if (key_info == NULL) {
  		sqlOomFault(db);
  		return NULL;
  	}
  	key_info->db = db;
  	key_info->key_def = NULL;
  	key_info->refs = 1;
  	key_info->part_count = part_count;
  	for (uint32_t i = 0; i < part_count; i++) {
  		struct key_part_def *part = &key_info->parts[i];
  		part->fieldno = i;
  		part->type = FIELD_TYPE_SCALAR;
  		part->coll_id = COLL_NONE;
  		part->is_nullable = false;
  		part->nullable_action = ON_CONFLICT_ACTION_ABORT;
  		part->sort_order = SORT_ORDER_ASC;
  		part->path = NULL;
  	}
  	return key_info;
  }
  
  struct sql_key_info *
  sql_key_info_new_from_key_def(sql *db, const struct key_def *key_def)
  {
  	struct sql_key_info *key_info = sqlDbMallocRawNN(db,
  				sql_key_info_sizeof(key_def->part_count));
  	if (key_info == NULL) {
  		sqlOomFault(db);
  		return NULL;
  	}
  	key_info->db = db;
  	key_info->key_def = NULL;
  	key_info->refs = 1;
  	key_info->part_count = key_def->part_count;
  	key_def_dump_parts(key_def, key_info->parts, NULL);
  	return key_info;
  }
  
  struct sql_key_info *
  sql_key_info_ref(struct sql_key_info *key_info)
  {
  	assert(key_info->refs > 0);
  	key_info->refs++;
  	return key_info;
  }
  
  void
  sql_key_info_unref(struct sql_key_info *key_info)
  {
  	if (key_info == NULL)
  		return;
  	assert(key_info->refs > 0);
  	if (--key_info->refs == 0) {
  		if (key_info->key_def != NULL)
  			key_def_delete(key_info->key_def);
  		sqlDbFree(key_info->db, key_info);
  	}
  }
  
  struct key_def *
  sql_key_info_to_key_def(struct sql_key_info *key_info)
  {
  	if (key_info->key_def == NULL) {
  		key_info->key_def = key_def_new(key_info->parts,
  						key_info->part_count, false);
  	}
  	return key_info->key_def;
  }
  
  static struct sql_key_info *
  sql_expr_list_to_key_info(struct Parse *parse, struct ExprList *list, int start)
  {
  	int expr_count = list->nExpr;
  	struct sql_key_info *key_info = sql_key_info_new(parse->db, expr_count);
  	if (key_info == NULL)
  		return NULL;
  	struct ExprList_item *item = list->a + start;
  	for (int i = start; i < expr_count; ++i, ++item) {
  		struct key_part_def *part = &key_info->parts[i - start];
  		bool unused;
  		uint32_t id;
  		struct coll *unused_coll;
  		if (sql_expr_coll(parse, item->pExpr, &unused, &id,
  				  &unused_coll) != 0) {
  			sqlDbFree(parse->db, key_info);
  			return NULL;
  		}
  		part->coll_id = id;
  		part->sort_order = item->sort_order;
  		part->type = sql_expr_type(item->pExpr);
  	}
  	return key_info;
  }
  
  const char *
  sql_select_op_name(int id)
  {
  	char *z;
  	switch (id) {
  	case TK_ALL:
  		z = "UNION ALL";
  		break;
  	case TK_INTERSECT:
  		z = "INTERSECT";
  		break;
  	case TK_EXCEPT:
  		z = "EXCEPT";
  		break;
  	default:
  		z = "UNION";
  		break;
  	}
  	return z;
  }
  
  /*
   * Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
   * is a no-op. Otherwise, it adds a single row of output to the EQP result,
   * where the caption is of the form:
   *
   *   "USE TEMP B-TREE FOR xxx"
   *
   * where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which
   * is determined by the zUsage argument.
   */
  static void
  explainTempTable(Parse * pParse, const char *zUsage)
  {
  	if (pParse->explain == 2) {
  		Vdbe *v = pParse->pVdbe;
  		char *zMsg =
  		    sqlMPrintf(pParse->db, "USE TEMP B-TREE FOR %s",
  				   zUsage);
  		sqlVdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg,
  				  P4_DYNAMIC);
  	}
  }
  
  /*
   * Unless an "EXPLAIN QUERY PLAN" command is being processed, this function
   * is a no-op. Otherwise, it adds a single row of output to the EQP result,
   * where the caption is of one of the two forms:
   *
   *   "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)"
   *   "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)"
   *
   * where iSub1 and iSub2 are the integers passed as the corresponding
   * function parameters, and op is the text representation of the parameter
   * of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT,
   * TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is
   * false, or the second form if it is true.
   */
  static void
  explainComposite(Parse * pParse,	/* Parse context */
  		 int op,	/* One of TK_UNION, TK_EXCEPT etc. */
  		 int iSub1,	/* Subquery id 1 */
  		 int iSub2,	/* Subquery id 2 */
  		 int bUseTmp	/* True if a temp table was used */
      )
  {
  	assert(op == TK_UNION || op == TK_EXCEPT || op == TK_INTERSECT
  	       || op == TK_ALL);
  	if (pParse->explain == 2) {
  		Vdbe *v = pParse->pVdbe;
  		char *zMsg =
  		    sqlMPrintf(pParse->db,
  				   "COMPOUND SUBQUERIES %d AND %d %s(%s)",
  				   iSub1, iSub2,
  				   bUseTmp ? "USING TEMP B-TREE " : "",
  				   sql_select_op_name(op)
  		    );
  		sqlVdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg,
  				  P4_DYNAMIC);
  	}
  }
  
  /*
   * If the inner loop was generated using a non-null pOrderBy argument,
   * then the results were placed in a sorter.  After the loop is terminated
   * we need to run the sorter and output the results.  The following
   * routine generates the code needed to do that.
   */
  static void
  generateSortTail(Parse * pParse,	/* Parsing context */
  		 Select * p,		/* The SELECT statement */
  		 SortCtx * pSort,	/* Information on the ORDER BY clause */
  		 int nColumn,		/* Number of columns of data */
  		 SelectDest * pDest)	/* Write the sorted results here */
  {
  	Vdbe *v = pParse->pVdbe;	/* The prepared statement */
  	int addrBreak = pSort->labelDone;	/* Jump here to exit loop */
  	int addrContinue = sqlVdbeMakeLabel(v);	/* Jump here for next cycle */
  	int addr;
  	int addrOnce = 0;
  	int iTab;
  	ExprList *pOrderBy = pSort->pOrderBy;
  	int eDest = pDest->eDest;
  	int regRow;
  	int regTupleid;
  	int iCol;
  	int nKey;
  	int iSortTab;		/* Sorter cursor to read from */
  	int nSortData;		/* Trailing values to read from sorter */
  	int i;
  	int bSeq;		/* True if sorter record includes seq. no. */
  	struct ExprList_item *aOutEx = p->pEList->a;
  
  	assert(addrBreak < 0);
  	if (pSort->labelBkOut) {
  		sqlVdbeAddOp2(v, OP_Gosub, pSort->regReturn,
  				  pSort->labelBkOut);
  		sqlVdbeGoto(v, addrBreak);
  		sqlVdbeResolveLabel(v, pSort->labelBkOut);
  	}
  	iTab = pSort->iECursor;
  	if (eDest == SRT_Output || eDest == SRT_Coroutine || eDest == SRT_Mem) {
  		regTupleid = 0;
  		regRow = pDest->iSdst;
  		nSortData = nColumn;
  	} else {
  		regTupleid = sqlGetTempReg(pParse);
  		regRow = sqlGetTempRange(pParse, nColumn);
  		nSortData = nColumn;
  	}
  	nKey = pOrderBy->nExpr - pSort->nOBSat;
  	if (pSort->sortFlags & SORTFLAG_UseSorter) {
  		int regSortOut = ++pParse->nMem;
  		iSortTab = pParse->nTab++;
  		if (pSort->labelBkOut) {
  			addrOnce = sqlVdbeAddOp0(v, OP_Once);
  			VdbeCoverage(v);
  		}
  		sqlVdbeAddOp3(v, OP_OpenPseudo, iSortTab, regSortOut,
  				  nKey + 1 + nSortData);
  		if (addrOnce)
  			sqlVdbeJumpHere(v, addrOnce);
  		addr = 1 + sqlVdbeAddOp2(v, OP_SorterSort, iTab, addrBreak);
  		VdbeCoverage(v);
  		codeOffset(v, p->iOffset, addrContinue);
  		sqlVdbeAddOp3(v, OP_SorterData, iTab, regSortOut, iSortTab);
  		bSeq = 0;
  	} else {
  		/* In case of DESC sorting order data should be taken from
  		 * the end of table. */
  		int opPositioning = (pSort->sortFlags & SORTFLAG_DESC) ?
  				    OP_Last : OP_Sort;
  		addr = 1 + sqlVdbeAddOp2(v, opPositioning, iTab, addrBreak);
  		VdbeCoverage(v);
  		codeOffset(v, p->iOffset, addrContinue);
  		iSortTab = iTab;
  		bSeq = 1;
  	}
  	for (i = 0, iCol = nKey + bSeq; i < nSortData; i++) {
  		int iRead;
  		if (aOutEx[i].u.x.iOrderByCol) {
  			iRead = aOutEx[i].u.x.iOrderByCol - 1;
  		} else {
  			iRead = iCol++;
  		}
  		sqlVdbeAddOp3(v, OP_Column, iSortTab, iRead, regRow + i);
  		VdbeComment((v, "%s",
  			     aOutEx[i].zName ? aOutEx[i].zName : aOutEx[i].
  			     zSpan));
  	}
  	switch (eDest) {
  	case SRT_Table:
  	case SRT_EphemTab: {
  			int regCopy = sqlGetTempRange(pParse,  nColumn);
  			sqlVdbeAddOp2(v, OP_NextIdEphemeral, pDest->reg_eph,
  					  regTupleid);
  			sqlVdbeAddOp3(v, OP_Copy, regRow, regCopy, nSortData - 1);
  			sqlVdbeAddOp3(v, OP_MakeRecord, regCopy, nColumn + 1, regRow);
  			sqlVdbeAddOp2(v, OP_IdxInsert, regRow, pDest->reg_eph);
  			sqlReleaseTempReg(pParse, regCopy);
  			break;
  		}
  	case SRT_Set:{
  			enum field_type *types =
  				field_type_sequence_dup(pParse, pDest->dest_type,
  							nColumn);
  			sqlVdbeAddOp4(v, OP_MakeRecord, regRow, nColumn,
  					  regTupleid, (char *)types,
  					  P4_DYNAMIC);
  			sql_expr_type_cache_change(pParse, regRow, nColumn);
  			sqlVdbeAddOp2(v, OP_IdxInsert, regTupleid, pDest->reg_eph);
  			break;
  		}
  	case SRT_Mem:{
  			/* The LIMIT clause will terminate the loop for us */
  			break;
  		}
  	default: {
  			assert(eDest == SRT_Output || eDest == SRT_Coroutine);
  			testcase(eDest == SRT_Output);
  			testcase(eDest == SRT_Coroutine);
  			if (eDest == SRT_Output) {
  				sqlVdbeAddOp2(v, OP_ResultRow, pDest->iSdst,
  						  nColumn);
  				sql_expr_type_cache_change(pParse,
  							   pDest->iSdst,
  							   nColumn);
  			} else {
  				sqlVdbeAddOp1(v, OP_Yield, pDest->iSDParm);
  			}
  			break;
  		}
  	}
  	if (regTupleid) {
  		if (eDest == SRT_Set) {
  			sqlReleaseTempRange(pParse, regRow, nColumn);
  		} else {
  			sqlReleaseTempReg(pParse, regRow);
  		}
  		sqlReleaseTempReg(pParse, regTupleid);
  	}
  	/* The bottom of the loop
  	 */
  	sqlVdbeResolveLabel(v, addrContinue);
  	if (pSort->sortFlags & SORTFLAG_UseSorter) {
  		sqlVdbeAddOp2(v, OP_SorterNext, iTab, addr);
  		VdbeCoverage(v);
  	} else {
  		/* In case of DESC sorting cursor should move backward. */
  		int opPositioning = (pSort->sortFlags & SORTFLAG_DESC) ?
  				    OP_Prev : OP_Next;
  		sqlVdbeAddOp2(v, opPositioning, iTab, addr);
  		VdbeCoverage(v);
  	}
  	if (pSort->regReturn)
  		sqlVdbeAddOp1(v, OP_Return, pSort->regReturn);
  	sqlVdbeResolveLabel(v, addrBreak);
  }
  
  /*
   * Generate code that will tell the VDBE the names of columns
   * in the result set.  This information is used to provide the
   * azCol[] values in the callback.
   */
  static void
  generateColumnNames(Parse * pParse,	/* Parser context */
  		    SrcList * pTabList,	/* List of tables */
  		    ExprList * pEList)	/* Expressions defining the result set */
  {
  	Vdbe *v = pParse->pVdbe;
  	int i, j;
  	sql *db = pParse->db;
  	int fullNames, shortNames;
  	/* If this is an EXPLAIN, skip this step */
  	if (pParse->explain) {
  		return;
  	}
  
  	if (pParse->colNamesSet || db->mallocFailed)
  		return;
  	assert(v != 0);
  	size_t var_pos_sz =  pParse->nVar * sizeof(uint32_t);
  	uint32_t *var_pos = (uint32_t *) region_alloc(&pParse->region,
  						      var_pos_sz);
  	if (var_pos == NULL) {
  		diag_set(OutOfMemory, var_pos_sz, "region", "var_pos");
  		return;
  	}
  	assert(pTabList != 0);
  	pParse->colNamesSet = 1;
  	fullNames = (pParse->sql_flags & SQL_FullColNames) != 0;
  	shortNames = (pParse->sql_flags & SQL_ShortColNames) != 0;
  	sqlVdbeSetNumCols(v, pEList->nExpr);
  	uint32_t var_count = 0;
  	for (i = 0; i < pEList->nExpr; i++) {
  		Expr *p;
  		p = pEList->a[i].pExpr;
  		if (NEVER(p == 0))
  			continue;
  		if (p->op == TK_VARIABLE)
  			var_pos[var_count++] = i;
  		sqlVdbeSetColName(v, i, COLNAME_DECLTYPE,
  				  field_type_strs[sql_expr_type(p)], SQL_TRANSIENT);
  		if (pEList->a[i].zName) {
  			char *zName = pEList->a[i].zName;
  			sqlVdbeSetColName(v, i, COLNAME_NAME, zName,
  					      SQL_TRANSIENT);
  		} else if (p->op == TK_COLUMN || p->op == TK_AGG_COLUMN) {
  			char *zCol;
  			int iCol = p->iColumn;
  			for (j = 0; ALWAYS(j < pTabList->nSrc); j++) {
  				if (pTabList->a[j].iCursor == p->iTable)
  					break;
  			}
  			assert(j < pTabList->nSrc);
  			struct space_def *space_def = pTabList->a[j].space->def;
  			assert(iCol >= 0 && iCol < (int)space_def->field_count);
  			zCol = space_def->fields[iCol].name;
  			if (!shortNames && !fullNames) {
  				sqlVdbeSetColName(v, i, COLNAME_NAME,
  						      sqlDbStrDup(db,
  								      pEList->a[i].zSpan),
  						      SQL_DYNAMIC);
  			} else if (fullNames) {
  				char *zName = 0;
  				zName = sqlMPrintf(db, "%s.%s",
  						       space_def->name, zCol);
  				sqlVdbeSetColName(v, i, COLNAME_NAME, zName,
  						      SQL_DYNAMIC);
  			} else {
  				sqlVdbeSetColName(v, i, COLNAME_NAME, zCol,
  						      SQL_TRANSIENT);
  			}
  		} else {
  			const char *z = pEList->a[i].zSpan;
  			z = z == 0 ? sqlMPrintf(db, "column%d",
  						    i + 1) : sqlDbStrDup(db,
  									     z);
  			sqlVdbeSetColName(v, i, COLNAME_NAME, z,
  					      SQL_DYNAMIC);
  		}
  	}
  	if (var_count == 0)
  		return;
  	v->var_pos = (uint32_t *) malloc(var_count * sizeof(uint32_t));
  	if (v->var_pos ==  NULL) {
  		diag_set(OutOfMemory, var_count * sizeof(uint32_t),
  			 "malloc", "v->var_pos");
  		return;
  	}
  	memcpy(v->var_pos, var_pos, var_count * sizeof(uint32_t));
  	v->res_var_count = var_count;
  }
  
  /*
   * Given an expression list (which is really the list of expressions
   * that form the result set of a SELECT statement) compute appropriate
   * column names for a table that would hold the expression list.
   *
   * All column names will be unique.
   *
   * Only the column names are computed.  Column.zType, Column.zColl,
   * and other fields of Column are zeroed.
   *
   * Return 0 on success.  If a memory allocation error occurs,
   * store NULL in *paCol and 0 in *pnCol and return -1.
   */
  int
  sqlColumnsFromExprList(Parse * parse, ExprList * expr_list,
  			   struct space_def *space_def)
  {
  	/* Database connection */
  	sql *db = parse->db;
  	u32 cnt;		/* Index added to make the name unique */
  	Expr *p;		/* Expression for a single result column */
  	char *zName;		/* Column name */
  	int nName;		/* Size of name in zName[] */
  	Hash ht;		/* Hash table of column names */
  
  	sqlHashInit(&ht);
  	uint32_t column_count =
  		expr_list != NULL ? (uint32_t)expr_list->nExpr : 0;
  	/*
  	 * This should be a table without resolved columns.
  	 * sqlViewGetColumnNames could use it to resolve
  	 * names for existing table.
  	 */
  	assert(space_def->fields == NULL);
  	struct region *region = &parse->region;
  	space_def->fields =
  		region_alloc(region,
  			     column_count * sizeof(space_def->fields[0]));
  	if (space_def->fields == NULL) {
  		sqlOomFault(db);
  		goto cleanup;
  	}
  	for (uint32_t i = 0; i < column_count; i++) {
  		memcpy(&space_def->fields[i], &field_def_default,
  		       sizeof(field_def_default));
  		space_def->fields[i].nullable_action = ON_CONFLICT_ACTION_NONE;
  		space_def->fields[i].is_nullable = true;
  	}
  	space_def->field_count = column_count;
  
  	for (uint32_t i = 0; i < column_count; i++) {
  		/* Get an appropriate name for the column
  		 */
  		p = sqlExprSkipCollate(expr_list->a[i].pExpr);
  		if ((zName = expr_list->a[i].zName) != 0) {
  			/* If the column contains an "AS <name>" phrase, use <name> as the name */
  		} else {
  			Expr *pColExpr = p;	/* The expression that is the result column name */
  			struct space_def *space_def = NULL;
  			while (pColExpr->op == TK_DOT) {
  				pColExpr = pColExpr->pRight;
  				assert(pColExpr != 0);
  			}
  			if (pColExpr->op == TK_COLUMN
  			    && ALWAYS(pColExpr->space_def != NULL)) {
  				/* For columns use the column name name */
  				int iCol = pColExpr->iColumn;
  				assert(iCol >= 0);
  				space_def = pColExpr->space_def;
  				zName = space_def->fields[iCol].name;
  			} else if (pColExpr->op == TK_ID) {
  				assert(!ExprHasProperty(pColExpr, EP_IntValue));
  				zName = pColExpr->u.zToken;
  			} else {
  				/* Use the original text of the column expression as its name */
  				zName = expr_list->a[i].zSpan;
  			}
  		}
  		if (zName == NULL)
  			zName = "_auto_field_";
  		zName = sqlMPrintf(db, "%s", zName);
  
  		/* Make sure the column name is unique.  If the name is not unique,
  		 * append an integer to the name so that it becomes unique.
  		 */
  		cnt = 0;
  		while (zName && sqlHashFind(&ht, zName) != 0) {
  			nName = sqlStrlen30(zName);
  			if (nName > 0) {
  				int j;
  				for (j = nName - 1;
  				     j > 0 && sqlIsdigit(zName[j]); j--);
  				if (zName[j] == '_')
  					nName = j;
  			}
  			zName =
  			    sqlMPrintf(db, "%.*z_%u", nName, zName, ++cnt);
  		}
  		size_t name_len = strlen(zName);
  		void *field = &space_def->fields[i];
  		if (zName != NULL &&
  		    sqlHashInsert(&ht, zName, field) == field)
  			sqlOomFault(db);
  		space_def->fields[i].name = region_alloc(region, name_len + 1);
  		if (space_def->fields[i].name == NULL) {
  			sqlOomFault(db);
  			goto cleanup;
  		} else {
  			memcpy(space_def->fields[i].name, zName, name_len);
  			space_def->fields[i].name[name_len] = '\0';
  		}
  	}
  cleanup:
  	sqlHashClear(&ht);
  	if (db->mallocFailed) {
  		/*
  		 * pTable->def could be not temporal in
  		 * sqlViewGetColumnNames so we need clean-up.
  		 */
  		space_def->fields = NULL;
  		space_def->field_count = 0;
  		return -1;
  	}
  	return 0;
  
  }
  
  /*
   * Add type and collation information to a column list based on
   * a SELECT statement.
   *
   * The column list presumably came from selectColumnNamesFromExprList().
   * The column list has only names, not types or collations.  This
   * routine goes through and adds the types and collations.
   *
   * This routine requires that all identifiers in the SELECT
   * statement be resolved.
   */
  void
  sqlSelectAddColumnTypeAndCollation(struct Parse *pParse,
  				       struct space_def *def,
  				       struct Select *pSelect)
  {
  	sql *db = pParse->db;
  	NameContext sNC;
  	Expr *p;
  	struct ExprList_item *a;
  
  	assert(pSelect != 0);
  	assert((pSelect->selFlags & SF_Resolved) != 0);
  	assert((int)def->field_count == pSelect->pEList->nExpr ||
  	       db->mallocFailed);
  	if (db->mallocFailed)
  		return;
  	memset(&sNC, 0, sizeof(sNC));
  	sNC.pSrcList = pSelect->pSrc;
  	a = pSelect->pEList->a;
  	for (uint32_t i = 0; i < def->field_count; i++) {
  		p = a[i].pExpr;
  		def->fields[i].type = sql_expr_type(p);
  		bool is_found;
  		uint32_t coll_id;
  		struct coll *unused;
  		if (def->fields[i].coll_id == COLL_NONE &&
  		    sql_expr_coll(pParse, p, &is_found, &coll_id,
  				  &unused) == 0 && coll_id != COLL_NONE)
  			def->fields[i].coll_id = coll_id;
  	}
  }
  
  /*
   * Given a SELECT statement, generate a space structure that describes
   * the result set of that SELECT.
   */
  struct space *
  sqlResultSetOfSelect(Parse * pParse, Select * pSelect)
  {
  	sql *db = pParse->db;
  
  	uint32_t saved_flags = pParse->sql_flags;
  	pParse->sql_flags |= ~SQL_FullColNames;
  	pParse->sql_flags &= SQL_ShortColNames;
  	sqlSelectPrep(pParse, pSelect, 0);
  	if (pParse->is_aborted)
  		return NULL;
  	while (pSelect->pPrior)
  		pSelect = pSelect->pPrior;
  	pParse->sql_flags = saved_flags;
  	struct space *space = sql_ephemeral_space_new(pParse, NULL);
  	if (space == NULL)
  		return NULL;
  	/* The sqlResultSetOfSelect() is only used in contexts where lookaside
  	 * is disabled
  	 */
  	assert(db->lookaside.bDisable);
  	sqlColumnsFromExprList(pParse, pSelect->pEList, space->def);
  	sqlSelectAddColumnTypeAndCollation(pParse, space->def, pSelect);
  	if (db->mallocFailed)
  		return NULL;
  	return space;
  }
  
  /*
   * Get a VDBE for the given parser context.  Create a new one if necessary.
   * If an error occurs, return NULL and leave a message in pParse.
   */
  static SQL_NOINLINE Vdbe *
  allocVdbe(Parse * pParse)
  {
  	Vdbe *v = pParse->pVdbe = sqlVdbeCreate(pParse);
  	if (v == NULL)
  		return NULL;
  	v->sql_flags = pParse->sql_flags;
  	sqlVdbeAddOp2(v, OP_Init, 0, 1);
  	if (pParse->pToplevel == 0
  	    && OptimizationEnabled(pParse->db, SQL_FactorOutConst)
  	    ) {
  		pParse->okConstFactor = 1;
  	}
  	return v;
  }
  
  Vdbe *
  sqlGetVdbe(Parse * pParse)
  {
  	Vdbe *v = pParse->pVdbe;
  	return v ? v : allocVdbe(pParse);
  }
  
  /*
   * Compute the iLimit and iOffset fields of the SELECT based on the
   * pLimit and pOffset expressions.  pLimit and pOffset hold the expressions
   * that appear in the original SQL statement after the LIMIT and OFFSET
   * keywords.  Or NULL if those keywords are omitted. iLimit and iOffset
   * are the integer memory register numbers for counters used to compute
   * the limit and offset.  If there is no limit and/or offset, then
   * iLimit and iOffset are negative.
   *
   * This routine changes the values of iLimit and iOffset only if
   * a limit or offset is defined by pLimit and pOffset.  iLimit and
   * iOffset should have been preset to appropriate default values (zero)
   * prior to calling this routine.
   *
   * The iOffset register (if it exists) is initialized to the value
   * of the OFFSET.  The iLimit register is initialized to LIMIT.  Register
   * iOffset+1 is initialized to LIMIT+OFFSET.
   *
   * Only if pLimit!=0 or pOffset!=0 do the limit registers get
   * redefined.  The UNION ALL operator uses this property to force
   * the reuse of the same limit and offset registers across multiple
   * SELECT statements.
   */
  static void
  computeLimitRegisters(Parse * pParse, Select * p, int iBreak)
  {
  	Vdbe *v = 0;
  	int iLimit = 0;
  	int iOffset;
  	if (p->iLimit)
  		return;
  
  	/*
  	 * "LIMIT -1" always shows all rows.  There is some
  	 * controversy about what the correct behavior should be.
  	 * The current implementation interprets "LIMIT 0" to mean
  	 * no rows.
  	 */
  	sqlExprCacheClear(pParse);
  	assert(p->pOffset == 0 || p->pLimit != 0);
  	if (p->pLimit) {
  		if((p->pLimit->flags & EP_Collate) != 0 ||
  		   (p->pOffset != NULL &&
  		   (p->pOffset->flags & EP_Collate) != 0)) {
  			diag_set(ClientError, ER_SQL_UNRECOGNIZED_SYNTAX,
  				 sizeof("COLLATE"), "COLLATE");
  			pParse->is_aborted = true;
  			return;
  		}
  		p->iLimit = iLimit = ++pParse->nMem;
  		v = sqlGetVdbe(pParse);
  		assert(v != 0);
  		int positive_limit_label = sqlVdbeMakeLabel(v);
  		int halt_label = sqlVdbeMakeLabel(v);
  		sqlExprCode(pParse, p->pLimit, iLimit);
  		sqlVdbeAddOp2(v, OP_MustBeInt, iLimit, halt_label);
  		/* If LIMIT clause >= 0 continue execution */
  		int r1 = sqlGetTempReg(pParse);
  		sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  		sqlVdbeAddOp3(v, OP_Ge, r1, positive_limit_label, iLimit);
  		/* Otherwise return an error and stop */
  		const char *err = tt_sprintf(tnt_errcode_desc(ER_SQL_EXECUTE),
  					     "Only positive integers are "\
  					     "allowed in the LIMIT clause");
  		sqlVdbeResolveLabel(v, halt_label);
  		sqlVdbeAddOp4(v, OP_SetDiag, ER_SQL_EXECUTE, 0, 0, err,
  			      P4_STATIC);
  		sqlVdbeAddOp1(v, OP_Halt, -1);
  
  		sqlVdbeResolveLabel(v, positive_limit_label);
  		VdbeCoverage(v);
  		VdbeComment((v, "LIMIT counter"));
  		sqlVdbeAddOp3(v, OP_Eq, r1, iBreak, iLimit);
  		sqlReleaseTempReg(pParse, r1);
  
  		if ((p->selFlags & SF_SingleRow) != 0) {
  			if (ExprHasProperty(p->pLimit, EP_System)) {
  				/*
  				 * Indirect LIMIT 1 is allowed only for
  				 * requests returning only 1 row.
  				 * To test this, we change LIMIT 1 to
  				 * LIMIT 2 and will look up LIMIT 1 overflow
  				 * at the sqlSelect end.
  				 */
  				sqlVdbeAddOp2(v, OP_Integer, 2, iLimit);
  			} else {
  				/*
  				 * User-defined complex limit for subquery
  				 * could be only 1 as resulting value.
  				 */
  				int r1 = sqlGetTempReg(pParse);
  				sqlVdbeAddOp2(v, OP_Integer, 1, r1);
  				int no_err = sqlVdbeMakeLabel(v);
  				sqlVdbeAddOp3(v, OP_Eq, iLimit, no_err, r1);
  				err = tnt_errcode_desc(ER_SQL_EXECUTE);
  				err = tt_sprintf(err, "Expression subquery "\
  						 "could be limited only "\
  						 "with 1");
  				sqlVdbeAddOp4(v, OP_SetDiag, ER_SQL_EXECUTE, 0,
  					      0, err, P4_STATIC);
  				sqlVdbeAddOp1(v, OP_Halt, -1);
  				sqlVdbeResolveLabel(v, no_err);
  				sqlReleaseTempReg(pParse, r1);
  
  				/* Runtime checks are no longer needed. */
  				p->selFlags &= ~SF_SingleRow;
  			}
  		}
  		if (p->pOffset) {
  			int positive_offset_label = sqlVdbeMakeLabel(v);
  			int offset_error_label = sqlVdbeMakeLabel(v);
  			p->iOffset = iOffset = ++pParse->nMem;
  			pParse->nMem++;	/* Allocate an extra register for limit+offset */
  			sqlExprCode(pParse, p->pOffset, iOffset);
  			sqlVdbeAddOp2(v, OP_MustBeInt, iOffset, offset_error_label);
  			/* If OFFSET clause >= 0 continue execution */
              		int r1 = sqlGetTempReg(pParse);
              		sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  
              		sqlVdbeAddOp3(v, OP_Ge, r1, positive_offset_label, iOffset);
  			/* Otherwise return an error and stop */
  			err = tt_sprintf(tnt_errcode_desc(ER_SQL_EXECUTE),
  					 "Only positive integers are allowed "\
  					 "in the OFFSET clause");
  			sqlVdbeResolveLabel(v, offset_error_label);
  			sqlVdbeAddOp4(v, OP_SetDiag, ER_SQL_EXECUTE, 0, 0, err,
  				      P4_STATIC);
  			sqlVdbeAddOp1(v, OP_Halt, -1);
  
  			sqlVdbeResolveLabel(v, positive_offset_label);
              		sqlReleaseTempReg(pParse, r1);
  			VdbeCoverage(v);
  			VdbeComment((v, "OFFSET counter"));
  			sqlVdbeAddOp3(v, OP_OffsetLimit, iLimit,
  					  iOffset + 1, iOffset);
  			VdbeComment((v, "LIMIT+OFFSET"));
  		}
  	}
  }
  
  /**
   * This function determines resulting collation sequence for
   * @n-th column of the result set for the compound SELECT
   * statement. Since compound SELECT performs implicit comparisons
   * between values, all parts of compound queries must use
   * the same collation. Otherwise, an error is raised.
   *
   * @param parser Parse context.
   * @param p Select meta-information.
   * @param n Column number of the result set.
   * @param is_forced_coll Used if we fall into recursion.
   *        For most-outer call it is unused. Used to indicate that
   *        explicit COLLATE clause is used.
   * @retval Id of collation to be used during string comparison.
   */
  static uint32_t
  multi_select_coll_seq_r(struct Parse *parser, struct Select *p, int n,
  			bool *is_forced_coll)
  {
  	bool is_prior_forced = false;
  	bool is_current_forced;
  	uint32_t prior_coll_id = COLL_NONE;
  	uint32_t current_coll_id;
  	if (p->pPrior != NULL) {
  		prior_coll_id = multi_select_coll_seq_r(parser, p->pPrior, n,
  							&is_prior_forced);
  	}
  	/*
  	 * Column number must be less than p->pEList->nExpr.
  	 * Otherwise an error would have been thrown during name
  	 * resolution and we would not have got this far.
  	 */
  	assert(n >= 0 && n < p->pEList->nExpr);
  	struct coll *unused;
  	if (sql_expr_coll(parser, p->pEList->a[n].pExpr, &is_current_forced,
  			  &current_coll_id, &unused) != 0)
  		return 0;
  	uint32_t res_coll_id;
  	if (collations_check_compatibility(prior_coll_id, is_prior_forced,
  					   current_coll_id, is_current_forced,
  					   &res_coll_id) != 0) {
  		parser->is_aborted = true;
  		return 0;
  	}
  	*is_forced_coll = (is_prior_forced || is_current_forced);
  	return res_coll_id;
  }
  
  static inline uint32_t
  multi_select_coll_seq(struct Parse *parser, struct Select *p, int n)
  {
  	bool unused;
  	return multi_select_coll_seq_r(parser, p, n, &unused);
  }
  
  /**
   * The select statement passed as the second parameter is a
   * compound SELECT with an ORDER BY clause. This function
   * allocates and returns a sql_key_info structure suitable for
   * implementing the ORDER BY.
   *
   * Space to hold the sql_key_info structure is obtained from malloc.
   * The calling function is responsible for ensuring that this
   * structure is eventually freed.
   *
   * @param parse Parsing context.
   * @param s Select struct to analyze.
   * @param extra No of extra slots to allocate.
   *
   * @retval Allocated key_info, NULL in case of OOM.
   */
  static struct sql_key_info *
  sql_multiselect_orderby_to_key_info(struct Parse *parse, struct Select *s,
  				   int extra)
  {
  	int ob_count = s->pOrderBy->nExpr;
  	struct sql_key_info *key_info = sql_key_info_new(parse->db,
  							 ob_count + extra);
  	if (key_info == NULL) {
  		sqlOomFault(parse->db);
  		return NULL;
  	}
  
  	ExprList *order_by = s->pOrderBy;
  	for (int i = 0; i < ob_count; i++) {
  		struct key_part_def *part = &key_info->parts[i];
  		struct ExprList_item *item = &order_by->a[i];
  		struct Expr *term = item->pExpr;
  		uint32_t id;
  		bool unused;
  		if ((term->flags & EP_Collate) != 0) {
  			struct coll *unused_coll;
  			if (sql_expr_coll(parse, term, &unused, &id,
  					  &unused_coll) != 0)
  				return 0;
  		} else {
  			id = multi_select_coll_seq(parse, s,
  						   item->u.x.iOrderByCol - 1);
  			if (id != COLL_NONE) {
  				const char *name = coll_by_id(id)->name;
  				order_by->a[i].pExpr =
  					sqlExprAddCollateString(parse, term,
  								    name);
  			}
  		}
  		part->coll_id = id;
  		part->sort_order = order_by->a[i].sort_order;
  	}
  
  	return key_info;
  }
  
  /*
   * This routine generates VDBE code to compute the content of a WITH RECURSIVE
   * query of the form:
   *
   *   <recursive-table> AS (<setup-query> UNION [ALL] <recursive-query>)
   *                         \___________/             \_______________/
   *                           p->pPrior                      p
   *
   *
   * There is exactly one reference to the recursive-table in the FROM clause
   * of recursive-query, marked with the SrcList->a[].fg.isRecursive flag.
   *
   * The setup-query runs once to generate an initial set of rows that go
   * into a Queue table.  Rows are extracted from the Queue table one by
   * one.  Each row extracted from Queue is output to pDest.  Then the single
   * extracted row (now in the iCurrent table) becomes the content of the
   * recursive-table for a recursive-query run.  The output of the recursive-query
   * is added back into the Queue table.  Then another row is extracted from Queue
   * and the iteration continues until the Queue table is empty.
   *
   * If the compound query operator is UNION then no duplicate rows are ever
   * inserted into the Queue table.  The iDistinct table keeps a copy of all rows
   * that have ever been inserted into Queue and causes duplicates to be
   * discarded.  If the operator is UNION ALL, then duplicates are allowed.
   *
   * If the query has an ORDER BY, then entries in the Queue table are kept in
   * ORDER BY order and the first entry is extracted for each cycle.  Without
   * an ORDER BY, the Queue table is just a FIFO.
   *
   * If a LIMIT clause is provided, then the iteration stops after LIMIT rows
   * have been output to pDest.  A LIMIT of zero means to output no rows and a
   * negative LIMIT means to output all rows.  If there is also an OFFSET clause
   * with a positive value, then the first OFFSET outputs are discarded rather
   * than being sent to pDest.  The LIMIT count does not begin until after OFFSET
   * rows have been skipped.
   */
  static void
  generateWithRecursiveQuery(Parse * pParse,	/* Parsing context */
  			   Select * p,		/* The recursive SELECT to be coded */
  			   SelectDest * pDest)	/* What to do with query results */
  {
  	SrcList *pSrc = p->pSrc;	/* The FROM clause of the recursive query */
  	int nCol = p->pEList->nExpr;	/* Number of columns in the recursive table */
  	Vdbe *v = pParse->pVdbe;	/* The prepared statement under construction */
  	Select *pSetup = p->pPrior;	/* The setup query */
  	int addrTop;		/* Top of the loop */
  	int addrCont, addrBreak;	/* CONTINUE and BREAK addresses */
  	int iCurrent = 0;	/* The Current table */
  	int regCurrent;		/* Register holding Current table */
  	int iQueue;		/* The Queue table */
  	int iDistinct = 0;	/* To ensure unique results if UNION */
  	int eDest = SRT_Fifo;	/* How to write to Queue */
  	SelectDest destQueue;	/* SelectDest targetting the Queue table */
  	int i;			/* Loop counter */
  	int rc;			/* Result code */
  	ExprList *pOrderBy;	/* The ORDER BY clause */
  	Expr *pLimit, *pOffset;	/* Saved LIMIT and OFFSET */
  	int regLimit, regOffset;	/* Registers used by LIMIT and OFFSET */
  
  	/* Process the LIMIT and OFFSET clauses, if they exist */
  	addrBreak = sqlVdbeMakeLabel(v);
  	p->nSelectRow = 320;	/* 4 billion rows */
  	computeLimitRegisters(pParse, p, addrBreak);
  	pLimit = p->pLimit;
  	pOffset = p->pOffset;
  	regLimit = p->iLimit;
  	regOffset = p->iOffset;
  	p->pLimit = p->pOffset = 0;
  	p->iLimit = p->iOffset = 0;
  	pOrderBy = p->pOrderBy;
  
  	/* Locate the cursor number of the Current table */
  	for (i = 0; ALWAYS(i < pSrc->nSrc); i++) {
  		if (pSrc->a[i].fg.isRecursive) {
  			iCurrent = pSrc->a[i].iCursor;
  			break;
  		}
  	}
  
  	/* Allocate cursors numbers for Queue and Distinct.  The cursor number for
  	 * the Distinct table must be exactly one greater than Queue in order
  	 * for the SRT_DistFifo and SRT_DistQueue destinations to work.
  	 */
  	iQueue = pParse->nTab++;
  	int reg_queue = ++pParse->nMem;
  	int reg_dist = 0;
  	if (p->op == TK_UNION) {
  		eDest = pOrderBy ? SRT_DistQueue : SRT_DistFifo;
  		iDistinct = pParse->nTab++;
  		reg_dist = ++pParse->nMem;
  	} else {
  		eDest = pOrderBy ? SRT_Queue : SRT_Fifo;
  	}
  	sqlSelectDestInit(&destQueue, eDest, iQueue, reg_queue);
  
  	/* Allocate cursors for Current, Queue, and Distinct. */
  	regCurrent = ++pParse->nMem;
  	sqlVdbeAddOp3(v, OP_OpenPseudo, iCurrent, regCurrent, nCol);
  	if (pOrderBy) {
  		struct sql_key_info *key_info =
  			sql_multiselect_orderby_to_key_info(pParse, p, 1);
  		sqlVdbeAddOp4(v, OP_OpenTEphemeral, reg_queue,
  				  pOrderBy->nExpr + 2, 0, (char *)key_info,
  				  P4_KEYINFO);
  		VdbeComment((v, "Orderby table"));
  		destQueue.pOrderBy = pOrderBy;
  	} else {
  		sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_queue, nCol + 1);
  		VdbeComment((v, "Queue table"));
  	}
  	sqlVdbeAddOp3(v, OP_IteratorOpen, iQueue, 0, reg_queue);
  	if (iDistinct) {
  		p->addrOpenEphm[0] =
  		    sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_dist, 1);
  		sqlVdbeAddOp3(v, OP_IteratorOpen, iDistinct, 0, reg_dist);
  		p->selFlags |= SF_UsesEphemeral;
  		VdbeComment((v, "Distinct table"));
  	}
  
  	/* Detach the ORDER BY clause from the compound SELECT */
  	p->pOrderBy = 0;
  
  	/* Store the results of the setup-query in Queue. */
  	pSetup->pNext = 0;
  	rc = sqlSelect(pParse, pSetup, &destQueue);
  	pSetup->pNext = p;
  	if (rc)
  		goto end_of_recursive_query;
  
  	/* Find the next row in the Queue and output that row */
  	addrTop = sqlVdbeAddOp2(v, OP_Rewind, iQueue, addrBreak);
  	VdbeCoverage(v);
  
  	/* Transfer the next row in Queue over to Current */
  	sqlVdbeAddOp1(v, OP_NullRow, iCurrent);	/* To reset column cache */
  	if (pOrderBy) {
  		sqlVdbeAddOp3(v, OP_Column, iQueue, pOrderBy->nExpr + 1,
  				  regCurrent);
  	} else {
  		sqlVdbeAddOp2(v, OP_RowData, iQueue, regCurrent);
  	}
  	sqlVdbeAddOp1(v, OP_Delete, iQueue);
  
  	/* Output the single row in Current */
  	addrCont = sqlVdbeMakeLabel(v);
  	codeOffset(v, regOffset, addrCont);
  	selectInnerLoop(pParse, p, p->pEList, iCurrent,
  			0, 0, pDest, addrCont, addrBreak);
  	if (regLimit) {
  		sqlVdbeAddOp2(v, OP_DecrJumpZero, regLimit, addrBreak);
  		VdbeCoverage(v);
  	}
  	sqlVdbeResolveLabel(v, addrCont);
  
  	/* Execute the recursive SELECT taking the single row in Current as
  	 * the value for the recursive-table. Store the results in the Queue.
  	 */
  	if (p->selFlags & SF_Aggregate) {
  		diag_set(ClientError, ER_UNSUPPORTED, "Tarantool",
  			 "recursive aggregate queries");
  		pParse->is_aborted = true;
  	} else {
  		p->pPrior = 0;
  		sqlSelect(pParse, p, &destQueue);
  		assert(p->pPrior == 0);
  		p->pPrior = pSetup;
  	}
  
  	/* Keep running the loop until the Queue is empty */
  	sqlVdbeGoto(v, addrTop);
  	sqlVdbeResolveLabel(v, addrBreak);
  
   end_of_recursive_query:
  	sql_expr_list_delete(pParse->db, p->pOrderBy);
  	p->pOrderBy = pOrderBy;
  	p->pLimit = pLimit;
  	p->pOffset = pOffset;
  	return;
  }
  
  /* Forward references */
  static int multiSelectOrderBy(Parse * pParse,	/* Parsing context */
  			      Select * p,	/* The right-most of SELECTs to be coded */
  			      SelectDest * pDest	/* What to do with query results */
      );
  
  /**
   * Handle the special case of a compound-select that originates
   * from a VALUES clause.  By handling this as a special case, we
   * avoid deep recursion, and thus do not need to enforce the
   * SQL_LIMIT_COMPOUND_SELECT on a VALUES clause.
   *
   * Because the Select object originates from a VALUES clause:
   *   (1) It has no LIMIT or OFFSET
   *   (2) All terms are UNION ALL
   *   (3) There is no ORDER BY clause
   *
   * @param pParse Parsing context.
   * @param p The right-most of SELECTs to be coded.
   * @param pDest What to do with query results.
   * @retval 0 On success, not 0 elsewhere.
   */
  static int
  multiSelectValues(struct Parse *pParse, struct Select *p,
  		  struct SelectDest *pDest)
  {
  	Select *pPrior;
  	int nRow = 1;
  	int rc = 0;
  	assert(p->selFlags & SF_MultiValue);
  	do {
  		assert(p->selFlags & SF_Values);
  		assert(p->op == TK_ALL
  		       || (p->op == TK_SELECT && p->pPrior == 0));
  		assert(p->pLimit == 0);
  		assert(p->pOffset == 0);
  		assert(p->pNext == 0
  		       || p->pEList->nExpr == p->pNext->pEList->nExpr);
  		if (p->pPrior == 0)
  			break;
  		assert(p->pPrior->pNext == p);
  		p = p->pPrior;
  		nRow++;
  	} while (1);
  	while (p) {
  		pPrior = p->pPrior;
  		p->pPrior = 0;
  		rc = sqlSelect(pParse, p, pDest);
  		p->pPrior = pPrior;
  		if (rc)
  			break;
  		p->nSelectRow = nRow;
  		p = p->pNext;
  	}
  	return rc;
  }
  
  /*
   * This routine is called to process a compound query form from
   * two or more separate queries using UNION, UNION ALL, EXCEPT, or
   * INTERSECT
   *
   * "p" points to the right-most of the two queries.  the query on the
   * left is p->pPrior.  The left query could also be a compound query
   * in which case this routine will be called recursively.
   *
   * The results of the total query are to be written into a destination
   * of type eDest with parameter iParm.
   *
   * Example 1:  Consider a three-way compound SQL statement.
   *
   *     SELECT a FROM t1 UNION SELECT b FROM t2 UNION SELECT c FROM t3
   *
   * This statement is parsed up as follows:
   *
   *     SELECT c FROM t3
   *      |
   *      `----->  SELECT b FROM t2
   *                |
   *                `------>  SELECT a FROM t1
   *
   * The arrows in the diagram above represent the Select.pPrior pointer.
   * So if this routine is called with p equal to the t3 query, then
   * pPrior will be the t2 query.  p->op will be TK_UNION in this case.
   *
   * Notice that because of the way sql parses compound SELECTs, the
   * individual selects always group from left to right.
   */
  static int
  multiSelect(Parse * pParse,	/* Parsing context */
  	    Select * p,		/* The right-most of SELECTs to be coded */
  	    SelectDest * pDest)	/* What to do with query results */
  {
  	int rc = 0;	/* Success code from a subroutine */
  	Select *pPrior;		/* Another SELECT immediately to our left */
  	Vdbe *v;		/* Generate code to this VDBE */
  	SelectDest dest;	/* Alternative data destination */
  	Select *pDelete = 0;	/* Chain of simple selects to delete */
  	sql *db;		/* Database connection */
  	int iSub1 = 0;		/* EQP id of left-hand query */
  	int iSub2 = 0;		/* EQP id of right-hand query */
  
  	/* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs.  Only
  	 * the last (right-most) SELECT in the series may have an ORDER BY or LIMIT.
  	 */
  	assert(p && p->pPrior);	/* Calling function guarantees this much */
  	assert((p->selFlags & SF_Recursive) == 0 || p->op == TK_ALL
  	       || p->op == TK_UNION);
  	db = pParse->db;
  	pPrior = p->pPrior;
  	dest = *pDest;
  	if (pPrior->pOrderBy) {
  		const char *err_msg =
  			tt_sprintf("ORDER BY clause should come after %s not "\
  				   "before", sql_select_op_name(p->op));
  		diag_set(ClientError, ER_SQL_PARSER_GENERIC, err_msg);
  		pParse->is_aborted = true;
  		rc = 1;
  		goto multi_select_end;
  	}
  	if (pPrior->pLimit) {
  		const char *err_msg =
  			tt_sprintf("LIMIT clause should come after %s not "\
  				   "before", sql_select_op_name(p->op));
  		diag_set(ClientError, ER_SQL_PARSER_GENERIC, err_msg);
  		pParse->is_aborted = true;
  		rc = 1;
  		goto multi_select_end;
  	}
  
  	v = sqlGetVdbe(pParse);
  	assert(v != 0);		/* The VDBE already created by calling function */
  
  	/* Create the destination temporary table if necessary
  	 */
  	if (dest.eDest == SRT_EphemTab) {
  		assert(p->pEList);
  		int nCols = p->pEList->nExpr;
  		sqlVdbeAddOp2(v, OP_OpenTEphemeral, dest.reg_eph, nCols + 1);
  		sqlVdbeAddOp3(v, OP_IteratorOpen, dest.iSDParm, 0, dest.reg_eph);
  		VdbeComment((v, "Destination temp"));
  		dest.eDest = SRT_Table;
  	}
  
  	/* Special handling for a compound-select that originates as a VALUES clause.
  	 */
  	if (p->selFlags & SF_MultiValue) {
  		rc = multiSelectValues(pParse, p, &dest);
  		goto multi_select_end;
  	}
  
  	/* Make sure all SELECTs in the statement have the same number of elements
  	 * in their result sets.
  	 */
  	assert(p->pEList && pPrior->pEList);
  	assert(p->pEList->nExpr == pPrior->pEList->nExpr);
  
  	if (p->selFlags & SF_Recursive) {
  		generateWithRecursiveQuery(pParse, p, &dest);
  	} else
  
  		/* Compound SELECTs that have an ORDER BY clause are handled separately.
  		 */
  	if (p->pOrderBy) {
  		return multiSelectOrderBy(pParse, p, pDest);
  	} else
  		/* Generate code for the left and right SELECT statements.
  		 */
  		switch (p->op) {
  		case TK_ALL:{
  				int addr = 0;
  				int nLimit;
  				assert(!pPrior->pLimit);
  				pPrior->iLimit = p->iLimit;
  				pPrior->iOffset = p->iOffset;
  				pPrior->pLimit = p->pLimit;
  				pPrior->pOffset = p->pOffset;
  				iSub1 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, pPrior, &dest);
  				p->pLimit = 0;
  				p->pOffset = 0;
  				if (rc) {
  					goto multi_select_end;
  				}
  				p->pPrior = 0;
  				p->iLimit = pPrior->iLimit;
  				p->iOffset = pPrior->iOffset;
  				if (p->iLimit) {
  					int r1 = sqlGetTempReg(pParse);
  					sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  					addr = sqlVdbeAddOp3(v, OP_Eq, r1, 0,
  							     p->iLimit);
  					sqlReleaseTempReg(pParse, r1);
  					VdbeComment((v,
  						     "Jump ahead if LIMIT reached"));
  					if (p->iOffset) {
  						sqlVdbeAddOp3(v,
  								  OP_OffsetLimit,
  								  p->iLimit,
  								  p->iOffset +
  								  1,
  								  p->iOffset);
  					}
  				}
  				iSub2 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, p, &dest);
  				testcase(rc != 0);
  				pDelete = p->pPrior;
  				p->pPrior = pPrior;
  				p->nSelectRow =
  				    sqlLogEstAdd(p->nSelectRow,
  						     pPrior->nSelectRow);
  				if (pPrior->pLimit
  				    && sqlExprIsInteger(pPrior->pLimit,
  							    &nLimit)
  				    && nLimit > 0
  				    && p->nSelectRow > sqlLogEst((u64) nLimit)
  				    ) {
  					p->nSelectRow =
  					    sqlLogEst((u64) nLimit);
  				}
  				if (addr) {
  					sqlVdbeJumpHere(v, addr);
  				}
  				break;
  			}
  		case TK_EXCEPT:
  		case TK_UNION:{
  				int unionTab;	/* Cursor number of the temporary table holding result */
  				int reg_union;
  				u8 op = 0;	/* One of the SRT_ operations to apply to self */
  				int priorOp;	/* The SRT_ operation to apply to prior selects */
  				Expr *pLimit, *pOffset;	/* Saved values of p->nLimit and p->nOffset */
  				int addr;
  				SelectDest uniondest;
  
  				testcase(p->op == TK_EXCEPT);
  				testcase(p->op == TK_UNION);
  				priorOp = SRT_Union;
  				if (dest.eDest == priorOp) {
  					/* We can reuse a temporary table generated by a SELECT to our
  					 * right.
  					 */
  					assert(p->pLimit == 0);	/* Not allowed on leftward elements */
  					assert(p->pOffset == 0);	/* Not allowed on leftward elements */
  					unionTab = dest.iSDParm;
  					reg_union = dest.reg_eph;
  				} else {
  					/* We will need to create our own temporary table to hold the
  					 * intermediate results.
  					 */
  					unionTab = pParse->nTab++;
  					reg_union = ++pParse->nMem;
  					assert(p->pOrderBy == 0);
  					addr =
  					    sqlVdbeAddOp2(v,
  							      OP_OpenTEphemeral,
  							      reg_union, 0);
  					sqlVdbeAddOp3(v, OP_IteratorOpen, unionTab, 0, reg_union);
  					assert(p->addrOpenEphm[0] == -1);
  					p->addrOpenEphm[0] = addr;
  					findRightmost(p)->selFlags |=
  					    SF_UsesEphemeral;
  					assert(p->pEList);
  				}
  
  				/* Code the SELECT statements to our left
  				 */
  				assert(!pPrior->pOrderBy);
  				sqlSelectDestInit(&uniondest, priorOp,
  						      unionTab, reg_union);
  				iSub1 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, pPrior, &uniondest);
  				if (rc) {
  					goto multi_select_end;
  				}
  
  				/* Code the current SELECT statement
  				 */
  				if (p->op == TK_EXCEPT) {
  					op = SRT_Except;
  				} else {
  					assert(p->op == TK_UNION);
  					op = SRT_Union;
  				}
  				p->pPrior = 0;
  				pLimit = p->pLimit;
  				p->pLimit = 0;
  				pOffset = p->pOffset;
  				p->pOffset = 0;
  				uniondest.eDest = op;
  				iSub2 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, p, &uniondest);
  				testcase(rc != 0);
  				/* Query flattening in sqlSelect() might refill p->pOrderBy.
  				 * Be sure to delete p->pOrderBy, therefore, to avoid a memory leak.
  				 */
  				sql_expr_list_delete(db, p->pOrderBy);
  				pDelete = p->pPrior;
  				p->pPrior = pPrior;
  				p->pOrderBy = 0;
  				if (p->op == TK_UNION) {
  					p->nSelectRow =
  					    sqlLogEstAdd(p->nSelectRow,
  							     pPrior->
  							     nSelectRow);
  				}
  				sql_expr_delete(db, p->pLimit, false);
  				p->pLimit = pLimit;
  				p->pOffset = pOffset;
  				p->iLimit = 0;
  				p->iOffset = 0;
  
  				/* Convert the data in the temporary table into whatever form
  				 * it is that we currently need.
  				 */
  				assert(unionTab == dest.iSDParm
  				       || dest.eDest != priorOp);
  				if (dest.eDest != priorOp) {
  					int iCont, iBreak, iStart;
  					assert(p->pEList);
  					if (dest.eDest == SRT_Output) {
  						Select *pFirst = p;
  						while (pFirst->pPrior)
  							pFirst = pFirst->pPrior;
  						generateColumnNames(pParse,
  								    pFirst->pSrc,
  								    pFirst->pEList);
  					}
  					iBreak = sqlVdbeMakeLabel(v);
  					iCont = sqlVdbeMakeLabel(v);
  					computeLimitRegisters(pParse, p,
  							      iBreak);
  					sqlVdbeAddOp2(v, OP_Rewind,
  							  unionTab, iBreak);
  					VdbeCoverage(v);
  					iStart = sqlVdbeCurrentAddr(v);
  					selectInnerLoop(pParse, p, p->pEList,
  							unionTab, 0, 0, &dest,
  							iCont, iBreak);
  					sqlVdbeResolveLabel(v, iCont);
  					sqlVdbeAddOp2(v, OP_Next, unionTab,
  							  iStart);
  					VdbeCoverage(v);
  					sqlVdbeResolveLabel(v, iBreak);
  					sqlVdbeAddOp2(v, OP_Close, unionTab,
  							  0);
  				}
  				break;
  			}
  		default:
  			assert(p->op == TK_INTERSECT); {
  				int tab1, tab2;
  				int reg_eph1, reg_eph2;
  				int iCont, iBreak, iStart;
  				Expr *pLimit, *pOffset;
  				int addr;
  				SelectDest intersectdest;
  				int r1;
  
  				/* INTERSECT is different from the others since it requires
  				 * two temporary tables.  Hence it has its own case.  Begin
  				 * by allocating the tables we will need.
  				 */
  				tab1 = pParse->nTab++;
  				reg_eph1 = ++pParse->nMem;
  				tab2 = pParse->nTab++;
  				reg_eph2 = ++pParse->nMem;
  				assert(p->pOrderBy == 0);
  
  				addr =
  				    sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_eph1,
  						      0);
  				sqlVdbeAddOp3(v, OP_IteratorOpen, tab1, 0, reg_eph1);
  				assert(p->addrOpenEphm[0] == -1);
  				p->addrOpenEphm[0] = addr;
  				findRightmost(p)->selFlags |= SF_UsesEphemeral;
  				assert(p->pEList);
  
  				/* Code the SELECTs to our left into temporary table "tab1".
  				 */
  				sqlSelectDestInit(&intersectdest, SRT_Union,
  						      tab1, reg_eph1);
  				iSub1 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, pPrior,
  						   &intersectdest);
  				if (rc) {
  					goto multi_select_end;
  				}
  
  				/* Code the current SELECT into temporary table "tab2"
  				 */
  				addr =
  				    sqlVdbeAddOp2(v, OP_OpenTEphemeral, reg_eph2,
  						      0);
  				sqlVdbeAddOp3(v, OP_IteratorOpen, tab2, 0, reg_eph2);
  				assert(p->addrOpenEphm[1] == -1);
  				p->addrOpenEphm[1] = addr;
  				p->pPrior = 0;
  				pLimit = p->pLimit;
  				p->pLimit = 0;
  				pOffset = p->pOffset;
  				p->pOffset = 0;
  				intersectdest.iSDParm = tab2;
  				intersectdest.reg_eph = reg_eph2;
  				iSub2 = pParse->iNextSelectId;
  				rc = sqlSelect(pParse, p, &intersectdest);
  				testcase(rc != 0);
  				pDelete = p->pPrior;
  				p->pPrior = pPrior;
  				if (p->nSelectRow > pPrior->nSelectRow)
  					p->nSelectRow = pPrior->nSelectRow;
  				sql_expr_delete(db, p->pLimit, false);
  				p->pLimit = pLimit;
  				p->pOffset = pOffset;
  
  				/* Generate code to take the intersection of the two temporary
  				 * tables.
  				 */
  				assert(p->pEList);
  				if (dest.eDest == SRT_Output) {
  					Select *pFirst = p;
  					while (pFirst->pPrior)
  						pFirst = pFirst->pPrior;
  					generateColumnNames(pParse,
  							    pFirst->pSrc,
  							    pFirst->pEList);
  				}
  				iBreak = sqlVdbeMakeLabel(v);
  				iCont = sqlVdbeMakeLabel(v);
  				computeLimitRegisters(pParse, p, iBreak);
  				sqlVdbeAddOp2(v, OP_Rewind, tab1, iBreak);
  				VdbeCoverage(v);
  				r1 = sqlGetTempReg(pParse);
  				iStart =
  				    sqlVdbeAddOp2(v, OP_RowData, tab1, r1);
  				sqlVdbeAddOp4Int(v, OP_NotFound, tab2,
  						     iCont, r1, 0);
  				VdbeCoverage(v);
  				sqlReleaseTempReg(pParse, r1);
  				selectInnerLoop(pParse, p, p->pEList, tab1,
  						0, 0, &dest, iCont, iBreak);
  				sqlVdbeResolveLabel(v, iCont);
  				sqlVdbeAddOp2(v, OP_Next, tab1, iStart);
  				VdbeCoverage(v);
  				sqlVdbeResolveLabel(v, iBreak);
  				sqlVdbeAddOp2(v, OP_Close, tab2, 0);
  				sqlVdbeAddOp2(v, OP_Close, tab1, 0);
  				break;
  			}
  		}
  
  	explainComposite(pParse, p->op, iSub1, iSub2, p->op != TK_ALL);
  
  	/* Compute collating sequences used by
  	 * temporary tables needed to implement the compound select.
  	 * Attach the key_info structure to all temporary tables.
  	 *
  	 * This section is run by the right-most SELECT statement only.
  	 * SELECT statements to the left always skip this part.  The right-most
  	 * SELECT might also skip this part if it has no ORDER BY clause and
  	 * no temp tables are required.
  	 */
  	if (p->selFlags & SF_UsesEphemeral) {
  		assert(p->pNext == NULL);
  		int nCol = p->pEList->nExpr;
  		struct sql_key_info *key_info = sql_key_info_new(db, nCol);
  		if (key_info == NULL)
  			goto multi_select_end;
  		for (int i = 0; i < nCol; i++) {
  			key_info->parts[i].coll_id =
  				multi_select_coll_seq(pParse, p, i);
  		}
  
  		for (struct Select *pLoop = p; pLoop; pLoop = pLoop->pPrior) {
  			for (int i = 0; i < 2; i++) {
  				int addr = pLoop->addrOpenEphm[i];
  				if (addr < 0) {
  					/* If [0] is unused then [1] is also unused.  So we can
  					 * always safely abort as soon as the first unused slot is found
  					 */
  					assert(pLoop->addrOpenEphm[1] < 0);
  					break;
  				}
  				sqlVdbeChangeP2(v, addr, nCol);
  				sqlVdbeChangeP4(v, addr,
  						    (char *)sql_key_info_ref(key_info),
  						    P4_KEYINFO);
  				pLoop->addrOpenEphm[i] = -1;
  			}
  		}
  		sql_key_info_unref(key_info);
  	}
  
   multi_select_end:
  	pDest->iSdst = dest.iSdst;
  	pDest->nSdst = dest.nSdst;
  	sql_select_delete(db, pDelete);
  	return rc;
  }
  
  /**
   * Code an output subroutine for a coroutine implementation of a
   * SELECT statment.
   *
   * The data to be output is contained in pIn->iSdst.  There are
   * pIn->nSdst columns to be output.  pDest is where the output
   * should be sent.
   *
   * regReturn is the number of the register holding the subroutine
   * return address.
   *
   * If regPrev>0 then it is the first register in a vector that
   * records the previous output.  mem[regPrev] is a flag that is
   * false if there has been no previous output.  If regPrev>0 then
   * code is generated to suppress duplicates. key_info is used for
   * comparing keys.
   *
   * If the LIMIT found in p->iLimit is reached, jump immediately to
   * iBreak.
   *
   * @param parse Parsing context.
   * @param p The SELECT statement.
   * @param in Coroutine supplying data.
   * @param dest Where to send the data.
   * @param reg_ret The return address register.
   * @param reg_prev Previous result register.  No uniqueness if 0.
   * @param key_info For comparing with previous entry.
   * @param break_addr Jump here if we hit the LIMIT.
   *
   * @retval Address of generated routine.
   */
  static int
  generateOutputSubroutine(struct Parse *parse, struct Select *p,
  			 struct SelectDest *in, struct SelectDest *dest,
  			 int reg_ret, int reg_prev,
  			 struct sql_key_info *key_info,
  			 int break_addr)
  {
  	Vdbe *v = parse->pVdbe;
  	int iContinue;
  	int addr;
  
  	addr = sqlVdbeCurrentAddr(v);
  	iContinue = sqlVdbeMakeLabel(v);
  
  	/* Suppress duplicates for UNION, EXCEPT, and INTERSECT
  	 */
  	if (reg_prev) {
  		int addr1, addr2;
  		addr1 = sqlVdbeAddOp1(v, OP_IfNot, reg_prev);
  		VdbeCoverage(v);
  		addr2 =
  		    sqlVdbeAddOp4(v, OP_Compare, in->iSdst, reg_prev + 1,
  				      in->nSdst,
  				      (char *)sql_key_info_ref(key_info),
  				      P4_KEYINFO);
  		sqlVdbeAddOp3(v, OP_Jump, addr2 + 2, iContinue, addr2 + 2);
  		VdbeCoverage(v);
  		sqlVdbeJumpHere(v, addr1);
  		sqlVdbeAddOp3(v, OP_Copy, in->iSdst, reg_prev + 1,
  				  in->nSdst - 1);
  		sqlVdbeAddOp2(v, OP_Bool, true, reg_prev);
  	}
  	if (parse->db->mallocFailed)
  		return 0;
  
  	/* Suppress the first OFFSET entries if there is an OFFSET clause
  	 */
  	codeOffset(v, p->iOffset, iContinue);
  
  	assert(dest->eDest != SRT_Exists);
  	assert(dest->eDest != SRT_Table);
  	switch (dest->eDest) {
  		/* Store the result as data using a unique key.
  		 */
  	case SRT_EphemTab:{
  			int regRec = sqlGetTempReg(parse);
  			int regCopy = sqlGetTempRange(parse, in->nSdst + 1);
  			sqlVdbeAddOp2(v, OP_NextIdEphemeral, dest->reg_eph,
  					  regCopy + in->nSdst);
  			sqlVdbeAddOp3(v, OP_Copy, in->iSdst, regCopy,
  					  in->nSdst - 1);
  			sqlVdbeAddOp3(v, OP_MakeRecord, regCopy,
  					  in->nSdst + 1, regRec);
  			/* Set flag to save memory allocating one by malloc. */
  			sqlVdbeChangeP5(v, 1);
  			sqlVdbeAddOp2(v, OP_IdxInsert, regRec, dest->reg_eph);
  			sqlReleaseTempRange(parse, regCopy, in->nSdst + 1);
  			sqlReleaseTempReg(parse, regRec);
  			break;
  		}
  		/* If we are creating a set for an "expr IN (SELECT ...)".
  		 */
  	case SRT_Set:{
  			int r1;
  			testcase(in->nSdst > 1);
  			r1 = sqlGetTempReg(parse);
  			enum field_type *types =
  				field_type_sequence_dup(parse, dest->dest_type,
  							in->nSdst);
  			sqlVdbeAddOp4(v, OP_MakeRecord, in->iSdst,
  					  in->nSdst, r1, (char *)types,
  					  P4_DYNAMIC);
  			sql_expr_type_cache_change(parse, in->iSdst,
  						   in->nSdst);
  			sqlVdbeAddOp2(v, OP_IdxInsert, r1, dest->reg_eph);
  			sqlReleaseTempReg(parse, r1);
  			break;
  		}
  
  		/* If this is a scalar select that is part of an expression, then
  		 * store the results in the appropriate memory cell and break out
  		 * of the scan loop.
  		 */
  	case SRT_Mem:{
  			assert(in->nSdst == 1 || parse->is_aborted);
  			testcase(in->nSdst != 1);
  			sqlExprCodeMove(parse, in->iSdst, dest->iSDParm,
  					    1);
  			/* The LIMIT clause will jump out of the loop for us */
  			break;
  		}
  		/* The results are stored in a sequence of registers
  		 * starting at dest->iSdst.  Then the co-routine yields.
  		 */
  	case SRT_Coroutine:{
  			if (dest->iSdst == 0) {
  				dest->iSdst =
  				    sqlGetTempRange(parse, in->nSdst);
  				dest->nSdst = in->nSdst;
  			}
  			sqlExprCodeMove(parse, in->iSdst, dest->iSdst,
  					    in->nSdst);
  			sqlVdbeAddOp1(v, OP_Yield, dest->iSDParm);
  			break;
  		}
  
  		/* If none of the above, then the result destination must be
  		 * SRT_Output.  This routine is never called with any other
  		 * destination other than the ones handled above or SRT_Output.
  		 *
  		 * For SRT_Output, results are stored in a sequence of registers.
  		 * Then the OP_ResultRow opcode is used to cause sql_step() to
  		 * return the next row of result.
  		 */
  	default:{
  			assert(dest->eDest == SRT_Output);
  			sqlVdbeAddOp2(v, OP_ResultRow, in->iSdst,
  					  in->nSdst);
  			sql_expr_type_cache_change(parse, in->iSdst, in->nSdst);
  			break;
  		}
  	}
  
  	/* Jump to the end of the loop if the LIMIT is reached.
  	 */
  	if (p->iLimit) {
  		sqlVdbeAddOp2(v, OP_DecrJumpZero, p->iLimit, break_addr);
  		VdbeCoverage(v);
  	}
  
  	/* Generate the subroutine return
  	 */
  	sqlVdbeResolveLabel(v, iContinue);
  	sqlVdbeAddOp1(v, OP_Return, reg_ret);
  
  	return addr;
  }
  
  /*
   * Alternative compound select code generator for cases when there
   * is an ORDER BY clause.
   *
   * We assume a query of the following form:
   *
   *      <selectA>  <operator>  <selectB>  ORDER BY <orderbylist>
   *
   * <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT.  The idea
   * is to code both <selectA> and <selectB> with the ORDER BY clause as
   * co-routines.  Then run the co-routines in parallel and merge the results
   * into the output.  In addition to the two coroutines (called selectA and
   * selectB) there are 7 subroutines:
   *
   *    outA:    Move the output of the selectA coroutine into the output
   *             of the compound query.
   *
   *    outB:    Move the output of the selectB coroutine into the output
   *             of the compound query.  (Only generated for UNION and
   *             UNION ALL.  EXCEPT and INSERTSECT never output a row that
   *             appears only in B.)
   *
   *    AltB:    Called when there is data from both coroutines and A<B.
   *
   *    AeqB:    Called when there is data from both coroutines and A==B.
   *
   *    AgtB:    Called when there is data from both coroutines and A>B.
   *
   *    EofA:    Called when data is exhausted from selectA.
   *
   *    EofB:    Called when data is exhausted from selectB.
   *
   * The implementation of the latter five subroutines depend on which
   * <operator> is used:
   *
   *
   *             UNION ALL         UNION            EXCEPT          INTERSECT
   *          -------------  -----------------  --------------  -----------------
   *   AltB:   outA, nextA      outA, nextA       outA, nextA         nextA
   *
   *   AeqB:   outA, nextA         nextA             nextA         outA, nextA
   *
   *   AgtB:   outB, nextB      outB, nextB          nextB            nextB
   *
   *   EofA:   outB, nextB      outB, nextB          halt             halt
   *
   *   EofB:   outA, nextA      outA, nextA       outA, nextA         halt
   *
   * In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA
   * causes an immediate jump to EofA and an EOF on B following nextB causes
   * an immediate jump to EofB.  Within EofA and EofB, and EOF on entry or
   * following nextX causes a jump to the end of the select processing.
   *
   * Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled
   * within the output subroutine.  The regPrev register set holds the previously
   * output value.  A comparison is made against this value and the output
   * is skipped if the next results would be the same as the previous.
   *
   * The implementation plan is to implement the two coroutines and seven
   * subroutines first, then put the control logic at the bottom.  Like this:
   *
   *          goto Init
   *     coA: coroutine for left query (A)
   *     coB: coroutine for right query (B)
   *    outA: output one row of A
   *    outB: output one row of B (UNION and UNION ALL only)
   *    EofA: ...
   *    EofB: ...
   *    AltB: ...
   *    AeqB: ...
   *    AgtB: ...
   *    Init: initialize coroutine registers
   *          yield coA
   *          if eof(A) goto EofA
   *          yield coB
   *          if eof(B) goto EofB
   *    Cmpr: Compare A, B
   *          Jump AltB, AeqB, AgtB
   *     End: ...
   *
   * We call AltB, AeqB, AgtB, EofA, and EofB "subroutines" but they are not
   * actually called using Gosub and they do not Return.  EofA and EofB loop
   * until all data is exhausted then jump to the "end" labe.  AltB, AeqB,
   * and AgtB jump to either L2 or to one of EofA or EofB.
   */
  static int
  multiSelectOrderBy(Parse * pParse,	/* Parsing context */
  		   Select * p,		/* The right-most of SELECTs to be coded */
  		   SelectDest * pDest)	/* What to do with query results */
  {
  	int i, j;		/* Loop counters */
  	Select *pPrior;		/* Another SELECT immediately to our left */
  	Vdbe *v;		/* Generate code to this VDBE */
  	SelectDest destA;	/* Destination for coroutine A */
  	SelectDest destB;	/* Destination for coroutine B */
  	int regAddrA;		/* Address register for select-A coroutine */
  	int regAddrB;		/* Address register for select-B coroutine */
  	int addrSelectA;	/* Address of the select-A coroutine */
  	int addrSelectB;	/* Address of the select-B coroutine */
  	int regOutA;		/* Address register for the output-A subroutine */
  	int regOutB;		/* Address register for the output-B subroutine */
  	int addrOutA;		/* Address of the output-A subroutine */
  	int addrOutB = 0;	/* Address of the output-B subroutine */
  	int addrEofA;		/* Address of the select-A-exhausted subroutine */
  	int addrEofA_noB;	/* Alternate addrEofA if B is uninitialized */
  	int addrEofB;		/* Address of the select-B-exhausted subroutine */
  	int addrAltB;		/* Address of the A<B subroutine */
  	int addrAeqB;		/* Address of the A==B subroutine */
  	int addrAgtB;		/* Address of the A>B subroutine */
  	int regLimitA;		/* Limit register for select-A */
  	int regLimitB;		/* Limit register for select-A */
  	int regPrev;		/* A range of registers to hold previous output */
  	int savedLimit;		/* Saved value of p->iLimit */
  	int savedOffset;	/* Saved value of p->iOffset */
  	int labelCmpr;		/* Label for the start of the merge algorithm */
  	int labelEnd;		/* Label for the end of the overall SELECT stmt */
  	int addr1;		/* Jump instructions that get retargetted */
  	int op;			/* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */
  	/* Comparison information for duplicate removal */
  	struct sql_key_info *key_info_dup = NULL;
  	/* Comparison information for merging rows */
  	struct sql_key_info *key_info_merge;
  	sql *db;		/* Database connection */
  	ExprList *pOrderBy;	/* The ORDER BY clause */
  	int nOrderBy;		/* Number of terms in the ORDER BY clause */
  	int *aPermute;		/* Mapping from ORDER BY terms to result set columns */
  	int iSub1;		/* EQP id of left-hand query */
  	int iSub2;		/* EQP id of right-hand query */
  
  	assert(p->pOrderBy != 0);
  	db = pParse->db;
  	v = pParse->pVdbe;
  	assert(v != 0);		/* Already thrown the error if VDBE alloc failed */
  	labelEnd = sqlVdbeMakeLabel(v);
  	labelCmpr = sqlVdbeMakeLabel(v);
  
  	/* Patch up the ORDER BY clause
  	 */
  	op = p->op;
  	pPrior = p->pPrior;
  	assert(pPrior->pOrderBy == 0);
  	pOrderBy = p->pOrderBy;
  	assert(pOrderBy);
  	nOrderBy = pOrderBy->nExpr;
  
  	/* For operators other than UNION ALL we have to make sure that
  	 * the ORDER BY clause covers every term of the result set.  Add
  	 * terms to the ORDER BY clause as necessary.
  	 */
  	if (op != TK_ALL) {
  		for (i = 1; db->mallocFailed == 0 && i <= p->pEList->nExpr; i++) {
  			struct ExprList_item *pItem;
  			for (j = 0, pItem = pOrderBy->a; j < nOrderBy;
  			     j++, pItem++) {
  				assert(pItem->u.x.iOrderByCol > 0);
  				if (pItem->u.x.iOrderByCol == i)
  					break;
  			}
  			if (j == nOrderBy) {
  				struct Expr *pNew =
  					sql_expr_new_anon(db, TK_INTEGER);
  				if (pNew == NULL) {
  					pParse->is_aborted = true;
  					return 1;
  				}
  				pNew->flags |= EP_IntValue;
  				pNew->u.iValue = i;
  				pOrderBy = sql_expr_list_append(pParse->db,
  								pOrderBy, pNew);
  				if (pOrderBy)
  					pOrderBy->a[nOrderBy++].u.x.
  					    iOrderByCol = (u16) i;
  			}
  		}
  	}
  
  	/* Compute the comparison permutation and key_info that is used with
  	 * the permutation used to determine if the next
  	 * row of results comes from selectA or selectB.  Also add explicit
  	 * collations to the ORDER BY clause terms so that when the subqueries
  	 * to the right and the left are evaluated, they use the correct
  	 * collation.
  	 */
  	aPermute = sqlDbMallocRawNN(db, sizeof(int) * (nOrderBy + 1));
  	if (aPermute) {
  		struct ExprList_item *pItem;
  		aPermute[0] = nOrderBy;
  		for (i = 1, pItem = pOrderBy->a; i <= nOrderBy; i++, pItem++) {
  			assert(pItem->u.x.iOrderByCol > 0);
  			assert(pItem->u.x.iOrderByCol <= p->pEList->nExpr);
  			aPermute[i] = pItem->u.x.iOrderByCol - 1;
  		}
  		key_info_merge = sql_multiselect_orderby_to_key_info(pParse,
  								     p, 1);
  	} else {
  		key_info_merge = NULL;
  	}
  
  	/* Reattach the ORDER BY clause to the query.
  	 */
  	p->pOrderBy = pOrderBy;
  	pPrior->pOrderBy = sql_expr_list_dup(pParse->db, pOrderBy, 0);
  
  	/* Allocate a range of temporary registers and the key_info needed
  	 * for the logic that removes duplicate result rows when the
  	 * operator is UNION, EXCEPT, or INTERSECT (but not UNION ALL).
  	 */
  	if (op == TK_ALL) {
  		regPrev = 0;
  	} else {
  		int expr_count = p->pEList->nExpr;
  		assert(nOrderBy >= expr_count || db->mallocFailed);
  		regPrev = pParse->nMem + 1;
  		pParse->nMem += expr_count + 1;
  		sqlVdbeAddOp2(v, OP_Bool, 0, regPrev);
  		key_info_dup = sql_key_info_new(db, expr_count);
  		if (key_info_dup != NULL) {
  			for (int i = 0; i < expr_count; i++) {
  				key_info_dup->parts[i].coll_id =
  					multi_select_coll_seq(pParse, p, i);
  			}
  		}
  	}
  
  	/* Separate the left and the right query from one another
  	 */
  	p->pPrior = 0;
  	pPrior->pNext = 0;
  	sqlResolveOrderGroupBy(pParse, p, p->pOrderBy, "ORDER");
  	if (pPrior->pPrior == 0) {
  		sqlResolveOrderGroupBy(pParse, pPrior, pPrior->pOrderBy,
  					   "ORDER");
  	}
  
  	/* Compute the limit registers */
  	computeLimitRegisters(pParse, p, labelEnd);
  	if (p->iLimit && op == TK_ALL) {
  		regLimitA = ++pParse->nMem;
  		regLimitB = ++pParse->nMem;
  		sqlVdbeAddOp2(v, OP_Copy,
  				  p->iOffset ? p->iOffset + 1 : p->iLimit,
  				  regLimitA);
  		sqlVdbeAddOp2(v, OP_Copy, regLimitA, regLimitB);
  	} else {
  		regLimitA = regLimitB = 0;
  	}
  	sql_expr_delete(db, p->pLimit, false);
  	p->pLimit = 0;
  	sql_expr_delete(db, p->pOffset, false);
  	p->pOffset = 0;
  
  	regAddrA = ++pParse->nMem;
  	regAddrB = ++pParse->nMem;
  	regOutA = ++pParse->nMem;
  	regOutB = ++pParse->nMem;
  	sqlSelectDestInit(&destA, SRT_Coroutine, regAddrA, -1);
  	sqlSelectDestInit(&destB, SRT_Coroutine, regAddrB, -1);
  
  	/* Generate a coroutine to evaluate the SELECT statement to the
  	 * left of the compound operator - the "A" select.
  	 */
  	addrSelectA = sqlVdbeCurrentAddr(v) + 1;
  	addr1 =
  	    sqlVdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA);
  	VdbeComment((v, "left SELECT"));
  	pPrior->iLimit = regLimitA;
  	iSub1 = pParse->iNextSelectId;
  	sqlSelect(pParse, pPrior, &destA);
  	sqlVdbeEndCoroutine(v, regAddrA);
  	sqlVdbeJumpHere(v, addr1);
  
  	/* Generate a coroutine to evaluate the SELECT statement on
  	 * the right - the "B" select
  	 */
  	addrSelectB = sqlVdbeCurrentAddr(v) + 1;
  	addr1 =
  	    sqlVdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB);
  	VdbeComment((v, "right SELECT"));
  	savedLimit = p->iLimit;
  	savedOffset = p->iOffset;
  	p->iLimit = regLimitB;
  	p->iOffset = 0;
  	iSub2 = pParse->iNextSelectId;
  	sqlSelect(pParse, p, &destB);
  	p->iLimit = savedLimit;
  	p->iOffset = savedOffset;
  	sqlVdbeEndCoroutine(v, regAddrB);
  
  	/* Generate a subroutine that outputs the current row of the A
  	 * select as the next output row of the compound select.
  	 */
  	VdbeNoopComment((v, "Output routine for A"));
  	addrOutA = generateOutputSubroutine(pParse,
  					    p, &destA, pDest, regOutA,
  					    regPrev, key_info_dup, labelEnd);
  
  	/* Generate a subroutine that outputs the current row of the B
  	 * select as the next output row of the compound select.
  	 */
  	if (op == TK_ALL || op == TK_UNION) {
  		VdbeNoopComment((v, "Output routine for B"));
  		addrOutB = generateOutputSubroutine(pParse,
  						    p, &destB, pDest, regOutB,
  						    regPrev, key_info_dup,
  						    labelEnd);
  	}
  
  	sql_key_info_unref(key_info_dup);
  
  	/* Generate a subroutine to run when the results from select A
  	 * are exhausted and only data in select B remains.
  	 */
  	if (op == TK_EXCEPT || op == TK_INTERSECT) {
  		addrEofA_noB = addrEofA = labelEnd;
  	} else {
  		VdbeNoopComment((v, "eof-A subroutine"));
  		addrEofA = sqlVdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
  		addrEofA_noB =
  		    sqlVdbeAddOp2(v, OP_Yield, regAddrB, labelEnd);
  		VdbeCoverage(v);
  		sqlVdbeGoto(v, addrEofA);
  		p->nSelectRow =
  		    sqlLogEstAdd(p->nSelectRow, pPrior->nSelectRow);
  	}
  
  	/* Generate a subroutine to run when the results from select B
  	 * are exhausted and only data in select A remains.
  	 */
  	if (op == TK_INTERSECT) {
  		addrEofB = addrEofA;
  		if (p->nSelectRow > pPrior->nSelectRow)
  			p->nSelectRow = pPrior->nSelectRow;
  	} else {
  		VdbeNoopComment((v, "eof-B subroutine"));
  		addrEofB = sqlVdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
  		sqlVdbeAddOp2(v, OP_Yield, regAddrA, labelEnd);
  		VdbeCoverage(v);
  		sqlVdbeGoto(v, addrEofB);
  	}
  
  	/* Generate code to handle the case of A<B
  	 */
  	VdbeNoopComment((v, "A-lt-B subroutine"));
  	addrAltB = sqlVdbeAddOp2(v, OP_Gosub, regOutA, addrOutA);
  	sqlVdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
  	VdbeCoverage(v);
  	sqlVdbeGoto(v, labelCmpr);
  
  	/* Generate code to handle the case of A==B
  	 */
  	if (op == TK_ALL) {
  		addrAeqB = addrAltB;
  	} else if (op == TK_INTERSECT) {
  		addrAeqB = addrAltB;
  		addrAltB++;
  	} else {
  		VdbeNoopComment((v, "A-eq-B subroutine"));
  		addrAeqB = sqlVdbeAddOp2(v, OP_Yield, regAddrA, addrEofA);
  		VdbeCoverage(v);
  		sqlVdbeGoto(v, labelCmpr);
  	}
  
  	/* Generate code to handle the case of A>B
  	 */
  	VdbeNoopComment((v, "A-gt-B subroutine"));
  	addrAgtB = sqlVdbeCurrentAddr(v);
  	if (op == TK_ALL || op == TK_UNION) {
  		sqlVdbeAddOp2(v, OP_Gosub, regOutB, addrOutB);
  	}
  	sqlVdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
  	VdbeCoverage(v);
  	sqlVdbeGoto(v, labelCmpr);
  
  	/* This code runs once to initialize everything.
  	 */
  	sqlVdbeJumpHere(v, addr1);
  	sqlVdbeAddOp2(v, OP_Yield, regAddrA, addrEofA_noB);
  	VdbeCoverage(v);
  	sqlVdbeAddOp2(v, OP_Yield, regAddrB, addrEofB);
  	VdbeCoverage(v);
  
  	/* Implement the main merge loop
  	 */
  	sqlVdbeResolveLabel(v, labelCmpr);
  	sqlVdbeAddOp4(v, OP_Permutation, 0, 0, 0, (char *)aPermute,
  			  P4_INTARRAY);
  	sqlVdbeAddOp4(v, OP_Compare, destA.iSdst, destB.iSdst, nOrderBy,
  			  (char *)key_info_merge, P4_KEYINFO);
  	sqlVdbeChangeP5(v, OPFLAG_PERMUTE);
  	sqlVdbeAddOp3(v, OP_Jump, addrAltB, addrAeqB, addrAgtB);
  	VdbeCoverage(v);
  
  	/* Jump to the this point in order to terminate the query.
  	 */
  	sqlVdbeResolveLabel(v, labelEnd);
  
  	/* Set the number of output columns
  	 */
  	if (pDest->eDest == SRT_Output) {
  		Select *pFirst = pPrior;
  		while (pFirst->pPrior)
  			pFirst = pFirst->pPrior;
  		generateColumnNames(pParse, pFirst->pSrc, pFirst->pEList);
  	}
  
  	/* Reassembly the compound query so that it will be freed correctly
  	 * by the calling function
  	 */
  	if (p->pPrior) {
  		sql_select_delete(db, p->pPrior);
  	}
  	p->pPrior = pPrior;
  	pPrior->pNext = p;
  
    /*** TBD:  Insert subroutine calls to close cursors on incomplete
    *** subqueries ***
    */
  	explainComposite(pParse, p->op, iSub1, iSub2, 0);
  	return pParse->is_aborted;
  }
  
  /* Forward Declarations */
  static void substExprList(Parse *, ExprList *, int, ExprList *);
  static void substSelect(Parse *, Select *, int, ExprList *, int);
  
  /*
   * Scan through the expression pExpr.  Replace every reference to
   * a column in table number iTable with a copy of the iColumn-th
   * entry in pEList.
   *
   * This routine is part of the flattening procedure.  A subquery
   * whose result set is defined by pEList appears as entry in the
   * FROM clause of a SELECT such that the VDBE cursor assigned to that
   * FORM clause entry is iTable.  This routine make the necessary
   * changes to pExpr so that it refers directly to the source table
   * of the subquery rather the result set of the subquery.
   */
  static Expr *
  substExpr(Parse * pParse,	/* Report errors here */
  	  Expr * pExpr,		/* Expr in which substitution occurs */
  	  int iTable,		/* Table to be substituted */
  	  ExprList * pEList)	/* Substitute expressions */
  {
  	sql *db = pParse->db;
  	if (pExpr == 0)
  		return 0;
  	if (pExpr->op == TK_COLUMN && pExpr->iTable == iTable) {
  		if (pExpr->iColumn < 0) {
  			pExpr->op = TK_NULL;
  		} else {
  			Expr *pNew;
  			Expr *pCopy = pEList->a[pExpr->iColumn].pExpr;
  			assert(pEList != 0 && pExpr->iColumn < pEList->nExpr);
  			assert(pExpr->pLeft == 0 && pExpr->pRight == 0);
  			if (sqlExprIsVector(pCopy)) {
  				assert((pCopy->flags & EP_xIsSelect) != 0);
  				int expr_count =
  					pCopy->x.pSelect->pEList->nExpr;
  				diag_set(ClientError, ER_SQL_COLUMN_COUNT,
  					 expr_count, 1);
  				pParse->is_aborted = true;
  			} else {
  				pNew = sqlExprDup(db, pCopy, 0);
  				if (pNew && (pExpr->flags & EP_FromJoin)) {
  					pNew->iRightJoinTable =
  					    pExpr->iRightJoinTable;
  					pNew->flags |= EP_FromJoin;
  				}
  				sql_expr_delete(db, pExpr, false);
  				pExpr = pNew;
  			}
  		}
  	} else {
  		pExpr->pLeft = substExpr(pParse, pExpr->pLeft, iTable, pEList);
  		pExpr->pRight =
  		    substExpr(pParse, pExpr->pRight, iTable, pEList);
  		if (ExprHasProperty(pExpr, EP_xIsSelect)) {
  			substSelect(pParse, pExpr->x.pSelect, iTable, pEList,
  				    1);
  		} else {
  			substExprList(pParse, pExpr->x.pList, iTable, pEList);
  		}
  	}
  	return pExpr;
  }
  
  static void
  substExprList(Parse * pParse,		/* Report errors here */
  	      ExprList * pList,		/* List to scan and in which to make substitutes */
  	      int iTable,		/* Table to be substituted */
  	      ExprList * pEList)	/* Substitute values */
  {
  	int i;
  	if (pList == 0)
  		return;
  	for (i = 0; i < pList->nExpr; i++) {
  		pList->a[i].pExpr =
  		    substExpr(pParse, pList->a[i].pExpr, iTable, pEList);
  	}
  }
  
  static void
  substSelect(Parse * pParse,	/* Report errors here */
  	    Select * p,		/* SELECT statement in which to make substitutions */
  	    int iTable,		/* Table to be replaced */
  	    ExprList * pEList,	/* Substitute values */
  	    int doPrior)	/* Do substitutes on p->pPrior too */
  {
  	SrcList *pSrc;
  	struct SrcList_item *pItem;
  	int i;
  	if (!p)
  		return;
  	do {
  		substExprList(pParse, p->pEList, iTable, pEList);
  		substExprList(pParse, p->pGroupBy, iTable, pEList);
  		substExprList(pParse, p->pOrderBy, iTable, pEList);
  		p->pHaving = substExpr(pParse, p->pHaving, iTable, pEList);
  		p->pWhere = substExpr(pParse, p->pWhere, iTable, pEList);
  		pSrc = p->pSrc;
  		assert(pSrc != 0);
  		for (i = pSrc->nSrc, pItem = pSrc->a; i > 0; i--, pItem++) {
  			substSelect(pParse, pItem->pSelect, iTable, pEList, 1);
  			if (pItem->fg.isTabFunc) {
  				substExprList(pParse, pItem->u1.pFuncArg,
  					      iTable, pEList);
  			}
  		}
  	} while (doPrior && (p = p->pPrior) != 0);
  }
  
  /*
   * This routine attempts to flatten subqueries as a performance optimization.
   * This routine returns 1 if it makes changes and 0 if no flattening occurs.
   *
   * To understand the concept of flattening, consider the following
   * query:
   *
   *     SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5
   *
   * The default way of implementing this query is to execute the
   * subquery first and store the results in a temporary table, then
   * run the outer query on that temporary table.  This requires two
   * passes over the data.  Furthermore, because the temporary table
   * has no indices, the WHERE clause on the outer query cannot be
   * optimized.
   *
   * This routine attempts to rewrite queries such as the above into
   * a single flat select, like this:
   *
   *     SELECT x+y AS a FROM t1 WHERE z<100 AND a>5
   *
   * The code generated for this simplification gives the same result
   * but only has to scan the data once.  And because indices might
   * exist on the table t1, a complete scan of the data might be
   * avoided.
   *
   * Flattening is only attempted if all of the following are true:
   *
   *   (1)  The subquery and the outer query do not both use aggregates.
   *
   *   (2)  The subquery is not an aggregate or (2a) the outer query is not a join
   *        and (2b) the outer query does not use subqueries other than the one
   *        FROM-clause subquery that is a candidate for flattening.  (2b is
   *        due to ticket [2f7170d73bf9abf80] from 2015-02-09.)
   *
   *   (3)  The subquery is not the right operand of a left outer join
   *        (Originally ticket #306.  Strengthened by ticket #3300)
   *
   *   (4)  The subquery is not DISTINCT.
   *
   *  (**)  At one point restrictions (4) and (5) defined a subset of DISTINCT
   *        sub-queries that were excluded from this optimization. Restriction
   *        (4) has since been expanded to exclude all DISTINCT subqueries.
   *
   *   (6)  The subquery does not use aggregates or the outer query is not
   *        DISTINCT.
   *
   *   (7)  The subquery has a FROM clause.  TODO:  For subqueries without
   *        A FROM clause, consider adding a FROM close with the special
   *        table sql_once that consists of a single row containing a
   *        single NULL.
   *
   *   (8)  The subquery does not use LIMIT or the outer query is not a join.
   *
   *   (9)  The subquery does not use LIMIT or the outer query does not use
   *        aggregates.
   *
   *  (**)  Restriction (10) was removed from the code on 2005-02-05 but we
   *        accidently carried the comment forward until 2014-09-15.  Original
   *        text: "The subquery does not use aggregates or the outer query
   *        does not use LIMIT."
   *
   *  (11)  The subquery and the outer query do not both have ORDER BY clauses.
   *
   *  (**)  Not implemented.  Subsumed into restriction (3).  Was previously
   *        a separate restriction deriving from ticket #350.
   *
   *  (13)  The subquery and outer query do not both use LIMIT.
   *
   *  (14)  The subquery does not use OFFSET.
   *
   *  (15)  The outer query is not part of a compound select or the
   *        subquery does not have a LIMIT clause.
   *        (See ticket #2339 and ticket [02a8e81d44]).
   *
   *  (16)  The outer query is not an aggregate or the subquery does
   *        not contain ORDER BY.  (Ticket #2942)  This used to not matter
   *        until we introduced the group_concat() function.
   *
   *  (17)  The sub-query is not a compound select, or it is a UNION ALL
   *        compound clause made up entirely of non-aggregate queries, and
   *        the parent query:
   *
   *          * is not itself part of a compound select,
   *          * is not an aggregate or DISTINCT query, and
   *          * is not a join
   *
   *        The parent and sub-query may contain WHERE clauses. Subject to
   *        rules (11), (13) and (14), they may also contain ORDER BY,
   *        LIMIT and OFFSET clauses.  The subquery cannot use any compound
   *        operator other than UNION ALL because all the other compound
   *        operators have an implied DISTINCT which is disallowed by
   *        restriction (4).
   *
   *        Also, each component of the sub-query must return the same number
   *        of result columns. This is actually a requirement for any compound
   *        SELECT statement, but all the code here does is make sure that no
   *        such (illegal) sub-query is flattened. The caller will detect the
   *        syntax error and return a detailed message.
   *
   *  (18)  If the sub-query is a compound select, then all terms of the
   *        ORDER by clause of the parent must be simple references to
   *        columns of the sub-query.
   *
   *  (19)  The subquery does not use LIMIT or the outer query does not
   *        have a WHERE clause.
   *
   *  (20)  If the sub-query is a compound select, then it must not use
   *        an ORDER BY clause.  Ticket #3773.  We could relax this constraint
   *        somewhat by saying that the terms of the ORDER BY clause must
   *        appear as unmodified result columns in the outer query.  But we
   *        have other optimizations in mind to deal with that case.
   *
   *  (21)  The subquery does not use LIMIT or the outer query is not
   *        DISTINCT.  (See ticket [752e1646fc]).
   *
   *  (22)  The subquery is not a recursive CTE.
   *
   *  (23)  The parent is not a recursive CTE, or the sub-query is not a
   *        compound query. This restriction is because transforming the
   *        parent to a compound query confuses the code that handles
   *        recursive queries in multiSelect().
   *
   *  (24)  The subquery is not an aggregate that uses the built-in min() or
   *        or max() functions.  (Without this restriction, a query like:
   *        "SELECT x FROM (SELECT max(y), x FROM t1)" would not necessarily
   *        return the value X for which Y was maximal.)
   *
   *
   * In this routine, the "p" parameter is a pointer to the outer query.
   * The subquery is p->pSrc->a[iFrom].  isAgg is true if the outer query
   * uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.
   *
   * If flattening is not attempted, this routine is a no-op and returns 0.
   * If flattening is attempted this routine returns 1.
   *
   * All of the expression analysis must occur on both the outer query and
   * the subquery before this routine runs.
   */
  static int
  flattenSubquery(Parse * pParse,		/* Parsing context */
  		Select * p,		/* The parent or outer SELECT statement */
  		int iFrom,		/* Index in p->pSrc->a[] of the inner subquery */
  		int isAgg,		/* True if outer SELECT uses aggregate functions */
  		int subqueryIsAgg)	/* True if the subquery uses aggregate functions */
  {
  	Select *pParent;	/* Current UNION ALL term of the other query */
  	Select *pSub;		/* The inner query or "subquery" */
  	Select *pSub1;		/* Pointer to the rightmost select in sub-query */
  	SrcList *pSrc;		/* The FROM clause of the outer query */
  	SrcList *pSubSrc;	/* The FROM clause of the subquery */
  	ExprList *pList;	/* The result set of the outer query */
  	int iParent;		/* VDBE cursor number of the pSub result set temp table */
  	int i;			/* Loop counter */
  	Expr *pWhere;		/* The WHERE clause */
  	struct SrcList_item *pSubitem;	/* The subquery */
  	sql *db = pParse->db;
  
  	/* Check to see if flattening is permitted.  Return 0 if not.
  	 */
  	assert(p != 0);
  	assert(p->pPrior == 0);	/* Unable to flatten compound queries */
  	if (OptimizationDisabled(db, SQL_QueryFlattener))
  		return 0;
  	pSrc = p->pSrc;
  	assert(pSrc && iFrom >= 0 && iFrom < pSrc->nSrc);
  	pSubitem = &pSrc->a[iFrom];
  	iParent = pSubitem->iCursor;
  	pSub = pSubitem->pSelect;
  	assert(pSub != 0);
  	if (subqueryIsAgg) {
  		if (isAgg)
  			return 0;	/* Restriction (1)   */
  		if (pSrc->nSrc > 1)
  			return 0;	/* Restriction (2a)  */
  		if ((p->pWhere && ExprHasProperty(p->pWhere, EP_Subquery))
  		    || (sqlExprListFlags(p->pEList) & EP_Subquery) != 0
  		    || (sqlExprListFlags(p->pOrderBy) & EP_Subquery) != 0) {
  			return 0;	/* Restriction (2b)  */
  		}
  	}
  
  	pSubSrc = pSub->pSrc;
  	assert(pSubSrc);
  	/* Prior to version 3.1.2, when LIMIT and OFFSET had to be simple constants,
  	 * not arbitrary expressions, we allowed some combining of LIMIT and OFFSET
  	 * because they could be computed at compile-time.  But when LIMIT and OFFSET
  	 * became arbitrary expressions, we were forced to add restrictions (13)
  	 * and (14).
  	 */
  	if (pSub->pLimit && p->pLimit)
  		return 0;	/* Restriction (13) */
  	if (pSub->pOffset)
  		return 0;	/* Restriction (14) */
  	if ((p->selFlags & SF_Compound) != 0 && pSub->pLimit) {
  		return 0;	/* Restriction (15) */
  	}
  	if (pSubSrc->nSrc == 0)
  		return 0;	/* Restriction (7)  */
  	if (pSub->selFlags & SF_Distinct)
  		return 0;	/* Restriction (5)  */
  	if (pSub->pLimit && (pSrc->nSrc > 1 || isAgg)) {
  		return 0;	/* Restrictions (8)(9) */
  	}
  	if ((p->selFlags & SF_Distinct) != 0 && subqueryIsAgg) {
  		return 0;	/* Restriction (6)  */
  	}
  	if (p->pOrderBy && pSub->pOrderBy) {
  		return 0;	/* Restriction (11) */
  	}
  	if (isAgg && pSub->pOrderBy)
  		return 0;	/* Restriction (16) */
  	if (pSub->pLimit && p->pWhere)
  		return 0;	/* Restriction (19) */
  	if (pSub->pLimit && (p->selFlags & SF_Distinct) != 0) {
  		return 0;	/* Restriction (21) */
  	}
  	testcase(pSub->selFlags & SF_Recursive);
  	testcase(pSub->selFlags & SF_MinMaxAgg);
  	if (pSub->selFlags & (SF_Recursive | SF_MinMaxAgg)) {
  		return 0;	/* Restrictions (22) and (24) */
  	}
  	if ((p->selFlags & SF_Recursive) && pSub->pPrior) {
  		return 0;	/* Restriction (23) */
  	}
  
  	/* OBSOLETE COMMENT 1:
  	 * Restriction 3:  If the subquery is a join, make sure the subquery is
  	 * not used as the right operand of an outer join.  Examples of why this
  	 * is not allowed:
  	 *
  	 *         t1 LEFT OUTER JOIN (t2 JOIN t3)
  	 *
  	 * If we flatten the above, we would get
  	 *
  	 *         (t1 LEFT OUTER JOIN t2) JOIN t3
  	 *
  	 * which is not at all the same thing.
  	 *
  	 * OBSOLETE COMMENT 2:
  	 * Restriction 12:  If the subquery is the right operand of a left outer
  	 * join, make sure the subquery has no WHERE clause.
  	 * An examples of why this is not allowed:
  	 *
  	 *         t1 LEFT OUTER JOIN (SELECT * FROM t2 WHERE t2.x>0)
  	 *
  	 * If we flatten the above, we would get
  	 *
  	 *         (t1 LEFT OUTER JOIN t2) WHERE t2.x>0
  	 *
  	 * But the t2.x>0 test will always fail on a NULL row of t2, which
  	 * effectively converts the OUTER JOIN into an INNER JOIN.
  	 *
  	 * THIS OVERRIDES OBSOLETE COMMENTS 1 AND 2 ABOVE:
  	 * Ticket #3300 shows that flattening the right term of a LEFT JOIN
  	 * is fraught with danger.  Best to avoid the whole thing.  If the
  	 * subquery is the right term of a LEFT JOIN, then do not flatten.
  	 */
  	if ((pSubitem->fg.jointype & JT_OUTER) != 0) {
  		return 0;
  	}
  
  	/* Restriction 17: If the sub-query is a compound SELECT, then it must
  	 * use only the UNION ALL operator. And none of the simple select queries
  	 * that make up the compound SELECT are allowed to be aggregate or distinct
  	 * queries.
  	 */
  	if (pSub->pPrior) {
  		if (isAgg || (p->selFlags & SF_Distinct) != 0
  		    || pSrc->nSrc != 1) {
  			return 0;
  		}
  		for (pSub1 = pSub; pSub1; pSub1 = pSub1->pPrior) {
  			/* Restriction 20 */
  			if (pSub1->pOrderBy != NULL)
  				return 0;
  			testcase((pSub1->
  				  selFlags & (SF_Distinct | SF_Aggregate)) ==
  				 SF_Distinct);
  			testcase((pSub1->
  				  selFlags & (SF_Distinct | SF_Aggregate)) ==
  				 SF_Aggregate);
  			assert(pSub->pSrc != 0);
  			assert(pSub->pEList->nExpr == pSub1->pEList->nExpr);
  			if ((pSub1->selFlags & (SF_Distinct | SF_Aggregate)) !=
  			    0 || (pSub1->pPrior && pSub1->op != TK_ALL)
  			    || pSub1->pSrc->nSrc < 1) {
  				return 0;
  			}
  			testcase(pSub1->pSrc->nSrc > 1);
  		}
  
  		/* Restriction 18. */
  		if (p->pOrderBy) {
  			int ii;
  			for (ii = 0; ii < p->pOrderBy->nExpr; ii++) {
  				if (p->pOrderBy->a[ii].u.x.iOrderByCol == 0)
  					return 0;
  			}
  		}
  	}
  
  	/***** If we reach this point, flattening is permitted. *****/
  	SELECTTRACE(1, pParse, p, ("flatten %s.%p from term %d\n",
  				   pSub->zSelName, pSub, iFrom));
  
  	/* If the sub-query is a compound SELECT statement, then (by restrictions
  	 * 17 and 18 above) it must be a UNION ALL and the parent query must
  	 * be of the form:
  	 *
  	 *     SELECT <expr-list> FROM (<sub-query>) <where-clause>
  	 *
  	 * followed by any ORDER BY, LIMIT and/or OFFSET clauses. This block
  	 * creates N-1 copies of the parent query without any ORDER BY, LIMIT or
  	 * OFFSET clauses and joins them to the left-hand-side of the original
  	 * using UNION ALL operators. In this case N is the number of simple
  	 * select statements in the compound sub-query.
  	 *
  	 * Example:
  	 *
  	 *     SELECT a+1 FROM (
  	 *        SELECT x FROM tab
  	 *        UNION ALL
  	 *        SELECT y FROM tab
  	 *        UNION ALL
  	 *        SELECT abs(z*2) FROM tab2
  	 *     ) WHERE a!=5 ORDER BY 1
  	 *
  	 * Transformed into:
  	 *
  	 *     SELECT x+1 FROM tab WHERE x+1!=5
  	 *     UNION ALL
  	 *     SELECT y+1 FROM tab WHERE y+1!=5
  	 *     UNION ALL
  	 *     SELECT abs(z*2)+1 FROM tab2 WHERE abs(z*2)+1!=5
  	 *     ORDER BY 1
  	 *
  	 * We call this the "compound-subquery flattening".
  	 */
  	for (pSub = pSub->pPrior; pSub; pSub = pSub->pPrior) {
  		Select *pNew;
  		ExprList *pOrderBy = p->pOrderBy;
  		Expr *pLimit = p->pLimit;
  		Expr *pOffset = p->pOffset;
  		Select *pPrior = p->pPrior;
  		p->pOrderBy = 0;
  		p->pSrc = 0;
  		p->pPrior = 0;
  		p->pLimit = 0;
  		p->pOffset = 0;
  		pNew = sqlSelectDup(db, p, 0);
  		sqlSelectSetName(pNew, pSub->zSelName);
  		p->pOffset = pOffset;
  		p->pLimit = pLimit;
  		p->pOrderBy = pOrderBy;
  		p->pSrc = pSrc;
  		p->op = TK_ALL;
  		if (pNew == 0) {
  			p->pPrior = pPrior;
  		} else {
  			pNew->pPrior = pPrior;
  			if (pPrior)
  				pPrior->pNext = pNew;
  			pNew->pNext = p;
  			p->pPrior = pNew;
  			SELECTTRACE(2, pParse, p,
  				    ("compound-subquery flattener creates %s.%p as peer\n",
  				     pNew->zSelName, pNew));
  		}
  		if (db->mallocFailed)
  			return 1;
  	}
  
  	/*
  	 * Begin flattening the iFrom-th entry of the FROM clause
  	 * in the outer query.
  	 */
  	pSub = pSub1 = pSubitem->pSelect;
  
  	/* Delete the transient table structure associated with the
  	 * subquery
  	 */
  	sqlDbFree(db, pSubitem->zName);
  	sqlDbFree(db, pSubitem->zAlias);
  	pSubitem->zName = 0;
  	pSubitem->zAlias = 0;
  	pSubitem->pSelect = 0;
  
  	/* Deletion of the pSubitem->space will be done when a corresponding
  	 * region will be freed.
  	 */
  
  	/* The following loop runs once for each term in a compound-subquery
  	 * flattening (as described above).  If we are doing a different kind
  	 * of flattening - a flattening other than a compound-subquery flattening -
  	 * then this loop only runs once.
  	 *
  	 * This loop moves all of the FROM elements of the subquery into the
  	 * the FROM clause of the outer query.  Before doing this, remember
  	 * the cursor number for the original outer query FROM element in
  	 * iParent.  The iParent cursor will never be used.  Subsequent code
  	 * will scan expressions looking for iParent references and replace
  	 * those references with expressions that resolve to the subquery FROM
  	 * elements we are now copying in.
  	 */
  	for (pParent = p; pParent;
  	     pParent = pParent->pPrior, pSub = pSub->pPrior) {
  		int nSubSrc;
  		u8 jointype = 0;
  		pSubSrc = pSub->pSrc;	/* FROM clause of subquery */
  		nSubSrc = pSubSrc->nSrc;	/* Number of terms in subquery FROM clause */
  		pSrc = pParent->pSrc;	/* FROM clause of the outer query */
  
  		if (pSrc) {
  			assert(pParent == p);	/* First time through the loop */
  			jointype = pSubitem->fg.jointype;
  		} else {
  			assert(pParent != p);	/* 2nd and subsequent times through the loop */
  			pSrc = pParent->pSrc =
  			    sql_src_list_append(db, 0, 0);
  			if (pSrc == NULL) {
  				pParse->is_aborted = true;
  				break;
  			}
  		}
  
  		/* The subquery uses a single slot of the FROM clause of the outer
  		 * query.  If the subquery has more than one element in its FROM clause,
  		 * then expand the outer query to make space for it to hold all elements
  		 * of the subquery.
  		 *
  		 * Example:
  		 *
  		 *    SELECT * FROM tabA, (SELECT * FROM sub1, sub2), tabB;
  		 *
  		 * The outer query has 3 slots in its FROM clause.  One slot of the
  		 * outer query (the middle slot) is used by the subquery.  The next
  		 * block of code will expand the outer query FROM clause to 4 slots.
  		 * The middle slot is expanded to two slots in order to make space
  		 * for the two elements in the FROM clause of the subquery.
  		 */
  		if (nSubSrc > 1) {
  			struct SrcList *new_list =
  				sql_src_list_enlarge(db, pSrc, nSubSrc - 1,
  						     iFrom + 1);
  			if (new_list == NULL) {
  				pParse->is_aborted = true;
  				break;
  			}
  			pParent->pSrc = pSrc = new_list;
  		}
  
  		/* Transfer the FROM clause terms from the subquery into the
  		 * outer query.
  		 */
  		for (i = 0; i < nSubSrc; i++) {
  			sqlIdListDelete(db, pSrc->a[i + iFrom].pUsing);
  			assert(pSrc->a[i + iFrom].fg.isTabFunc == 0);
  			pSrc->a[i + iFrom] = pSubSrc->a[i];
  			memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i]));
  		}
  		pSrc->a[iFrom].fg.jointype = jointype;
  
  		/* Now begin substituting subquery result set expressions for
  		 * references to the iParent in the outer query.
  		 *
  		 * Example:
  		 *
  		 *   SELECT a+5, b*10 FROM (SELECT x*3 AS a, y+10 AS b FROM t1) WHERE a>b;
  		 *   \                     \_____________ subquery __________/          /
  		 *    \_____________________ outer query ______________________________/
  		 *
  		 * We look at every expression in the outer query and every place we see
  		 * "a" we substitute "x*3" and every place we see "b" we substitute "y+10".
  		 */
  		pList = pParent->pEList;
  		for (i = 0; i < pList->nExpr; i++) {
  			if (pList->a[i].zName == 0) {
  				char *str = pList->a[i].zSpan;
  				int len = strlen(str);
  				char *name =
  					sql_normalized_name_db_new(db, str,
  								   len);
  				if (name == NULL)
  					pParse->is_aborted = true;
  				pList->a[i].zName = name;
  			}
  		}
  		if (pSub->pOrderBy) {
  			/* At this point, any non-zero iOrderByCol values indicate that the
  			 * ORDER BY column expression is identical to the iOrderByCol'th
  			 * expression returned by SELECT statement pSub. Since these values
  			 * do not necessarily correspond to columns in SELECT statement pParent,
  			 * zero them before transfering the ORDER BY clause.
  			 *
  			 * Not doing this may cause an error if a subsequent call to this
  			 * function attempts to flatten a compound sub-query into pParent
  			 * (the only way this can happen is if the compound sub-query is
  			 * currently part of pSub->pSrc). See ticket [d11a6e908f].
  			 */
  			ExprList *pOrderBy = pSub->pOrderBy;
  			for (i = 0; i < pOrderBy->nExpr; i++) {
  				pOrderBy->a[i].u.x.iOrderByCol = 0;
  			}
  			assert(pParent->pOrderBy == 0);
  			assert(pSub->pPrior == 0);
  			pParent->pOrderBy = pOrderBy;
  			pSub->pOrderBy = 0;
  		}
  		pWhere = sqlExprDup(db, pSub->pWhere, 0);
  		if (subqueryIsAgg) {
  			assert(pParent->pHaving == 0);
  			pParent->pHaving = pParent->pWhere;
  			pParent->pWhere = pWhere;
  			struct Expr *sub_having =
  				sqlExprDup(db, pSub->pHaving, 0);
  			if (sub_having != NULL || pParent->pHaving != NULL) {
  				pParent->pHaving =
  					sql_and_expr_new(db, sub_having,
  							 pParent->pHaving);
  				if (pParent->pHaving == NULL)
  					pParse->is_aborted = true;
  			}
  			assert(pParent->pGroupBy == 0);
  			pParent->pGroupBy =
  			    sql_expr_list_dup(db, pSub->pGroupBy, 0);
  		} else if (pWhere != NULL || pParent->pWhere != NULL) {
  			pParent->pWhere =
  				sql_and_expr_new(db, pWhere, pParent->pWhere);
  			if (pParent->pWhere == NULL)
  				pParse->is_aborted = true;
  		}
  		substSelect(pParse, pParent, iParent, pSub->pEList, 0);
  
  		/* The flattened query is distinct if either the inner or the
  		 * outer query is distinct.
  		 */
  		pParent->selFlags |= pSub->selFlags & SF_Distinct;
  
  		/*
  		 * SELECT ... FROM (SELECT ... LIMIT a OFFSET b) LIMIT x OFFSET y;
  		 *
  		 * One is tempted to try to add a and b to combine the limits.  But this
  		 * does not work if either limit is negative.
  		 */
  		if (pSub->pLimit) {
  			pParent->pLimit = pSub->pLimit;
  			pSub->pLimit = 0;
  		}
  	}
  
  	/* Finially, delete what is left of the subquery and return
  	 * success.
  	 */
  	sql_select_delete(db, pSub1);
  
  #ifdef SQL_DEBUG
  	if (sqlSelectTrace & 0x100) {
  		SELECTTRACE(0x100, pParse, p, ("After flattening:\n"));
  		sqlTreeViewSelect(0, p, 0);
  	}
  #endif
  
  	return 1;
  }
  
  /*
   * Make copies of relevant WHERE clause terms of the outer query into
   * the WHERE clause of subquery.  Example:
   *
   *    SELECT * FROM (SELECT a AS x, c-d AS y FROM t1) WHERE x=5 AND y=10;
   *
   * Transformed into:
   *
   *    SELECT * FROM (SELECT a AS x, c-d AS y FROM t1 WHERE a=5 AND c-d=10)
   *     WHERE x=5 AND y=10;
   *
   * The hope is that the terms added to the inner query will make it more
   * efficient.
   *
   * Do not attempt this optimization if:
   *
   *   (1) The inner query is an aggregate.  (In that case, we'd really want
   *       to copy the outer WHERE-clause terms onto the HAVING clause of the
   *       inner query.  But they probably won't help there so do not bother.)
   *
   *   (2) The inner query is the recursive part of a common table expression.
   *
   *   (3) The inner query has a LIMIT clause (since the changes to the WHERE
   *       close would change the meaning of the LIMIT).
   *
   *   (4) The inner query is the right operand of a LEFT JOIN.  (The caller
   *       enforces this restriction since this routine does not have enough
   *       information to know.)
   *
   *   (5) The WHERE clause expression originates in the ON or USING clause
   *       of a LEFT JOIN.
   *
   * Return 0 if no changes are made and non-zero if one or more WHERE clause
   * terms are duplicated into the subquery.
   */
  static int
  pushDownWhereTerms(Parse * pParse,	/* Parse context (for malloc() and error reporting) */
  		   Select * pSubq,	/* The subquery whose WHERE clause is to be augmented */
  		   Expr * pWhere,	/* The WHERE clause of the outer query */
  		   int iCursor)		/* Cursor number of the subquery */
  {
  	Expr *pNew;
  	int nChng = 0;
  	Select *pX;		/* For looping over compound SELECTs in pSubq */
  	if (pWhere == 0)
  		return 0;
  	for (pX = pSubq; pX; pX = pX->pPrior) {
  		if ((pX->selFlags & (SF_Aggregate | SF_Recursive)) != 0) {
  			testcase(pX->selFlags & SF_Aggregate);
  			testcase(pX->selFlags & SF_Recursive);
  			testcase(pX != pSubq);
  			return 0;	/* restrictions (1) and (2) */
  		}
  	}
  	if (pSubq->pLimit != 0) {
  		return 0;	/* restriction (3) */
  	}
  	while (pWhere->op == TK_AND) {
  		nChng +=
  		    pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor);
  		pWhere = pWhere->pLeft;
  	}
  	if (ExprHasProperty(pWhere, EP_FromJoin))
  		return 0;	/* restriction 5 */
  	if (sqlExprIsTableConstant(pWhere, iCursor)) {
  		nChng++;
  		while (pSubq) {
  			pNew = sqlExprDup(pParse->db, pWhere, 0);
  			pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
  			pSubq->pWhere = sql_and_expr_new(pParse->db,
  							 pSubq->pWhere, pNew);
  			if (pSubq->pWhere == NULL)
  				pParse->is_aborted = true;
  			pSubq = pSubq->pPrior;
  		}
  	}
  	return nChng;
  }
  
  /*
   * Based on the contents of the AggInfo structure indicated by the first
   * argument, this function checks if the following are true:
   *
   *    * the query contains just a single aggregate function,
   *    * the aggregate function is either min() or max(), and
   *    * the argument to the aggregate function is a column value.
   *
   * If all of the above are true, then WHERE_ORDERBY_MIN or WHERE_ORDERBY_MAX
   * is returned as appropriate. Also, *ppMinMax is set to point to the
   * list of arguments passed to the aggregate before returning.
   *
   * Or, if the conditions above are not met, *ppMinMax is set to 0 and
   * WHERE_ORDERBY_NORMAL is returned.
   */
  static u8
  minMaxQuery(AggInfo * pAggInfo, ExprList ** ppMinMax)
  {
  	int eRet = WHERE_ORDERBY_NORMAL;	/* Return value */
  
  	*ppMinMax = 0;
  	if (pAggInfo->nFunc == 1) {
  		Expr *pExpr = pAggInfo->aFunc[0].pExpr;	/* Aggregate function */
  		ExprList *pEList = pExpr->x.pList;	/* Arguments to agg function */
  
  		assert(pExpr->op == TK_AGG_FUNCTION);
  		if (pEList && pEList->nExpr == 1
  		    && pEList->a[0].pExpr->op == TK_AGG_COLUMN) {
  			const char *zFunc = pExpr->u.zToken;
  			if (sqlStrICmp(zFunc, "min") == 0) {
  				eRet = WHERE_ORDERBY_MIN;
  				*ppMinMax = pEList;
  			} else if (sqlStrICmp(zFunc, "max") == 0) {
  				eRet = WHERE_ORDERBY_MAX;
  				*ppMinMax = pEList;
  			}
  		}
  	}
  
  	assert(*ppMinMax == 0 || (*ppMinMax)->nExpr == 1);
  	return eRet;
  }
  
  /**
   * The second argument is the associated aggregate-info object.
   * This function tests if the SELECT is of the form:
   *
   *   SELECT count(*) FROM <tbl>
   *
   * where table is not a sub-select or view.
   *
   * @param select The select statement in form of aggregate query.
   * @param agg_info The associated aggregate-info object.
   * @retval Pointer to space representing the table,
   *         if the query matches this pattern. NULL otherwise.
   */
  static struct space*
  is_simple_count(struct Select *select, struct AggInfo *agg_info)
  {
  	assert(select->pGroupBy == NULL);
  	if (select->pWhere != NULL || select->pEList->nExpr != 1 ||
  	    select->pSrc->nSrc != 1 || select->pSrc->a[0].pSelect != NULL) {
  		return NULL;
  	}
  	struct space *space = select->pSrc->a[0].space;
  	assert(space != NULL && !space->def->opts.is_view);
  	struct Expr *expr = select->pEList->a[0].pExpr;
  	assert(expr != NULL);
  	if (expr->op != TK_AGG_FUNCTION)
  		return NULL;
  	if (NEVER(agg_info->nFunc == 0))
  		return NULL;
  	assert(agg_info->aFunc->func->def->language ==
  	       FUNC_LANGUAGE_SQL_BUILTIN);
  	if (sql_func_flag_is_set(agg_info->aFunc->func, SQL_FUNC_COUNT) ||
  	    (agg_info->aFunc->pExpr->x.pList != NULL &&
  	     agg_info->aFunc->pExpr->x.pList->nExpr > 0))
  		return NULL;
  	if (expr->flags & EP_Distinct)
  		return NULL;
  	return space;
  }
  
  /*
   * If the source-list item passed as an argument was augmented with an
   * INDEXED BY clause, then try to locate the specified index. If there
   * was such a clause and the named index cannot be found, return
   * -1 and set an error. Otherwise, populate
   * pFrom->pIndex and return 0.
   */
  int
  sqlIndexedByLookup(Parse * pParse, struct SrcList_item *pFrom)
  {
  	if (pFrom->space != NULL && pFrom->fg.isIndexedBy) {
  		struct space *space = pFrom->space;
  		char *zIndexedBy = pFrom->u1.zIndexedBy;
  		struct index *idx = NULL;
  		for (uint32_t i = 0; i < space->index_count; ++i) {
  			if (strcmp(space->index[i]->def->name,
  				   zIndexedBy) == 0) {
  				idx = space->index[i];
  				break;
  			}
  		}
  		if (idx == NULL) {
  			diag_set(ClientError, ER_NO_SUCH_INDEX_NAME,
  				 zIndexedBy, space->def->name);
  			pParse->is_aborted = true;
  			return -1;
  		}
  		pFrom->pIBIndex = idx->def;
  	}
  	return 0;
  }
  
  /*
   * Detect compound SELECT statements that use an ORDER BY clause with
   * an alternative collating sequence.
   *
   *    SELECT ... FROM t1 EXCEPT SELECT ... FROM t2 ORDER BY .. COLLATE ...
   *
   * These are rewritten as a subquery:
   *
   *    SELECT * FROM (SELECT ... FROM t1 EXCEPT SELECT ... FROM t2)
   *     ORDER BY ... COLLATE ...
   *
   * This transformation is necessary because the multiSelectOrderBy() routine
   * above that generates the code for a compound SELECT with an ORDER BY clause
   * uses a merge algorithm that requires the same collating sequence on the
   * result columns as on the ORDER BY clause.
   *
   * This transformation is only needed for EXCEPT, INTERSECT, and UNION.
   * The UNION ALL operator works fine with multiSelectOrderBy() even when
   * there are COLLATE terms in the ORDER BY.
   */
  static int
  convertCompoundSelectToSubquery(Walker * pWalker, Select * p)
  {
  	int i;
  	Select *pNew;
  	Select *pX;
  	sql *db;
  	struct ExprList_item *a;
  	SrcList *pNewSrc;
  	Parse *pParse;
  	Token dummy;
  
  	if (p->pPrior == 0)
  		return WRC_Continue;
  	if (p->pOrderBy == 0)
  		return WRC_Continue;
  	for (pX = p; pX && (pX->op == TK_ALL || pX->op == TK_SELECT);
  	     pX = pX->pPrior) {
  	}
  	if (pX == 0)
  		return WRC_Continue;
  	a = p->pOrderBy->a;
  	for (i = p->pOrderBy->nExpr - 1; i >= 0; i--) {
  		if (a[i].pExpr->flags & EP_Collate)
  			break;
  	}
  	if (i < 0)
  		return WRC_Continue;
  
  	/* If we reach this point, that means the transformation is required. */
  
  	pParse = pWalker->pParse;
  	db = pParse->db;
  	pNew = sqlDbMallocZero(db, sizeof(*pNew));
  	if (pNew == 0)
  		return WRC_Abort;
  	memset(&dummy, 0, sizeof(dummy));
  	pNewSrc =
  	    sqlSrcListAppendFromTerm(pParse, 0, 0, &dummy, pNew, 0, 0);
  	if (pNewSrc == 0)
  		return WRC_Abort;
  	*pNew = *p;
  	p->pSrc = pNewSrc;
  	struct Expr *expr = sql_expr_new_anon(db, TK_ASTERISK);
  	if (expr == NULL)
  		pParse->is_aborted = true;
  	p->pEList = sql_expr_list_append(pParse->db, NULL, expr);
  	p->op = TK_SELECT;
  	p->pWhere = 0;
  	pNew->pGroupBy = 0;
  	pNew->pHaving = 0;
  	pNew->pOrderBy = 0;
  	p->pPrior = 0;
  	p->pNext = 0;
  	p->pWith = 0;
  	p->selFlags &= ~SF_Compound;
  	assert((p->selFlags & SF_Converted) == 0);
  	p->selFlags |= SF_Converted;
  	assert(pNew->pPrior != 0);
  	pNew->pPrior->pNext = pNew;
  	pNew->pLimit = 0;
  	pNew->pOffset = 0;
  	return WRC_Continue;
  }
  
  /*
   * Argument pWith (which may be NULL) points to a linked list of nested
   * WITH contexts, from inner to outermost. If the table identified by
   * FROM clause element pItem is really a common-table-expression (CTE)
   * then return a pointer to the CTE definition for that table. Otherwise
   * return NULL.
   *
   * If a non-NULL value is returned, set *ppContext to point to the With
   * object that the returned CTE belongs to.
   */
  static struct Cte *
  searchWith(With * pWith,		/* Current innermost WITH clause */
  	   struct SrcList_item *pItem,	/* FROM clause element to resolve */
  	   With ** ppContext)		/* OUT: WITH clause return value belongs to */
  {
  	const char *zName;
  	if ((zName = pItem->zName) != 0) {
  		With *p;
  		for (p = pWith; p; p = p->pOuter) {
  			int i;
  			for (i = 0; i < p->nCte; i++) {
  				if (strcmp(zName, p->a[i].zName) == 0) {
  					*ppContext = p;
  					return &p->a[i];
  				}
  			}
  		}
  	}
  	return 0;
  }
  
  /* The code generator maintains a stack of active WITH clauses
   * with the inner-most WITH clause being at the top of the stack.
   *
   * This routine pushes the WITH clause passed as the second argument
   * onto the top of the stack. If argument bFree is true, then this
   * WITH clause will never be popped from the stack. In this case it
   * should be freed along with the Parse object. In other cases, when
   * bFree==0, the With object will be freed along with the SELECT
   * statement with which it is associated.
   */
  void
  sqlWithPush(Parse * pParse, With * pWith, u8 bFree)
  {
  	assert(bFree == 0 || (pParse->pWith == 0 && pParse->pWithToFree == 0));
  	if (pWith) {
  		assert(pParse->pWith != pWith);
  		pWith->pOuter = pParse->pWith;
  		pParse->pWith = pWith;
  		if (bFree)
  			pParse->pWithToFree = pWith;
  	}
  }
  
  /*
   * This function checks if argument pFrom refers to a CTE declared by
   * a WITH clause on the stack currently maintained by the parser. And,
   * if currently processing a CTE expression, if it is a recursive
   * reference to the current CTE.
   *
   * If pFrom falls into either of the two categories above, pFrom->space
   * and other fields are populated accordingly. The caller should check
   * (pFrom->space!=0) to determine whether or not a successful match
   * was found.
   *
   * Whether or not a match is found, 0 is returned if no error
   * occurs. If an error does occur, an error message is stored in the
   * parser and some error code other than 0 returned.
   */
  static int
  withExpand(Walker * pWalker, struct SrcList_item *pFrom)
  {
  	Parse *pParse = pWalker->pParse;
  	sql *db = pParse->db;
  	struct Cte *pCte;	/* Matched CTE (or NULL if no match) */
  	With *pWith;		/* WITH clause that pCte belongs to */
  
  	assert(pFrom->space == NULL);
  
  	pCte = searchWith(pParse->pWith, pFrom, &pWith);
  	if (pCte) {
  		ExprList *pEList;
  		Select *pSel;
  		Select *pLeft;	/* Left-most SELECT statement */
  		int bMayRecursive;	/* True if compound joined by UNION [ALL] */
  		With *pSavedWith;	/* Initial value of pParse->pWith */
  
  		/* If pCte->zCteErr is non-NULL at this point, then this is an illegal
  		 * recursive reference to CTE pCte. Leave an error in pParse and return
  		 * early. If pCte->zCteErr is NULL, then this is not a recursive reference.
  		 * In this case, proceed.
  		 */
  		if (pCte->zCteErr) {
  			diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  				 tt_sprintf(pCte->zCteErr, pCte->zName));
  			pParse->is_aborted = true;
  			return -1;
  		}
  		if (pFrom->fg.isTabFunc) {
  			const char *err = "'%s' is not a function";
  			diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  				 tt_sprintf(err, pFrom->zName));
  			pParse->is_aborted = true;
  			return -1;
  		}
  
  		assert(pFrom->space == NULL);
  		pFrom->space = sql_ephemeral_space_new(pParse, pCte->zName);
  		if (pFrom->space == NULL)
  			return WRC_Abort;
  		pFrom->pSelect = sqlSelectDup(db, pCte->pSelect, 0);
  		if (db->mallocFailed)
  			return -1;
  		assert(pFrom->pSelect);
  
  		/* Check if this is a recursive CTE. */
  		pSel = pFrom->pSelect;
  		bMayRecursive = (pSel->op == TK_ALL || pSel->op == TK_UNION);
  		uint32_t ref_counter = 0;
  		if (bMayRecursive) {
  			int i;
  			SrcList *pSrc = pFrom->pSelect->pSrc;
  			for (i = 0; i < pSrc->nSrc; i++) {
  				struct SrcList_item *pItem = &pSrc->a[i];
  				if (pItem->zName != 0
  				    && 0 == sqlStrICmp(pItem->zName,
  							   pCte->zName)
  				    ) {
  					pItem->space = pFrom->space;
  					pItem->fg.isRecursive = 1;
  					ref_counter++;
  					pSel->selFlags |= SF_Recursive;
  				}
  			}
  		}
  		if (ref_counter > 1) {
  			const char *err_msg =
  				tt_sprintf("multiple references to recursive "\
  					   "table: %s", pCte->zName);
  			diag_set(ClientError, ER_SQL_PARSER_GENERIC, err_msg);
  			pParse->is_aborted = true;
  			return -1;
  		}
  		assert(ref_counter == 0 ||
  			((pSel->selFlags & SF_Recursive) && ref_counter == 1));
  
  		pCte->zCteErr = "circular reference: %s";
  		pSavedWith = pParse->pWith;
  		pParse->pWith = pWith;
  		sqlWalkSelect(pWalker, bMayRecursive ? pSel->pPrior : pSel);
  		pParse->pWith = pWith;
  
  		for (pLeft = pSel; pLeft->pPrior; pLeft = pLeft->pPrior) ;
  		pEList = pLeft->pEList;
  		if (pCte->pCols) {
  			if (pEList && pEList->nExpr != pCte->pCols->nExpr) {
  				const char *err_msg =
  					tt_sprintf("table %s has %d values "\
  						   "for %d columns",
  						   pCte->zName, pEList->nExpr,
  						   pCte->pCols->nExpr);
  				diag_set(ClientError, ER_SQL_PARSER_GENERIC, err_msg);
  				pParse->is_aborted = true;
  				pParse->pWith = pSavedWith;
  				return -1;
  			}
  			pEList = pCte->pCols;
  		}
  
  		sqlColumnsFromExprList(pParse, pEList, pFrom->space->def);
  
  		if (bMayRecursive) {
  			if (pSel->selFlags & SF_Recursive) {
  				pCte->zCteErr =
  				    "multiple recursive references: %s";
  			} else {
  				pCte->zCteErr =
  				    "recursive reference in a subquery: %s";
  			}
  			sqlWalkSelect(pWalker, pSel);
  		}
  		pCte->zCteErr = 0;
  		pParse->pWith = pSavedWith;
  	}
  
  	return 0;
  }
  
  /*
   * If the SELECT passed as the second argument has an associated WITH
   * clause, pop it from the stack stored as part of the Parse object.
   *
   * This function is used as the xSelectCallback2() callback by
   * sqlSelectExpand() when walking a SELECT tree to resolve table
   * names and other FROM clause elements.
   */
  static void
  selectPopWith(Walker * pWalker, Select * p)
  {
  	Parse *pParse = pWalker->pParse;
  	With *pWith = findRightmost(p)->pWith;
  	if (pWith != 0) {
  		assert(pParse->pWith == pWith);
  		pParse->pWith = pWith->pOuter;
  	}
  }
  
  /*
   * This routine is a Walker callback for "expanding" a SELECT statement.
   * "Expanding" means to do the following:
   *
   *    (1)  Make sure VDBE cursor numbers have been assigned to every
   *         element of the FROM clause.
   *
   *    (2)  Fill in the pTabList->a[].pTab fields in the SrcList that
   *         defines FROM clause.  When views appear in the FROM clause,
   *         fill pTabList->a[].pSelect with a copy of the SELECT statement
   *         that implements the view.  A copy is made of the view's SELECT
   *         statement so that we can freely modify or delete that statement
   *         without worrying about messing up the persistent representation
   *         of the view.
   *
   *    (3)  Add terms to the WHERE clause to accommodate the NATURAL keyword
   *         on joins and the ON and USING clause of joins.
   *
   *    (4)  Scan the list of columns in the result set (pEList) looking
   *         for instances of the "*" operator or the TABLE.* operator.
   *         If found, expand each "*" to be every column in every table
   *         and TABLE.* to be every column in TABLE.
   *
   */
  static int
  selectExpander(Walker * pWalker, Select * p)
  {
  	Parse *pParse = pWalker->pParse;
  	int i, j, k;
  	SrcList *pTabList;
  	ExprList *pEList;
  	struct SrcList_item *pFrom;
  	sql *db = pParse->db;
  	Expr *pE, *pRight, *pExpr;
  	u16 selFlags = p->selFlags;
  
  	p->selFlags |= SF_Expanded;
  	if (db->mallocFailed) {
  		return WRC_Abort;
  	}
  	if (NEVER(p->pSrc == 0) || (selFlags & SF_Expanded) != 0) {
  		return WRC_Prune;
  	}
  	pTabList = p->pSrc;
  	pEList = p->pEList;
  	if (pWalker->xSelectCallback2 == selectPopWith) {
  		sqlWithPush(pParse, findRightmost(p)->pWith, 0);
  	}
  
  	/* Make sure cursor numbers have been assigned to all entries in
  	 * the FROM clause of the SELECT statement.
  	 */
  	sqlSrcListAssignCursors(pParse, pTabList);
  
  	/* Look up every table named in the FROM clause of the select.  If
  	 * an entry of the FROM clause is a subquery instead of a table or view,
  	 * then create a transient space structure to describe the subquery.
  	 */
  	for (i = 0, pFrom = pTabList->a; i < pTabList->nSrc; i++, pFrom++) {
  		assert(pFrom->fg.isRecursive == 0 || pFrom->space != NULL);
  		if (pFrom->fg.isRecursive)
  			continue;
  		assert(pFrom->space == NULL);
  
  		if (withExpand(pWalker, pFrom))
  			return WRC_Abort;
  		if (pFrom->space != NULL) {
  		} else
  
  		if (pFrom->zName == 0) {
  			Select *pSel = pFrom->pSelect;
  			/* A sub-query in the FROM clause of a SELECT */
  			assert(pSel != 0);
  			assert(pFrom->space == NULL);
  			if (sqlWalkSelect(pWalker, pSel))
  				return WRC_Abort;
  			/*
  			 * Will be overwritten with pointer as
  			 * unique identifier.
  			 */
  			const char *name = "sql_sq_DEADBEAFDEADBEAF";
  			struct space *space =
  				sql_ephemeral_space_new(sqlParseToplevel(pParse),
  							name);
  			if (space == NULL)
  				return WRC_Abort;
  			pFrom->space = space;
  			/*
  			 * Rewrite old name with correct pointer.
  			 */
  			name = tt_sprintf("sql_sq_%llX", (void *)space);
  			sprintf(space->def->name, "%s", name);
  			while (pSel->pPrior) {
  				pSel = pSel->pPrior;
  			}
  			sqlColumnsFromExprList(pParse, pSel->pEList,
  					       space->def);
  		} else {
  			/*
  			 * An ordinary table or view name in the
  			 * FROM clause.
  			 */
  			struct space *space = sql_lookup_space(pParse, pFrom);
  			if (space == NULL)
  				return WRC_Abort;
  			if (pFrom->fg.isTabFunc) {
  				const char *err =
  					tt_sprintf("'%s' is not a function",
  						   pFrom->zName);
  				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  					 err);
  				pParse->is_aborted = true;
  				return WRC_Abort;
  			}
  			if (space->def->opts.is_view) {
  				struct Select *select =
  					sql_view_compile(db, space->def->opts.sql);
  				if (select == NULL)
  					return WRC_Abort;
  				sqlSrcListAssignCursors(pParse,
  							    select->pSrc);
  				assert(pFrom->pSelect == 0);
  				pFrom->pSelect = select;
  				sqlSelectSetName(pFrom->pSelect,
  						 space->def->name);
  				sqlWalkSelect(pWalker, pFrom->pSelect);
  			}
  		}
  		/* Locate the index named by the INDEXED BY clause, if any. */
  		if (sqlIndexedByLookup(pParse, pFrom)) {
  			return WRC_Abort;
  		}
  	}
  
  	/* Process NATURAL keywords, and ON and USING clauses of joins.
  	 */
  	if (db->mallocFailed || sqlProcessJoin(pParse, p)) {
  		return WRC_Abort;
  	}
  
  	/* For every "*" that occurs in the column list, insert the names of
  	 * all columns in all tables.  And for every TABLE.* insert the names
  	 * of all columns in TABLE.  The parser inserted a special expression
  	 * with the TK_ASTERISK operator for each "*" that it found in the column
  	 * list.  The following code just has to locate the TK_ASTERISK
  	 * expressions and expand each one to the list of all columns in
  	 * all tables.
  	 *
  	 * The first loop just checks to see if there are any "*" operators
  	 * that need expanding.
  	 */
  	for (k = 0; k < pEList->nExpr; k++) {
  		pE = pEList->a[k].pExpr;
  		if (pE->op == TK_ASTERISK)
  			break;
  		assert(pE->op != TK_DOT || pE->pRight != 0);
  		assert(pE->op != TK_DOT
  		       || (pE->pLeft != 0 && pE->pLeft->op == TK_ID));
  		if (pE->op == TK_DOT && pE->pRight->op == TK_ASTERISK)
  			break;
  	}
  	if (k < pEList->nExpr) {
  		/*
  		 * If we get here it means the result set contains one or more "*"
  		 * operators that need to be expanded.  Loop through each expression
  		 * in the result set and expand them one by one.
  		 */
  		struct ExprList_item *a = pEList->a;
  		ExprList *pNew = 0;
  		uint32_t flags = pParse->sql_flags;
  		int longNames = (flags & SQL_FullColNames) != 0
  		    && (flags & SQL_ShortColNames) == 0;
  
  		for (k = 0; k < pEList->nExpr; k++) {
  			pE = a[k].pExpr;
  			pRight = pE->pRight;
  			assert(pE->op != TK_DOT || pRight != 0);
  			if (pE->op != TK_ASTERISK
  			    && (pE->op != TK_DOT || pRight->op != TK_ASTERISK)
  			    ) {
  				/* This particular expression does not need to be expanded.
  				 */
  				pNew = sql_expr_list_append(pParse->db, pNew,
  							    a[k].pExpr);
  				if (pNew != NULL) {
  					pNew->a[pNew->nExpr - 1].zName =
  					    a[k].zName;
  					pNew->a[pNew->nExpr - 1].zSpan =
  					    a[k].zSpan;
  					a[k].zName = 0;
  					a[k].zSpan = 0;
  				}
  				a[k].pExpr = 0;
  			} else {
  				/* This expression is a "*" or a "TABLE.*" and needs to be
  				 * expanded.
  				 */
  				int tableSeen = 0;	/* Set to 1 when TABLE matches */
  				char *zTName = 0;	/* text of name of TABLE */
  				if (pE->op == TK_DOT) {
  					assert(pE->pLeft != 0);
  					assert(!ExprHasProperty
  					       (pE->pLeft, EP_IntValue));
  					zTName = pE->pLeft->u.zToken;
  				}
  				for (i = 0, pFrom = pTabList->a;
  				     i < pTabList->nSrc; i++, pFrom++) {
  					struct space *space = pFrom->space;
  					Select *pSub = pFrom->pSelect;
  					char *zTabName = pFrom->zAlias;
  					if (zTabName == NULL)
  						zTabName = space->def->name;
  					if (db->mallocFailed)
  						break;
  					if (pSub == 0
  					    || (pSub->
  						selFlags & SF_NestedFrom) ==
  					    0) {
  						pSub = 0;
  						if (zTName != NULL
  						    && strcmp(zTName, zTabName)
  						    != 0) {
  							continue;
  						}
  					}
  					for (j = 0; j < (int)space->def->field_count; j++) {
  						char *zName = space->def->fields[j].name;
  						char *zColname;	/* The computed column name */
  						char *zToFree;	/* Malloced string that needs to be freed */
  						Token sColname;	/* Computed column name as a token */
  
  						assert(zName);
  						if (zTName && pSub
  						    && sqlMatchSpanName(pSub->pEList->a[j].zSpan,
  									    0,
  									    zTName) == 0) {
  							continue;
  						}
  						tableSeen = 1;
  
  						if (i > 0 && zTName == 0) {
  							if ((pFrom->fg.jointype & JT_NATURAL) != 0
  							    && tableAndColumnIndex(pTabList, i, zName, 0, 0)) {
  								/* In a NATURAL join, omit the join columns from the
  								 * table to the right of the join
  								 */
  								continue;
  							}
  							if (sqlIdListIndex(pFrom->pUsing, zName) >= 0) {
  								/* In a join with a USING clause, omit columns in the
  								 * using clause from the table on the right.
  								 */
  								continue;
  							}
  						}
  						pRight = sql_expr_new_named(db,
  								TK_ID, zName);
  						if (pRight == NULL)
  							pParse->is_aborted = true;
  						zColname = zName;
  						zToFree = 0;
  						if (longNames
  						    || pTabList->nSrc > 1) {
  							Expr *pLeft;
  							pLeft = sql_expr_new_named(
  									db,
  									TK_ID,
  									zTabName);
  							if (pLeft == NULL) {
  								pParse->
  								is_aborted = true;
  							}
  							pExpr =
  							    sqlPExpr(pParse,
  									 TK_DOT,
  									 pLeft,
  									 pRight);
  							if (longNames) {
  								zColname =
  								    sqlMPrintf
  								    (db,
  								     "%s.%s",
  								     zTabName,
  								     zName);
  								zToFree =
  								    zColname;
  							}
  						} else {
  							pExpr = pRight;
  						}
  						pNew = sql_expr_list_append(
  							pParse->db, pNew, pExpr);
  						sqlTokenInit(&sColname, zColname);
  						sqlExprListSetName(pParse,
  								       pNew,
  								       &sColname,
  								       0);
  						if (pNew != NULL
  						    && (p->
  							selFlags &
  							SF_NestedFrom) != 0) {
  							struct ExprList_item *pX
  							    =
  							    &pNew->a[pNew->
  								     nExpr - 1];
  							if (pSub) {
  								pX->zSpan = sqlDbStrDup(db,
  											    pSub->pEList->a[j].zSpan);
  								testcase(pX->zSpan == 0);
  							} else {
  								pX->zSpan = sqlMPrintf(db,
  											   "%s.%s",
  											   zTabName,
  											   zColname);
  								testcase(pX->zSpan == 0);
  							}
  							pX->bSpanIsTab = 1;
  						}
  						sqlDbFree(db, zToFree);
  					}
  				}
  				if (!tableSeen) {
  					if (zTName) {
  						diag_set(ClientError,
  							 ER_NO_SUCH_SPACE,
  							 zTName);
  					} else {
  						diag_set(ClientError,
  							 ER_SQL_SELECT_WILDCARD);
  					}
  					pParse->is_aborted = true;
  				}
  			}
  		}
  		sql_expr_list_delete(db, pEList);
  		p->pEList = pNew;
  	}
  #if SQL_MAX_COLUMN
  	if (p->pEList && p->pEList->nExpr > db->aLimit[SQL_LIMIT_COLUMN]) {
  		diag_set(ClientError, ER_SQL_PARSER_LIMIT, "The number of "\
  			 "columns in result set", p->pEList->nExpr,
  			 db->aLimit[SQL_LIMIT_COLUMN]);
  		pParse->is_aborted = true;
  		return WRC_Abort;
  	}
  #endif
  	return WRC_Continue;
  }
  
  /*
   * No-op routine for the parse-tree walker.
   *
   * When this routine is the Walker.xExprCallback then expression trees
   * are walked without any actions being taken at each node.  Presumably,
   * when this routine is used for Walker.xExprCallback then
   * Walker.xSelectCallback is set to do something useful for every
   * subquery in the parser tree.
   */
  int
  sqlExprWalkNoop(Walker * NotUsed, Expr * NotUsed2)
  {
  	UNUSED_PARAMETER2(NotUsed, NotUsed2);
  	return WRC_Continue;
  }
  
  /*
   * This routine "expands" a SELECT statement and all of its subqueries.
   * For additional information on what it means to "expand" a SELECT
   * statement, see the comment on the selectExpand worker callback above.
   *
   * Expanding a SELECT statement is the first step in processing a
   * SELECT statement.  The SELECT statement must be expanded before
   * name resolution is performed.
   *
   * If anything goes wrong, an error message is written into pParse.
   * The calling function can detect the problem by looking at pParse->is_aborted
   * and/or pParse->db->mallocFailed.
   */
  static void
  sqlSelectExpand(Parse * pParse, Select * pSelect)
  {
  	Walker w;
  	memset(&w, 0, sizeof(w));
  	w.xExprCallback = sqlExprWalkNoop;
  	w.pParse = pParse;
  	if (pParse->hasCompound) {
  		w.xSelectCallback = convertCompoundSelectToSubquery;
  		sqlWalkSelect(&w, pSelect);
  	}
  	w.xSelectCallback = selectExpander;
  	if ((pSelect->selFlags & SF_MultiValue) == 0) {
  		w.xSelectCallback2 = selectPopWith;
  	}
  	sqlWalkSelect(&w, pSelect);
  }
  
  /*
   * This is a Walker.xSelectCallback callback for the sqlSelectTypeInfo()
   * interface.
   *
   * For each FROM-clause subquery, add Column.zType and Column.zColl
   * information to the Table structure that represents the result set
   * of that subquery.
   *
   * The Table structure that represents the result set was constructed
   * by selectExpander() but the type and collation information was omitted
   * at that point because identifiers had not yet been resolved.  This
   * routine is called after identifier resolution.
   */
  static void
  selectAddSubqueryTypeInfo(Walker * pWalker, Select * p)
  {
  	Parse *pParse;
  	int i;
  	SrcList *pTabList;
  	struct SrcList_item *pFrom;
  
  	assert(p->selFlags & SF_Resolved);
  	assert((p->selFlags & SF_HasTypeInfo) == 0);
  	p->selFlags |= SF_HasTypeInfo;
  	pParse = pWalker->pParse;
  	pTabList = p->pSrc;
  	for (i = 0, pFrom = pTabList->a; i < pTabList->nSrc; i++, pFrom++) {
  		struct space *space = pFrom->space;
  		assert(space != NULL);
  		if (space->def->id == 0) {
  			/* A sub-query in the FROM clause of a SELECT */
  			Select *pSel = pFrom->pSelect;
  			if (pSel) {
  				while (pSel->pPrior)
  					pSel = pSel->pPrior;
  				sqlSelectAddColumnTypeAndCollation(pParse,
  								   space->def,
  							 	   pSel);
  			}
  		}
  	}
  }
  
  /*
   * This routine adds datatype and collating sequence information to
   * the Table structures of all FROM-clause subqueries in a
   * SELECT statement.
   *
   * Use this routine after name resolution.
   */
  static void
  sqlSelectAddTypeInfo(Parse * pParse, Select * pSelect)
  {
  	Walker w;
  	memset(&w, 0, sizeof(w));
  	w.xSelectCallback2 = selectAddSubqueryTypeInfo;
  	w.xExprCallback = sqlExprWalkNoop;
  	w.pParse = pParse;
  	sqlWalkSelect(&w, pSelect);
  }
  
  /*
   * This routine sets up a SELECT statement for processing.  The
   * following is accomplished:
   *
   *     *  VDBE Cursor numbers are assigned to all FROM-clause terms.
   *     *  Ephemeral Table objects are created for all FROM-clause subqueries.
   *     *  ON and USING clauses are shifted into WHERE statements
   *     *  Wildcards "*" and "TABLE.*" in result sets are expanded.
   *     *  Identifiers in expression are matched to tables.
   *
   * This routine acts recursively on all subqueries within the SELECT.
   */
  void
  sqlSelectPrep(Parse * pParse,	/* The parser context */
  		  Select * p,	/* The SELECT statement being coded. */
  		  NameContext * pOuterNC	/* Name context for container */
      )
  {
  	sql *db;
  	if (NEVER(p == 0))
  		return;
  	db = pParse->db;
  	if (db->mallocFailed)
  		return;
  	if (p->selFlags & SF_HasTypeInfo)
  		return;
  	sqlSelectExpand(pParse, p);
  	if (pParse->is_aborted || db->mallocFailed)
  		return;
  	sqlResolveSelectNames(pParse, p, pOuterNC);
  	if (pParse->is_aborted || db->mallocFailed)
  		return;
  	sqlSelectAddTypeInfo(pParse, p);
  }
  
  /*
   * Reset the aggregate accumulator.
   *
   * The aggregate accumulator is a set of memory cells that hold
   * intermediate results while calculating an aggregate.  This
   * routine generates code that stores NULLs in all of those memory
   * cells.
   */
  static void
  resetAccumulator(Parse * pParse, AggInfo * pAggInfo)
  {
  	Vdbe *v = pParse->pVdbe;
  	int i;
  	struct AggInfo_func *pFunc;
  	int nReg = pAggInfo->nFunc + pAggInfo->nColumn;
  	if (nReg == 0)
  		return;
  #ifdef SQL_DEBUG
  	/* Verify that all AggInfo registers are within the range specified by
  	 * AggInfo.mnReg..AggInfo.mxReg
  	 */
  	assert(nReg <= pAggInfo->mxReg - pAggInfo->mnReg + 1);
  	for (i = 0; i < pAggInfo->nColumn; i++) {
  		assert(pAggInfo->aCol[i].iMem >= pAggInfo->mnReg
  		       && pAggInfo->aCol[i].iMem <= pAggInfo->mxReg);
  	}
  	for (i = 0; i < pAggInfo->nFunc; i++) {
  		assert(pAggInfo->aFunc[i].iMem >= pAggInfo->mnReg
  		       && pAggInfo->aFunc[i].iMem <= pAggInfo->mxReg);
  	}
  #endif
  	sqlVdbeAddOp3(v, OP_Null, 0, pAggInfo->mnReg, pAggInfo->mxReg);
  	for (pFunc = pAggInfo->aFunc, i = 0; i < pAggInfo->nFunc; i++, pFunc++) {
  		if (pFunc->iDistinct >= 0) {
  			Expr *pE = pFunc->pExpr;
  			assert(!ExprHasProperty(pE, EP_xIsSelect));
  			if (pE->x.pList == 0 || pE->x.pList->nExpr != 1) {
  				diag_set(ClientError, ER_SQL_PARSER_GENERIC,
  					 "DISTINCT aggregates must have "\
  					 "exactly one argument");
  				pParse->is_aborted = true;
  				pFunc->iDistinct = -1;
  			} else {
  				struct sql_key_info *key_info =
  					sql_expr_list_to_key_info(pParse,
  								  pE->x.pList,
  								  0);
  				sqlVdbeAddOp4(v, OP_OpenTEphemeral,
  						  pFunc->reg_eph, 1, 0,
  						  (char *)key_info, P4_KEYINFO);
  				sqlVdbeAddOp3(v, OP_IteratorOpen,
  						  pFunc->iDistinct, 0, pFunc->reg_eph);
  			}
  		}
  	}
  }
  
  /*
   * Invoke the OP_AggFinalize opcode for every aggregate function
   * in the AggInfo structure.
   */
  static void
  finalizeAggFunctions(Parse * pParse, AggInfo * pAggInfo)
  {
  	Vdbe *v = pParse->pVdbe;
  	int i;
  	struct AggInfo_func *pF;
  	for (i = 0, pF = pAggInfo->aFunc; i < pAggInfo->nFunc; i++, pF++) {
  		ExprList *pList = pF->pExpr->x.pList;
  		assert(!ExprHasProperty(pF->pExpr, EP_xIsSelect));
  		sqlVdbeAddOp2(v, OP_AggFinal, pF->iMem,
  				  pList ? pList->nExpr : 0);
  		sqlVdbeAppendP4(v, pF->func, P4_FUNC);
  	}
  }
  
  /*
   * Update the accumulator memory cells for an aggregate based on
   * the current cursor position.
   */
  static void
  updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
  {
  	Vdbe *v = pParse->pVdbe;
  	int i;
  	int regHit = 0;
  	int addrHitTest = 0;
  	struct AggInfo_func *pF;
  	struct AggInfo_col *pC;
  
  	pAggInfo->directMode = 1;
  	for (i = 0, pF = pAggInfo->aFunc; i < pAggInfo->nFunc; i++, pF++) {
  		int nArg;
  		int addrNext = 0;
  		int regAgg;
  		ExprList *pList = pF->pExpr->x.pList;
  		assert(!ExprHasProperty(pF->pExpr, EP_xIsSelect));
  		if (pList) {
  			nArg = pList->nExpr;
  			regAgg = sqlGetTempRange(pParse, nArg);
  			sqlExprCodeExprList(pParse, pList, regAgg, 0,
  						SQL_ECEL_DUP);
  		} else {
  			nArg = 0;
  			regAgg = 0;
  		}
  		if (pF->iDistinct >= 0) {
  			addrNext = sqlVdbeMakeLabel(v);
  			testcase(nArg == 0);	/* Error condition */
  			testcase(nArg > 1);	/* Also an error */
  			vdbe_insert_distinct(pParse, pF->iDistinct, pF->reg_eph,
  					     addrNext, 1, regAgg);
  		}
  		if (sql_func_flag_is_set(pF->func, SQL_FUNC_NEEDCOLL)) {
  			struct coll *coll = NULL;
  			struct ExprList_item *pItem;
  			int j;
  			assert(pList != 0);	/* pList!=0 if pF->pFunc has NEEDCOLL */
  			bool unused;
  			uint32_t id;
  			for (j = 0, pItem = pList->a; coll == NULL && j < nArg;
  			     j++, pItem++) {
  				if (sql_expr_coll(pParse, pItem->pExpr,
  						  &unused, &id, &coll) != 0)
  					return;
  			}
  			if (regHit == 0 && pAggInfo->nAccumulator)
  				regHit = ++pParse->nMem;
  			sqlVdbeAddOp4(v, OP_CollSeq, regHit, 0, 0,
  					  (char *)coll, P4_COLLSEQ);
  		}
  		sqlVdbeAddOp3(v, OP_AggStep0, 0, regAgg, pF->iMem);
  		sqlVdbeAppendP4(v, pF->func, P4_FUNC);
  		sqlVdbeChangeP5(v, (u8) nArg);
  		sql_expr_type_cache_change(pParse, regAgg, nArg);
  		sqlReleaseTempRange(pParse, regAgg, nArg);
  		if (addrNext) {
  			sqlVdbeResolveLabel(v, addrNext);
  			sqlExprCacheClear(pParse);
  		}
  	}
  
  	/* Before populating the accumulator registers, clear the column cache.
  	 * Otherwise, if any of the required column values are already present
  	 * in registers, sqlExprCode() may use OP_SCopy to copy the value
  	 * to pC->iMem. But by the time the value is used, the original register
  	 * may have been used, invalidating the underlying buffer holding the
  	 * text or blob value. See ticket [883034dcb5].
  	 *
  	 * Another solution would be to change the OP_SCopy used to copy cached
  	 * values to an OP_Copy.
  	 */
  	if (regHit) {
  		addrHitTest = sqlVdbeAddOp1(v, OP_If, regHit);
  		VdbeCoverage(v);
  	}
  	sqlExprCacheClear(pParse);
  	for (i = 0, pC = pAggInfo->aCol; i < pAggInfo->nAccumulator; i++, pC++) {
  		sqlExprCode(pParse, pC->pExpr, pC->iMem);
  	}
  	pAggInfo->directMode = 0;
  	sqlExprCacheClear(pParse);
  	if (addrHitTest) {
  		sqlVdbeJumpHere(v, addrHitTest);
  	}
  }
  
  /**
   * Add a single OP_Explain instruction to the VDBE to explain
   * a simple count(*) query ("SELECT count(*) FROM <tab>").
   * For memtx engine count is a simple operation,
   * which takes O(1) complexity.
   *
   * @param parse_context Current parsing context.
   * @param table_name Name of table being queried.
   */
  static void
  explain_simple_count(struct Parse *parse_context, const char *table_name)
  {
  	if (parse_context->explain == 2) {
  		char *zEqp = sqlMPrintf(parse_context->db, "B+tree count %s",
  					    table_name);
  		sqlVdbeAddOp4(parse_context->pVdbe, OP_Explain,
  				  parse_context->iSelectId, 0, 0, zEqp,
  				  P4_DYNAMIC);
  	}
  }
  
  /**
   * Generate VDBE code that HALT program when subselect returned
   * more than one row (determined as LIMIT 1 overflow).
   * @param parser Current parsing context.
   * @param limit_reg LIMIT register.
   * @param end_mark mark to jump if select returned distinct one
   *                 row as expected.
   */
  static void
  vdbe_code_raise_on_multiple_rows(struct Parse *parser, int limit_reg, int end_mark)
  {
  	assert(limit_reg != 0);
  	struct Vdbe *v = sqlGetVdbe(parser);
  	assert(v != NULL);
  
  	int r1 = sqlGetTempReg(parser);
  	sqlVdbeAddOp2(v, OP_Integer, 0, r1);
  	sqlVdbeAddOp3(v, OP_Ne, r1, end_mark, limit_reg);
  	const char *error = tt_sprintf(tnt_errcode_desc(ER_SQL_EXECUTE),
  				       "Expression subquery returned more "\
  				       "than 1 row");
  	sqlVdbeAddOp4(v, OP_SetDiag, ER_SQL_EXECUTE, 0, 0, error, P4_STATIC);
  	sqlVdbeAddOp1(v, OP_Halt, -1);
  	sqlReleaseTempReg(parser, r1);
  }
  
  /*
   * Generate code for the SELECT statement given in the p argument.
   *
   * The results are returned according to the SelectDest structure.
   * See comments in sqlInt.h for further information.
   *
   * This routine does NOT free the Select structure passed in.  The
   * calling function needs to do that.
   *
   * @retval 0 on success.
   * @retval != 0 on error.
   */
  int
  sqlSelect(Parse * pParse,		/* The parser context */
  	      Select * p,		/* The SELECT statement being coded. */
  	      SelectDest * pDest)	/* What to do with the query results */
  {
  	int i, j;		/* Loop counters */
  	WhereInfo *pWInfo;	/* Return from sqlWhereBegin() */
  	Vdbe *v;		/* The virtual machine under construction */
  	int isAgg;		/* True for select lists like "count(*)" */
  	ExprList *pEList = 0;	/* List of columns to extract. */
  	SrcList *pTabList;	/* List of tables to select from */
  	Expr *pWhere;		/* The WHERE clause.  May be NULL */
  	ExprList *pGroupBy;	/* The GROUP BY clause.  May be NULL */
  	Expr *pHaving;		/* The HAVING clause.  May be NULL */
  	int rc = 1;		/* Value to return from this function */
  	DistinctCtx sDistinct;	/* Info on how to code the DISTINCT keyword */
  	SortCtx sSort;		/* Info on how to code the ORDER BY clause */
  	AggInfo sAggInfo;	/* Information used by aggregate queries */
  	int iEnd;		/* Address of the end of the query */
  	sql *db;		/* The database connection */
  	int iRestoreSelectId = pParse->iSelectId;
  	pParse->iSelectId = pParse->iNextSelectId++;
  
  	db = pParse->db;
  	if (p == 0 || db->mallocFailed || pParse->is_aborted) {
  		return 1;
  	}
  	memset(&sAggInfo, 0, sizeof(sAggInfo));
  #ifdef SQL_DEBUG
  	pParse->nSelectIndent++;
  	SELECTTRACE(1, pParse, p, ("begin processing:\n"));
  	if (sqlSelectTrace & 0x100) {
  		sqlTreeViewSelect(0, p, 0);
  	}
  #endif
  
  	assert(p->pOrderBy == 0 || pDest->eDest != SRT_DistFifo);
  	assert(p->pOrderBy == 0 || pDest->eDest != SRT_Fifo);
  	assert(p->pOrderBy == 0 || pDest->eDest != SRT_DistQueue);
  	assert(p->pOrderBy == 0 || pDest->eDest != SRT_Queue);
  	if (IgnorableOrderby(pDest)) {
  		assert(pDest->eDest == SRT_Exists || pDest->eDest == SRT_Union
  		       || pDest->eDest == SRT_Except
  		       || pDest->eDest == SRT_Discard
  		       || pDest->eDest == SRT_Queue
  		       || pDest->eDest == SRT_DistFifo
  		       || pDest->eDest == SRT_DistQueue
  		       || pDest->eDest == SRT_Fifo);
  		/* If ORDER BY makes no difference in the output then neither does
  		 * DISTINCT so it can be removed too.
  		 */
  		sql_expr_list_delete(db, p->pOrderBy);
  		p->pOrderBy = 0;
  		p->selFlags &= ~SF_Distinct;
  	}
  	sqlSelectPrep(pParse, p, 0);
  	memset(&sSort, 0, sizeof(sSort));
  	sSort.pOrderBy = p->pOrderBy;
  	pTabList = p->pSrc;
  	if (pParse->is_aborted || db->mallocFailed) {
  		goto select_end;
  	}
  	assert(p->pEList != 0);
  	isAgg = (p->selFlags & SF_Aggregate) != 0;
  #ifdef SQL_DEBUG
  	if (sqlSelectTrace & 0x100) {
  		SELECTTRACE(0x100, pParse, p, ("after name resolution:\n"));
  		sqlTreeViewSelect(0, p, 0);
  	}
  #endif
  
  	/* Try to flatten subqueries in the FROM clause up into the main query
  	 */
  	for (i = 0; !p->pPrior && i < pTabList->nSrc; i++) {
  		struct SrcList_item *pItem = &pTabList->a[i];
  		Select *pSub = pItem->pSelect;
  		int isAggSub;
  		struct space *space = pItem->space;
  		if (pSub == 0)
  			continue;
  
  		/* Catch mismatch in the declared columns of a view and the number of
  		 * columns in the SELECT on the RHS
  		 */
  		if ((int)space->def->field_count != pSub->pEList->nExpr) {
  			diag_set(ClientError, ER_CREATE_SPACE, space->def->name,
  				 "number of aliases doesn't match provided "\
  				 "columns");
  			pParse->is_aborted = true;
  			goto select_end;
  		}
  
  		isAggSub = (pSub->selFlags & SF_Aggregate) != 0;
  		if (flattenSubquery(pParse, p, i, isAgg, isAggSub)) {
  			/* This subquery can be absorbed into its parent. */
  			if (isAggSub) {
  				isAgg = 1;
  				p->selFlags |= SF_Aggregate;
  			}
  			i = -1;
  		}
  		pTabList = p->pSrc;
  		if (db->mallocFailed)
  			goto select_end;
  		if (!IgnorableOrderby(pDest)) {
  			sSort.pOrderBy = p->pOrderBy;
  		}
  	}
  
  	/* Get a pointer the VDBE under construction, allocating a new VDBE if one
  	 * does not already exist
  	 */
  	v = sqlGetVdbe(pParse);
  	if (v == 0)
  		goto select_end;
  
  	/* Handle compound SELECT statements using the separate multiSelect()
  	 * procedure.
  	 */
  	if (p->pPrior) {
  		rc = multiSelect(pParse, p, pDest);
  		pParse->iSelectId = iRestoreSelectId;
  
  		int end = sqlVdbeMakeLabel(v);
  		if ((p->selFlags & SF_SingleRow) != 0 && p->iLimit != 0) {
  			vdbe_code_raise_on_multiple_rows(pParse, p->iLimit,
  							 end);
  		}
  		sqlVdbeResolveLabel(v, end);
  
  #ifdef SQL_DEBUG
  		SELECTTRACE(1, pParse, p, ("end compound-select processing\n"));
  		pParse->nSelectIndent--;
  #endif
  		return rc;
  	}
  
  	/* Generate code for all sub-queries in the FROM clause
  	 */
  	for (i = 0; i < pTabList->nSrc; i++) {
  		struct SrcList_item *pItem = &pTabList->a[i];
  		SelectDest dest;
  		Select *pSub = pItem->pSelect;
  		if (pSub == 0)
  			continue;
  
  		/* Sometimes the code for a subquery will be generated more than
  		 * once, if the subquery is part of the WHERE clause in a LEFT JOIN,
  		 * for example.  In that case, do not regenerate the code to manifest
  		 * a view or the co-routine to implement a view.  The first instance
  		 * is sufficient, though the subroutine to manifest the view does need
  		 * to be invoked again.
  		 */
  		if (pItem->addrFillSub) {
  			if (pItem->fg.viaCoroutine == 0) {
  				sqlVdbeAddOp2(v, OP_Gosub, pItem->regReturn,
  						  pItem->addrFillSub);
  			}
  			continue;
  		}
  
  		/* Increment Parse.nHeight by the height of the largest expression
  		 * tree referred to by this, the parent select. The child select
  		 * may contain expression trees of at most
  		 * (SQL_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
  		 * more conservative than necessary, but much easier than enforcing
  		 * an exact limit.
  		 */
  		pParse->nHeight += sqlSelectExprHeight(p);
  
  		/* Make copies of constant WHERE-clause terms in the outer query down
  		 * inside the subquery.  This can help the subquery to run more efficiently.
  		 */
  		if ((pItem->fg.jointype & JT_OUTER) == 0
  		    && pushDownWhereTerms(pParse, pSub, p->pWhere,
  					  pItem->iCursor)
  		    ) {
  #ifdef SQL_DEBUG
  			if (sqlSelectTrace & 0x100) {
  				SELECTTRACE(0x100, pParse, p,
  					    ("After WHERE-clause push-down:\n"));
  				sqlTreeViewSelect(0, p, 0);
  			}
  #endif
  		}
  
  		/* Generate code to implement the subquery
  		 *
  		 * The subquery is implemented as a co-routine if all of these are true:
  		 *   (1)  The subquery is guaranteed to be the outer loop (so that it
  		 *        does not need to be computed more than once)
  		 *   (2)  The ALL keyword after SELECT is omitted.  (Applications are
  		 *        allowed to say "SELECT ALL" instead of just "SELECT" to disable
  		 *        the use of co-routines.)
  		 *
  		 * TODO: Are there other reasons beside (1) to use a co-routine
  		 * implementation?
  		 */
  		if (i == 0 && (pTabList->nSrc == 1 || (pTabList->a[1].fg.jointype & (JT_LEFT | JT_CROSS)) != 0)	/* (1) */
  		    &&(p->selFlags & SF_All) == 0	/* (2) */
  		    && OptimizationEnabled(db, SQL_SubqCoroutine)	/* (3) */
  		    ) {
  			/* Implement a co-routine that will return a single row of the result
  			 * set on each invocation.
  			 */
  			int addrTop = sqlVdbeCurrentAddr(v) + 1;
  			pItem->regReturn = ++pParse->nMem;
  			sqlVdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn,
  					  0, addrTop);
  			VdbeComment((v, "%s", pItem->space->def->name));
  			pItem->addrFillSub = addrTop;
  			sqlSelectDestInit(&dest, SRT_Coroutine,
  					      pItem->regReturn, -1);
  			pItem->iSelectId = pParse->iNextSelectId;
  			sqlSelect(pParse, pSub, &dest);
  			pItem->fg.viaCoroutine = 1;
  			pItem->regResult = dest.iSdst;
  			sqlVdbeEndCoroutine(v, pItem->regReturn);
  			sqlVdbeJumpHere(v, addrTop - 1);
  			sqlClearTempRegCache(pParse);
  		} else {
  			/* Generate a subroutine that will fill
  			 * an ephemeral space with the content
  			 * of this subquery. pItem->addrFillSub
  			 * will point to the address of the
  			 * generated subroutine.
  			 * pItem->regReturn is a register
  			 * allocated to hold the subroutine
  			 * return address
  			 */
  			int topAddr;
  			int onceAddr = 0;
  			int retAddr;
  			assert(pItem->addrFillSub == 0);
  			pItem->regReturn = ++pParse->nMem;
  			topAddr =
  			    sqlVdbeAddOp2(v, OP_Integer, 0,
  					      pItem->regReturn);
  			pItem->addrFillSub = topAddr + 1;
  			if (pItem->fg.isCorrelated == 0) {
  				/* If the subquery is not
  				 * correlated and if we are not
  				 * inside of a trigger, then
  				 * we only need to compute the
  				 * value of the subquery once.
  				 */
  				onceAddr = sqlVdbeAddOp0(v, OP_Once);
  				VdbeCoverage(v);
  				VdbeComment((v, "materialize \"%s\"",
  					     pItem->space->def->name));
  			} else {
  				VdbeNoopComment((v, "materialize \"%s\"",
  						 pItem->space->def->name));
  			}
  			sqlSelectDestInit(&dest, SRT_EphemTab,
  					      pItem->iCursor, ++pParse->nMem);
  			pItem->iSelectId = pParse->iNextSelectId;
  			sqlSelect(pParse, pSub, &dest);
  			if (onceAddr)
  				sqlVdbeJumpHere(v, onceAddr);
  			retAddr =
  			    sqlVdbeAddOp1(v, OP_Return, pItem->regReturn);
  			VdbeComment((v, "end %s", pItem->space->def->name));
  			sqlVdbeChangeP1(v, topAddr, retAddr);
  			sqlClearTempRegCache(pParse);
  		}
  		if (db->mallocFailed)
  			goto select_end;
  		pParse->nHeight -= sqlSelectExprHeight(p);
  	}
  
  	/* Various elements of the SELECT copied into local variables for
  	 * convenience
  	 */
  	pEList = p->pEList;
  	pWhere = p->pWhere;
  	pGroupBy = p->pGroupBy;
  	pHaving = p->pHaving;
  	sDistinct.isTnct = (p->selFlags & SF_Distinct) != 0;
  
  #ifdef SQL_DEBUG
  	if (sqlSelectTrace & 0x400) {
  		SELECTTRACE(0x400, pParse, p,
  			    ("After all FROM-clause analysis:\n"));
  		sqlTreeViewSelect(0, p, 0);
  	}
  #endif
  
  	/* If the query is DISTINCT with an ORDER BY but is not an aggregate, and
  	 * if the select-list is the same as the ORDER BY list, then this query
  	 * can be rewritten as a GROUP BY. In other words, this:
  	 *
  	 *     SELECT DISTINCT xyz FROM ... ORDER BY xyz
  	 *
  	 * is transformed to:
  	 *
  	 *     SELECT xyz FROM ... GROUP BY xyz ORDER BY xyz
  	 *
  	 * The second form is preferred as a single index (or temp-table) may be
  	 * used for both the ORDER BY and DISTINCT processing. As originally
  	 * written the query must use a temp-table for at least one of the ORDER
  	 * BY and DISTINCT, and an index or separate temp-table for the other.
  	 */
  	if ((p->selFlags & (SF_Distinct | SF_Aggregate)) == SF_Distinct
  	    && sqlExprListCompare(sSort.pOrderBy, pEList, -1) == 0) {
  		p->selFlags &= ~SF_Distinct;
  		pGroupBy = p->pGroupBy = sql_expr_list_dup(db, pEList, 0);
  		/* Notice that even thought SF_Distinct has been cleared from p->selFlags,
  		 * the sDistinct.isTnct is still set.  Hence, isTnct represents the
  		 * original setting of the SF_Distinct flag, not the current setting
  		 */
  		assert(sDistinct.isTnct);
  
  #ifdef SQL_DEBUG
  		if (sqlSelectTrace & 0x400) {
  			SELECTTRACE(0x400, pParse, p,
  				    ("Transform DISTINCT into GROUP BY:\n"));
  			sqlTreeViewSelect(0, p, 0);
  		}
  #endif
  	}
  
  	/* If there is an ORDER BY clause, then create an ephemeral index to
  	 * do the sorting.  But this sorting ephemeral index might end up
  	 * being unused if the data can be extracted in pre-sorted order.
  	 * If that is the case, then the OP_OpenEphemeral instruction will be
  	 * changed to an OP_Noop once we figure out that the sorting index is
  	 * not needed.  The sSort.addrSortIndex variable is used to facilitate
  	 * that change.
  	 */
  	if (sSort.pOrderBy) {
  		struct sql_key_info *key_info =
  			sql_expr_list_to_key_info(pParse, sSort.pOrderBy, 0);
  		sSort.reg_eph = ++pParse->nMem;
  		sSort.iECursor = pParse->nTab++;
  		/* Number of columns in transient table equals to number of columns in
  		 * SELECT statement plus number of columns in ORDER BY statement
  		 * and plus one column for ID.
  		 */
  		int nCols = pEList->nExpr + sSort.pOrderBy->nExpr + 1;
  		if (key_info->parts[0].sort_order == SORT_ORDER_DESC) {
  			sSort.sortFlags |= SORTFLAG_DESC;
  		}
  		sSort.addrSortIndex =
  		    sqlVdbeAddOp4(v, OP_OpenTEphemeral,
  				      sSort.reg_eph,
  				      nCols,
  				      0, (char *)key_info, P4_KEYINFO);
  		sqlVdbeAddOp3(v, OP_IteratorOpen, sSort.iECursor, 0, sSort.reg_eph);
  		VdbeComment((v, "Sort table"));
  	} else {
  		sSort.addrSortIndex = -1;
  	}
  
  	/* If the output is destined for a temporary table, open that table.
  	 */
  	if (pDest->eDest == SRT_EphemTab) {
  		struct sql_key_info *key_info =
  			sql_expr_list_to_key_info(pParse, pEList, 0);
  		sqlVdbeAddOp4(v, OP_OpenTEphemeral, pDest->reg_eph,
  				  pEList->nExpr + 1, 0, (char *)key_info,
  				  P4_KEYINFO);
  		sqlVdbeAddOp3(v, OP_IteratorOpen, pDest->iSDParm, 0,
  				  pDest->reg_eph);
  
  		VdbeComment((v, "Output table"));
  	}
  
  	/* Set the limiter.
  	 */
  	iEnd = sqlVdbeMakeLabel(v);
  	if ((p->selFlags & SF_FixedLimit) == 0) {
  		p->nSelectRow = 320;	/* 4 billion rows */
  	}
  	computeLimitRegisters(pParse, p, iEnd);
  	if (p->iLimit == 0 && sSort.addrSortIndex >= 0) {
  		sqlVdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen);
  		sqlVdbeChangeP1(v, sSort.addrSortIndex, sSort.iECursor);
  		sqlVdbeChangeToNoop(v, sSort.addrSortIndex + 1);
  		sSort.sortFlags |= SORTFLAG_UseSorter;
  	}
  
  	/* Open an ephemeral index to use for the distinct set.
  	 */
  	if (p->selFlags & SF_Distinct) {
  		sDistinct.cur_eph = pParse->nTab++;
  		sDistinct.reg_eph = ++pParse->nMem;
  		struct sql_key_info *key_info =
  			sql_expr_list_to_key_info(pParse, p->pEList, 0);
  		sDistinct.addrTnct = sqlVdbeAddOp4(v, OP_OpenTEphemeral,
  						       sDistinct.reg_eph,
  						       key_info->part_count,
  						       0, (char *)key_info,
  						       P4_KEYINFO);
  		sqlVdbeAddOp3(v, OP_IteratorOpen, sDistinct.cur_eph, 0,
  				  sDistinct.reg_eph);
  		VdbeComment((v, "Distinct table"));
  		sDistinct.eTnctType = WHERE_DISTINCT_UNORDERED;
  	} else {
  		sDistinct.eTnctType = WHERE_DISTINCT_NOOP;
  	}
  
  	if (!isAgg && pGroupBy == 0) {
  		/* No aggregate functions and no GROUP BY clause */
  		u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0);
  		assert(WHERE_USE_LIMIT == SF_FixedLimit);
  		wctrlFlags |= p->selFlags & SF_FixedLimit;
  
  		/* Begin the database scan. */
  		pWInfo =
  		    sqlWhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy,
  				      p->pEList, wctrlFlags, p->nSelectRow);
  		if (pWInfo == 0)
  			goto select_end;
  		if (sqlWhereOutputRowCount(pWInfo) < p->nSelectRow) {
  			p->nSelectRow = sqlWhereOutputRowCount(pWInfo);
  		}
  		if (sDistinct.isTnct && sqlWhereIsDistinct(pWInfo)) {
  			sDistinct.eTnctType = sqlWhereIsDistinct(pWInfo);
  		}
  		if (sSort.pOrderBy) {
  			sSort.nOBSat = sqlWhereIsOrdered(pWInfo);
  			sSort.bOrderedInnerLoop =
  			    sqlWhereOrderedInnerLoop(pWInfo);
  			if (sSort.nOBSat == sSort.pOrderBy->nExpr) {
  				sSort.pOrderBy = 0;
  			}
  		}
  
  		/* If sorting index that was created by a prior OP_OpenEphemeral
  		 * instruction ended up not being needed, then change the OP_OpenEphemeral
  		 * into an OP_Noop.
  		 */
  		if (sSort.addrSortIndex >= 0 && sSort.pOrderBy == 0) {
  			/*
  			 * To handle ordering two op-codes are
  			 * emitted: OpenTEphemeral & IteratorOpen.
  			 * sSort.addrSortIndex is address of
  			 * first insn in a couple. To evict
  			 * ephemral space, need to noop both
  			 * op-codes.
  			 */
  			sqlVdbeChangeToNoop(v, sSort.addrSortIndex);
  			sqlVdbeChangeToNoop(v, sSort.addrSortIndex + 1);
  		}
  
  		/* Use the standard inner loop. */
  		selectInnerLoop(pParse, p, pEList, -1, &sSort, &sDistinct,
  				pDest, sqlWhereContinueLabel(pWInfo),
  				sqlWhereBreakLabel(pWInfo));
  
  		/* End the database scan loop.
  		 */
  		sqlWhereEnd(pWInfo);
  	} else {
  		/* This case when there exist aggregate functions or a GROUP BY clause
  		 * or both
  		 */
  		NameContext sNC;	/* Name context for processing aggregate information */
  		int iAMem;	/* First Mem address for storing current GROUP BY */
  		int iBMem;	/* First Mem address for previous GROUP BY */
  		int iUseFlag;	/* Mem address holding flag indicating that at least
  				 * one row of the input to the aggregator has been
  				 * processed
  				 */
  		int iAbortFlag;	/* Mem address which causes query abort if positive */
  		int groupBySort;	/* Rows come from source in GROUP BY order */
  		int addrEnd;	/* End of processing for this SELECT */
  		int sortPTab = 0;	/* Pseudotable used to decode sorting results */
  		int sortOut = 0;	/* Output register from the sorter */
  		int orderByGrp = 0;	/* True if the GROUP BY and ORDER BY are the same */
  
  		/* Remove any and all aliases between the result set and the
  		 * GROUP BY clause.
  		 */
  		if (pGroupBy) {
  			int k;	/* Loop counter */
  			struct ExprList_item *pItem;	/* For looping over expression in a list */
  
  			for (k = p->pEList->nExpr, pItem = p->pEList->a; k > 0;
  			     k--, pItem++) {
  				pItem->u.x.iAlias = 0;
  			}
  			for (k = pGroupBy->nExpr, pItem = pGroupBy->a; k > 0;
  			     k--, pItem++) {
  				pItem->u.x.iAlias = 0;
  			}
  			assert(66 == sqlLogEst(100));
  			if (p->nSelectRow > 66)
  				p->nSelectRow = 66;
  		} else {
  			assert(0 == sqlLogEst(1));
  			p->nSelectRow = 0;
  		}
  
  		/* If there is both a GROUP BY and an ORDER BY clause and they are
  		 * identical, then it may be possible to disable the ORDER BY clause
  		 * on the grounds that the GROUP BY will cause elements to come out
  		 * in the correct order. It also may not - the GROUP BY might use a
  		 * database index that causes rows to be grouped together as required
  		 * but not actually sorted. Either way, record the fact that the
  		 * ORDER BY and GROUP BY clauses are the same by setting the orderByGrp
  		 * variable.
  		 */
  		if (sqlExprListCompare(pGroupBy, sSort.pOrderBy, -1) == 0) {
  			orderByGrp = 1;
  		}
  
  		/* Create a label to jump to when we want to abort the query */
  		addrEnd = sqlVdbeMakeLabel(v);
  
  		/* Convert TK_COLUMN nodes into TK_AGG_COLUMN and make entries in
  		 * sAggInfo for all TK_AGG_FUNCTION nodes in expressions of the
  		 * SELECT statement.
  		 */
  		memset(&sNC, 0, sizeof(sNC));
  		sNC.pParse = pParse;
  		sNC.pSrcList = pTabList;
  		sNC.pAggInfo = &sAggInfo;
  		sAggInfo.mnReg = pParse->nMem + 1;
  		sAggInfo.nSortingColumn = pGroupBy ? pGroupBy->nExpr : 0;
  		sAggInfo.pGroupBy = pGroupBy;
  		sqlExprAnalyzeAggList(&sNC, pEList);
  		sqlExprAnalyzeAggList(&sNC, sSort.pOrderBy);
  		if (pHaving) {
  			sqlExprAnalyzeAggregates(&sNC, pHaving);
  		}
  		sAggInfo.nAccumulator = sAggInfo.nColumn;
  		for (i = 0; i < sAggInfo.nFunc; i++) {
  			assert(!ExprHasProperty
  			       (sAggInfo.aFunc[i].pExpr, EP_xIsSelect));
  			sNC.ncFlags |= NC_InAggFunc;
  			sqlExprAnalyzeAggList(&sNC,
  						  sAggInfo.aFunc[i].pExpr->x.
  						  pList);
  			sNC.ncFlags &= ~NC_InAggFunc;
  		}
  		sAggInfo.mxReg = pParse->nMem;
  		if (db->mallocFailed)
  			goto select_end;
  
  		/* Processing for aggregates with GROUP BY is very different and
  		 * much more complex than aggregates without a GROUP BY.
  		 */
  		if (pGroupBy) {
  			int addr1;	/* A-vs-B comparision jump */
  			int addrOutputRow;	/* Start of subroutine that outputs a result row */
  			int regOutputRow;	/* Return address register for output subroutine */
  			int addrSetAbort;	/* Set the abort flag and return */
  			int addrTopOfLoop;	/* Top of the input loop */
  			int addrSortingIdx;	/* The OP_OpenEphemeral for the sorting index */
  			int addrReset;	/* Subroutine for resetting the accumulator */
  			int regReset;	/* Return address register for reset subroutine */
  
  			/* If there is a GROUP BY clause we might need a sorting index to
  			 * implement it.  Allocate that sorting index now.  If it turns out
  			 * that we do not need it after all, the OP_SorterOpen instruction
  			 * will be converted into a Noop.
  			 */
  			sAggInfo.sortingIdx = pParse->nTab++;
  			struct sql_key_info *key_info =
  				sql_expr_list_to_key_info(pParse, pGroupBy, 0);
  			addrSortingIdx =
  			    sqlVdbeAddOp4(v, OP_SorterOpen,
  					      sAggInfo.sortingIdx,
  					      sAggInfo.nSortingColumn, 0,
  					      (char *)key_info, P4_KEYINFO);
  
  			/* Initialize memory locations used by GROUP BY aggregate processing
  			 */
  			iUseFlag = ++pParse->nMem;
  			iAbortFlag = ++pParse->nMem;
  			regOutputRow = ++pParse->nMem;
  			addrOutputRow = sqlVdbeMakeLabel(v);
  			regReset = ++pParse->nMem;
  			addrReset = sqlVdbeMakeLabel(v);
  			iAMem = pParse->nMem + 1;
  			pParse->nMem += pGroupBy->nExpr;
  			iBMem = pParse->nMem + 1;
  			pParse->nMem += pGroupBy->nExpr;
  			sqlVdbeAddOp2(v, OP_Integer, 0, iAbortFlag);
  			VdbeComment((v, "clear abort flag"));
  			sqlVdbeAddOp2(v, OP_Integer, 0, iUseFlag);
  			VdbeComment((v, "indicate accumulator empty"));
  			sqlVdbeAddOp3(v, OP_Null, 0, iAMem,
  					  iAMem + pGroupBy->nExpr - 1);
  
  			/* Begin a loop that will extract all source rows in GROUP BY order.
  			 * This might involve two separate loops with an OP_Sort in between, or
  			 * it might be a single loop that uses an index to extract information
  			 * in the right order to begin with.
  			 */
  			sqlVdbeAddOp2(v, OP_Gosub, regReset, addrReset);
  			pWInfo =
  			    sqlWhereBegin(pParse, pTabList, pWhere,
  					      pGroupBy, 0,
  					      WHERE_GROUPBY | (orderByGrp ?
  							       WHERE_SORTBYGROUP
  							       : 0), 0);
  			if (pWInfo == 0)
  				goto select_end;
  			if (sqlWhereIsOrdered(pWInfo) == pGroupBy->nExpr) {
  				/* The optimizer is able to deliver rows in group by order so
  				 * we do not have to sort.  The OP_OpenEphemeral table will be
  				 * cancelled later because we still need to use the key_info
  				 */
  				groupBySort = 0;
  			} else {
  				/* Rows are coming out in undetermined order.  We have to push
  				 * each row into a sorting index, terminate the first loop,
  				 * then loop over the sorting index in order to get the output
  				 * in sorted order
  				 */
  				int regBase;
  				int regRecord;
  				int nCol;
  				int nGroupBy;
  
  				explainTempTable(pParse,
  						 (sDistinct.isTnct
  						  && (p->
  						      selFlags & SF_Distinct) ==
  						  0) ? "DISTINCT" : "GROUP BY");
  
  				groupBySort = 1;
  				nGroupBy = pGroupBy->nExpr;
  				nCol = nGroupBy;
  				j = nGroupBy;
  				for (i = 0; i < sAggInfo.nColumn; i++) {
  					if (sAggInfo.aCol[i].iSorterColumn >= j) {
  						nCol++;
  						j++;
  					}
  				}
  				regBase = sqlGetTempRange(pParse, nCol);
  				sqlExprCacheClear(pParse);
  				sqlExprCodeExprList(pParse, pGroupBy,
  							regBase, 0, 0);
  				j = nGroupBy;
  				for (i = 0; i < sAggInfo.nColumn; i++) {
  					struct AggInfo_col *pCol =
  					    &sAggInfo.aCol[i];
  					if (pCol->iSorterColumn >= j) {
  						int r1 = j + regBase;
  						sqlExprCodeGetColumnToReg
  						    (pParse, pCol->iColumn,
  						     pCol->iTable, r1);
  						j++;
  					}
  				}
  				regRecord = sqlGetTempReg(pParse);
  				sqlVdbeAddOp3(v, OP_MakeRecord, regBase,
  						  nCol, regRecord);
  				sqlVdbeAddOp2(v, OP_SorterInsert,
  						  sAggInfo.sortingIdx,
  						  regRecord);
  				sqlReleaseTempReg(pParse, regRecord);
  				sqlReleaseTempRange(pParse, regBase, nCol);
  				sqlWhereEnd(pWInfo);
  				sAggInfo.sortingIdxPTab = sortPTab =
  				    pParse->nTab++;
  				sortOut = sqlGetTempReg(pParse);
  				sqlVdbeAddOp3(v, OP_OpenPseudo, sortPTab,
  						  sortOut, nCol);
  				sqlVdbeAddOp2(v, OP_SorterSort,
  						  sAggInfo.sortingIdx, addrEnd);
  				VdbeComment((v, "GROUP BY sort"));
  				VdbeCoverage(v);
  				sAggInfo.useSortingIdx = 1;
  				sqlExprCacheClear(pParse);
  
  			}
  
  			/* If the index or temporary table used by the GROUP BY sort
  			 * will naturally deliver rows in the order required by the ORDER BY
  			 * clause, cancel the ephemeral table open coded earlier.
  			 *
  			 * This is an optimization - the correct answer should result regardless.
  			 * Use the SQL_GroupByOrder flag with SQL_TESTCTRL_OPTIMIZER to
  			 * disable this optimization for testing purposes.
  			 */
  			if (orderByGrp
  			    && OptimizationEnabled(db, SQL_GroupByOrder)
  			    && (groupBySort || sqlWhereIsSorted(pWInfo))
  			    ) {
  				sSort.pOrderBy = 0;
  				sqlVdbeChangeToNoop(v, sSort.addrSortIndex);
  				sqlVdbeChangeToNoop(v, sSort.addrSortIndex + 1);
  			}
  
  			/* Evaluate the current GROUP BY terms and store in b0, b1, b2...
  			 * (b0 is memory location iBMem+0, b1 is iBMem+1, and so forth)
  			 * Then compare the current GROUP BY terms against the GROUP BY terms
  			 * from the previous row currently stored in a0, a1, a2...
  			 */
  			addrTopOfLoop = sqlVdbeCurrentAddr(v);
  			sqlExprCacheClear(pParse);
  			if (groupBySort) {
  				sqlVdbeAddOp3(v, OP_SorterData,
  						  sAggInfo.sortingIdx, sortOut,
  						  sortPTab);
  			}
  			for (j = 0; j < pGroupBy->nExpr; j++) {
  				if (groupBySort) {
  					sqlVdbeAddOp3(v, OP_Column,
  							  sortPTab, j,
  							  iBMem + j);
  				} else {
  					sAggInfo.directMode = 1;
  					sqlExprCode(pParse,
  							pGroupBy->a[j].pExpr,
  							iBMem + j);
  				}
  			}
  			sqlVdbeAddOp4(v, OP_Compare, iAMem, iBMem,
  					  pGroupBy->nExpr,
  					  (char*)sql_key_info_ref(key_info),
  					  P4_KEYINFO);
  			addr1 = sqlVdbeCurrentAddr(v);
  			sqlVdbeAddOp3(v, OP_Jump, addr1 + 1, 0, addr1 + 1);
  			VdbeCoverage(v);
  
  			/* Generate code that runs whenever the GROUP BY changes.
  			 * Changes in the GROUP BY are detected by the previous code
  			 * block.  If there were no changes, this block is skipped.
  			 *
  			 * This code copies current group by terms in b0,b1,b2,...
  			 * over to a0,a1,a2.  It then calls the output subroutine
  			 * and resets the aggregate accumulator registers in preparation
  			 * for the next GROUP BY batch.
  			 */
  			sqlExprCodeMove(pParse, iBMem, iAMem,
  					    pGroupBy->nExpr);
  			sqlVdbeAddOp2(v, OP_Gosub, regOutputRow,
  					  addrOutputRow);
  			VdbeComment((v, "output one row"));
  			sqlVdbeAddOp2(v, OP_IfPos, iAbortFlag, addrEnd);
  			VdbeCoverage(v);
  			VdbeComment((v, "check abort flag"));
  			sqlVdbeAddOp2(v, OP_Gosub, regReset, addrReset);
  			VdbeComment((v, "reset accumulator"));
  
  			/* Update the aggregate accumulators based on the content of
  			 * the current row
  			 */
  			sqlVdbeJumpHere(v, addr1);
  			updateAccumulator(pParse, &sAggInfo);
  			sqlVdbeAddOp2(v, OP_Integer, 1, iUseFlag);
  			VdbeComment((v, "indicate data in accumulator"));
  
  			/* End of the loop
  			 */
  			if (groupBySort) {
  				sqlVdbeAddOp2(v, OP_SorterNext,
  						  sAggInfo.sortingIdx,
  						  addrTopOfLoop);
  				VdbeCoverage(v);
  			} else {
  				sqlWhereEnd(pWInfo);
  				sqlVdbeChangeToNoop(v, addrSortingIdx);
  			}
  
  			/* Output the final row of result
  			 */
  			sqlVdbeAddOp2(v, OP_Gosub, regOutputRow,
  					  addrOutputRow);
  			VdbeComment((v, "output final row"));
  
  			/* Jump over the subroutines
  			 */
  			sqlVdbeGoto(v, addrEnd);
  
  			/* Generate a subroutine that outputs a single row of the result
  			 * set.  This subroutine first looks at the iUseFlag.  If iUseFlag
  			 * is less than or equal to zero, the subroutine is a no-op.  If
  			 * the processing calls for the query to abort, this subroutine
  			 * increments the iAbortFlag memory location before returning in
  			 * order to signal the caller to abort.
  			 */
  			addrSetAbort = sqlVdbeCurrentAddr(v);
  			sqlVdbeAddOp2(v, OP_Integer, 1, iAbortFlag);
  			VdbeComment((v, "set abort flag"));
  			sqlVdbeAddOp1(v, OP_Return, regOutputRow);
  			sqlVdbeResolveLabel(v, addrOutputRow);
  			addrOutputRow = sqlVdbeCurrentAddr(v);
  			sqlVdbeAddOp2(v, OP_IfPos, iUseFlag,
  					  addrOutputRow + 2);
  			VdbeCoverage(v);
  			VdbeComment((v,
  				     "Groupby result generator entry point"));
  			sqlVdbeAddOp1(v, OP_Return, regOutputRow);
  			finalizeAggFunctions(pParse, &sAggInfo);
  			sqlExprIfFalse(pParse, pHaving, addrOutputRow + 1,
  					   SQL_JUMPIFNULL);
  			selectInnerLoop(pParse, p, p->pEList, -1, &sSort,
  					&sDistinct, pDest, addrOutputRow + 1,
  					addrSetAbort);
  			sqlVdbeAddOp1(v, OP_Return, regOutputRow);
  			VdbeComment((v, "end groupby result generator"));
  
  			/* Generate a subroutine that will reset the group-by accumulator
  			 */
  			sqlVdbeResolveLabel(v, addrReset);
  			resetAccumulator(pParse, &sAggInfo);
  			sqlVdbeAddOp1(v, OP_Return, regReset);
  
  		} /* endif pGroupBy.  Begin aggregate queries without GROUP BY: */
  		else {
  			struct space *space = is_simple_count(p, &sAggInfo);
  			if (space != NULL) {
  				/*
  				 * If is_simple_count() returns a pointer to
  				 * space, then the SQL statement is of the form:
  				 *
  				 *   SELECT count(*) FROM <tbl>
  				 *
  				 * This statement is so common that it is
  				 * optimized specially. The OP_Count instruction
  				 * is executed on the primary key index,
  				 * since there is no difference which index
  				 * to choose.
  				 */
  				const int cursor = pParse->nTab++;
  				/*
  				 * Open the cursor, execute the OP_Count,
  				 * close the cursor.
  				 */
  				vdbe_emit_open_cursor(pParse, cursor, 0, space);
  				sqlVdbeAddOp2(v, OP_Count, cursor,
  						  sAggInfo.aFunc[0].iMem);
  				sqlVdbeAddOp1(v, OP_Close, cursor);
  				explain_simple_count(pParse, space->def->name);
  			} else
  			{
  				/* Check if the query is of one of the following forms:
  				 *
  				 *   SELECT min(x) FROM ...
  				 *   SELECT max(x) FROM ...
  				 *
  				 * If it is, then ask the code in where.c to attempt to sort results
  				 * as if there was an "ORDER ON x" or "ORDER ON x DESC" clause.
  				 * If where.c is able to produce results sorted in this order, then
  				 * add vdbe code to break out of the processing loop after the
  				 * first iteration (since the first iteration of the loop is
  				 * guaranteed to operate on the row with the minimum or maximum
  				 * value of x, the only row required).
  				 *
  				 * A special flag must be passed to sqlWhereBegin() to slightly
  				 * modify behavior as follows:
  				 *
  				 *   + If the query is a "SELECT min(x)", then the loop coded by
  				 *     where.c should not iterate over any values with a NULL value
  				 *     for x.
  				 *
  				 *   + The optimizer code in where.c (the thing that decides which
  				 *     index or indices to use) should place a different priority on
  				 *     satisfying the 'ORDER BY' clause than it does in other cases.
  				 *     Refer to code and comments in where.c for details.
  				 */
  				ExprList *pMinMax = 0;
  				u8 flag = WHERE_ORDERBY_NORMAL;
  				ExprList *pDel = 0;
  
  				assert(p->pGroupBy == 0);
  				assert(flag == 0);
  				if (p->pHaving == 0) {
  					flag = minMaxQuery(&sAggInfo, &pMinMax);
  				}
  				assert(flag == 0
  				       || (pMinMax != 0
  					   && pMinMax->nExpr == 1));
  
  				if (flag) {
  					pMinMax =
  					    sql_expr_list_dup(db, pMinMax, 0);
  					pDel = pMinMax;
  					assert(db->mallocFailed
  					       || pMinMax != 0);
  					if (!db->mallocFailed) {
  						pMinMax->a[0].sort_order =
  						    flag !=
  						    WHERE_ORDERBY_MIN ? 1 : 0;
  						pMinMax->a[0].pExpr->op =
  						    TK_COLUMN;
  					}
  				}
  
  				/* This case runs if the aggregate has no GROUP BY clause.  The
  				 * processing is much simpler since there is only a single row
  				 * of output.
  				 */
  				resetAccumulator(pParse, &sAggInfo);
  				pWInfo =
  				    sqlWhereBegin(pParse, pTabList, pWhere,
  						      pMinMax, 0, flag, 0);
  				if (pWInfo == 0) {
  					sql_expr_list_delete(db, pDel);
  					goto select_end;
  				}
  				updateAccumulator(pParse, &sAggInfo);
  				assert(pMinMax == 0 || pMinMax->nExpr == 1);
  				if (sqlWhereIsOrdered(pWInfo) > 0) {
  					sqlVdbeGoto(v,
  							sqlWhereBreakLabel
  							(pWInfo));
  					VdbeComment((v, "%s() by index",
  						     (flag ==
  						      WHERE_ORDERBY_MIN ? "min"
  						      : "max")));
  				}
  				sqlWhereEnd(pWInfo);
  				finalizeAggFunctions(pParse, &sAggInfo);
  				sql_expr_list_delete(db, pDel);
  			}
  
  			sSort.pOrderBy = 0;
  			sqlExprIfFalse(pParse, pHaving, addrEnd,
  					   SQL_JUMPIFNULL);
  			selectInnerLoop(pParse, p, p->pEList, -1, 0, 0, pDest,
  					addrEnd, addrEnd);
  		}
  		sqlVdbeResolveLabel(v, addrEnd);
  
  	}			/* endif aggregate query */
  
  	if (sDistinct.eTnctType == WHERE_DISTINCT_UNORDERED) {
  		explainTempTable(pParse, "DISTINCT");
  	}
  
  	/* If there is an ORDER BY clause, then we need to sort the results
  	 * and send them to the callback one by one.
  	 */
  	if (sSort.pOrderBy) {
  		explainTempTable(pParse,
  				 sSort.nOBSat >
  				 0 ? "RIGHT PART OF ORDER BY" : "ORDER BY");
  		generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest);
  	}
  
  	/* Generate code that prevent returning multiple rows. */
  	if ((p->selFlags & SF_SingleRow) != 0 && p->iLimit != 0)
  		vdbe_code_raise_on_multiple_rows(pParse, p->iLimit, iEnd);
  	/* Jump here to skip this query. */
  	sqlVdbeResolveLabel(v, iEnd);
  
  	/* The SELECT has been coded. If there is an error in the Parse structure,
  	 * set the return code to 1. Otherwise 0.
  	 */
  	rc = (pParse->is_aborted);
  
  	/* Control jumps to here if an error is encountered above, or upon
  	 * successful coding of the SELECT.
  	 */
   select_end:
  	pParse->iSelectId = iRestoreSelectId;
  
  	/* Identify column names if results of the SELECT are to be output.
  	 */
  	if (rc == 0 && pDest->eDest == SRT_Output) {
  		generateColumnNames(pParse, pTabList, pEList);
  	}
  
  	sqlDbFree(db, sAggInfo.aCol);
  	sqlDbFree(db, sAggInfo.aFunc);
  #ifdef SQL_DEBUG
  	SELECTTRACE(1, pParse, p, ("end processing\n"));
  	pParse->nSelectIndent--;
  #endif
  	return rc;
  }
  
  void
  sql_expr_extract_select(struct Parse *parser, struct Select *select)
  {
  	struct ExprList *expr_list = select->pEList;
  	assert(expr_list->nExpr == 1);
  	parser->parsed_ast_type = AST_TYPE_EXPR;
  	/*
  	 * Extract a copy of parsed expression.
  	 * We cannot use EXPRDUP_REDUCE flag in sqlExprDup call
  	 * because some compiled Expr (like Checks expressions)
  	 * may require further resolve with sqlResolveExprNames.
  	 */
  	parser->parsed_ast.expr =
  		sqlExprDup(parser->db, expr_list->a->pExpr, 0);
  }
  