[tarantool-patches] [PATCH v2 6/7] sql: refactor sql_expr_create to set diag

Kirill Shcherbatov kshcherbatov at tarantool.org
Wed Feb 27 14:13:17 MSK 2019


Refactored sql_expr_create routine to use diag_set in case
of memory allocation error.
This change is necessary because the sql_expr_create body has a
sqlNameFromToken call that will be changed in subsequent patches.

Needed for #3931
---
 src/box/sql/build.c         |  44 +++++--
 src/box/sql/expr.c          | 249 +++++++++++++++---------------------
 src/box/sql/fk_constraint.c | 185 +++++++++++++++++----------
 src/box/sql/parse.y         |  35 +++--
 src/box/sql/resolve.c       |  47 ++++---
 src/box/sql/select.c        |  90 +++++++++----
 src/box/sql/sqlInt.h        |  80 +++++++++++-
 src/box/sql/wherecode.c     |   9 +-
 src/box/sql/whereexpr.c     |  22 ++--
 9 files changed, 462 insertions(+), 299 deletions(-)

diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 2084dbfeb..24f20836b 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -627,9 +627,11 @@ sqlAddPrimaryKey(Parse * pParse,	/* Parsing context */
 		struct ExprList *list;
 		struct Token token;
 		sqlTokenInit(&token, space->def->fields[iCol].name);
-		list = sql_expr_list_append(db, NULL,
-					    sqlExprAlloc(db, TK_ID,
-							     &token, 0));
+		struct Expr *expr =
+			sql_expr_create(db, TK_ID, &token, false);
+		if (expr == NULL)
+			goto tnt_error;
+		list = sql_expr_list_append(db, NULL, expr);
 		if (list == NULL)
 			goto primary_key_exit;
 		sql_create_index(pParse, 0, 0, list, 0, SORT_ORDER_ASC,
@@ -659,6 +661,9 @@ sqlAddPrimaryKey(Parse * pParse,	/* Parsing context */
 primary_key_exit:
 	sql_expr_list_delete(pParse->db, pList);
 	return;
+tnt_error:
+	sql_parser_error(pParse);
+	goto primary_key_exit;
 }
 
 void
@@ -1372,12 +1377,15 @@ sql_id_eq_str_expr(struct Parse *parse, const char *col_name,
 		   const char *col_value)
 {
 	struct sql *db = parse->db;
-
-	struct Expr *col_name_expr = sqlExpr(db, TK_ID, col_name);
-	if (col_name_expr == NULL)
+	struct Expr *col_name_expr = sql_op_expr_create(db, TK_ID, col_name);
+	if (col_name_expr == NULL) {
+		sql_parser_error(parse);
 		return NULL;
-	struct Expr *col_value_expr = sqlExpr(db, TK_STRING, col_value);
+	}
+	struct Expr *col_value_expr =
+		sql_op_expr_create(db, TK_STRING, col_value);
 	if (col_value_expr == NULL) {
+		sql_parser_error(parse);
 		sql_expr_delete(db, col_name_expr, false);
 		return NULL;
 	}
@@ -1400,13 +1408,19 @@ vdbe_emit_stat_space_clear(struct Parse *parse, const char *stat_table_name,
 	struct Expr *where = NULL;
 	if (idx_name != NULL) {
 		struct Expr *expr = sql_id_eq_str_expr(parse, "idx", idx_name);
-		if (expr != NULL)
-			where = sqlExprAnd(db, expr, where);
+		if (expr != NULL && (expr != NULL || where != NULL)) {
+			where = sql_and_expr_create(db, expr, where);
+			if (where == NULL)
+				sql_parser_error(parse);
+		}
 	}
 	if (table_name != NULL) {
 		struct Expr *expr = sql_id_eq_str_expr(parse, "tbl", table_name);
-		if (expr != NULL)
-			where = sqlExprAnd(db, expr, where);
+		if (expr != NULL && (expr != NULL || where != NULL)) {
+			where = sql_and_expr_create(db, expr, where);
+			if (where == NULL)
+				sql_parser_error(parse);
+		}
 	}
 	/**
 	 * On memory allocation error sql_table delete_from
@@ -2265,9 +2279,11 @@ sql_create_index(struct Parse *parse, struct Token *token,
 		struct Token prev_col;
 		uint32_t last_field = def->field_count - 1;
 		sqlTokenInit(&prev_col, def->fields[last_field].name);
-		col_list = sql_expr_list_append(parse->db, NULL,
-						sqlExprAlloc(db, TK_ID,
-								 &prev_col, 0));
+		struct Expr *expr = sql_expr_create(db, TK_ID, &prev_col,
+						    false);
+		if (expr == NULL)
+			goto tnt_error;
+		col_list = sql_expr_list_append(parse->db, NULL, expr);
 		if (col_list == NULL)
 			goto exit_create_index;
 		assert(col_list->nExpr == 1);
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index fa2ff1ab3..dd5e2c28d 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -149,16 +149,17 @@ sqlExprAddCollateToken(Parse * pParse,	/* Parsing context */
 			   int dequote	/* True to dequote pCollName */
     )
 {
-	if (pCollName->n > 0) {
-		Expr *pNew =
-		    sqlExprAlloc(pParse->db, TK_COLLATE, pCollName,
-				     dequote);
-		if (pNew) {
-			pNew->pLeft = pExpr;
-			pNew->flags |= EP_Collate | EP_Skip;
-			pExpr = pNew;
-		}
+	if (pCollName->n == 0)
+		return pExpr;
+	struct Expr *new_expr =
+		sql_expr_create(pParse->db, TK_COLLATE, pCollName, dequote);
+	if (new_expr == NULL) {
+		sql_parser_error(pParse);
+		return NULL;
 	}
+	new_expr->pLeft = pExpr;
+	new_expr->flags |= EP_Collate | EP_Skip;
+	pExpr = new_expr;
 	return pExpr;
 }
 
@@ -854,113 +855,62 @@ sqlExprSetHeightAndFlags(Parse * pParse, Expr * p)
 #define exprSetHeight(y)
 #endif				/* SQL_MAX_EXPR_DEPTH>0 */
 
-/*
- * This routine is the core allocator for Expr nodes.
- *
- * Construct a new expression node and return a pointer to it.  Memory
- * for this node and for the pToken argument is a single allocation
- * obtained from sqlDbMalloc().  The calling function
- * is responsible for making sure the node eventually gets freed.
- *
- * If dequote is true, then the token (if it exists) is dequoted.
- * If dequote is false, no dequoting is performed.  The deQuote
- * parameter is ignored if pToken is NULL or if the token does not
- * appear to be quoted.  If the quotes were of the form "..." (double-quotes)
- * then the EP_DblQuoted flag is set on the expression node.
- *
- * Special case:  If op==TK_INTEGER and pToken points to a string that
- * can be translated into a 32-bit integer, then the token is not
- * stored in u.zToken.  Instead, the integer values is written
- * into u.iValue and the EP_IntValue flag is set.  No extra storage
- * is allocated to hold the integer text and the dequote flag is ignored.
- */
-Expr *
-sqlExprAlloc(sql * db,	/* Handle for sqlDbMallocRawNN() */
-		 int op,	/* Expression opcode */
-		 const Token * pToken,	/* Token argument.  Might be NULL */
-		 int dequote	/* True to dequote */
-    )
+struct Expr *
+sql_expr_create(struct sql *db, int op, const Token *token, bool dequote)
 {
-	Expr *pNew;
-	int nExtra = 0;
-	int iValue = 0;
-
-	assert(db != 0);
-	if (pToken) {
-		if (op != TK_INTEGER || pToken->z == 0
-		    || sqlGetInt32(pToken->z, &iValue) == 0) {
-			nExtra = pToken->n + 1;
-			assert(iValue >= 0);
+	int extra_sz = 0;
+	int val = 0;
+	if (token != NULL) {
+		if (op != TK_INTEGER || token->z == NULL ||
+		    sqlGetInt32(token->z, &val) == 0) {
+			extra_sz = token->n + 1;
+			assert(val >= 0);
 		}
 	}
-	pNew = sqlDbMallocRawNN(db, sizeof(Expr) + nExtra);
-	if (pNew) {
-		memset(pNew, 0, sizeof(Expr));
-		pNew->op = (u8) op;
-		pNew->iAgg = -1;
-		if (pToken) {
-			if (nExtra == 0) {
-				pNew->flags |= EP_IntValue;
-				pNew->u.iValue = iValue;
-			} else {
-				pNew->u.zToken = (char *)&pNew[1];
-				assert(pToken->z != 0 || pToken->n == 0);
-				if (pToken->n)
-					memcpy(pNew->u.zToken, pToken->z,
-					       pToken->n);
-				pNew->u.zToken[pToken->n] = 0;
-				if (dequote){
-					if (pNew->u.zToken[0] == '"')
-						pNew->flags |= EP_DblQuoted;
-					if (pNew->op == TK_ID ||
-					    pNew->op == TK_COLLATE ||
-					    pNew->op == TK_FUNCTION){
-						sqlNormalizeName(pNew->u.zToken);
-					}else{
-						sqlDequote(pNew->u.zToken);
-					}
-				}
-			}
-		}
-#if SQL_MAX_EXPR_DEPTH>0
-		pNew->nHeight = 1;
-#endif
+	struct Expr *expr = sqlDbMallocRawNN(db, sizeof(*expr) + extra_sz);
+	if (expr == NULL) {
+		diag_set(OutOfMemory, sizeof(*expr), "sqlDbMallocRawNN",
+			 "expr");
+		return NULL;
 	}
-	return pNew;
-}
 
-/*
- * Allocate a new expression node from a zero-terminated token that has
- * already been dequoted.
- */
-Expr *
-sqlExpr(sql * db,	/* Handle for sqlDbMallocZero() (may be null) */
-	    int op,		/* Expression opcode */
-	    const char *zToken	/* Token argument.  Might be NULL */
-    )
-{
-	Token x;
-	x.z = zToken;
-	x.n = zToken ? sqlStrlen30(zToken) : 0;
-	return sqlExprAlloc(db, op, &x, 0);
+	memset(expr, 0, sizeof(*expr));
+	expr->op = (u8)op;
+	expr->iAgg = -1;
+#if SQL_MAX_EXPR_DEPTH > 0
+	expr->nHeight = 1;
+#endif
+	if (token == NULL)
+		return expr;
+
+	if (extra_sz == 0) {
+		expr->flags |= EP_IntValue;
+		expr->u.iValue = val;
+	} else {
+		expr->u.zToken = (char *)&expr[1];
+		assert(token->z != NULL || token->n == 0);
+		memcpy(expr->u.zToken, token->z, token->n);
+		expr->u.zToken[token->n] = '\0';
+		if (dequote) {
+			if (expr->u.zToken[0] == '"')
+				expr->flags |= EP_DblQuoted;
+			if (expr->op == TK_ID || expr->op == TK_COLLATE ||
+			    expr->op == TK_FUNCTION)
+				sqlNormalizeName(expr->u.zToken);
+			else
+				sqlDequote(expr->u.zToken);
+		}
+	}
+	return expr;
 }
 
-/* Allocate a new expression and initialize it as integer.
- * @param db sql engine.
- * @param value Value to initialize by.
- *
- * @retval not NULL Allocated and initialized expr.
- * @retval     NULL Memory error.
- */
-Expr *
-sqlExprInteger(sql * db, int value)
+struct Expr *
+sql_op_expr_create(struct sql *db, int op, const char *name)
 {
-	Expr *ret = sqlExpr(db, TK_INTEGER, NULL);
-	if (ret != NULL) {
-		ret->flags = EP_IntValue;
-		ret->u.iValue = value;
-	}
-	return ret;
+	struct Token name_token;
+	name_token.z = name;
+	name_token.n = name != NULL ? strlen(name) : 0;
+	return sql_expr_create(db, op, &name_token, false);
 }
 
 /*
@@ -1006,8 +956,15 @@ sqlPExpr(Parse * pParse,	/* Parsing context */
 {
 	Expr *p;
 	if (op == TK_AND && pParse->nErr == 0) {
-		/* Take advantage of short-circuit false optimization for AND */
-		p = sqlExprAnd(pParse->db, pLeft, pRight);
+		/*
+		 * Take advantage of short-circuit false
+		 * optimization for AND.
+		 */
+		if (pLeft == NULL && pRight == NULL)
+			return NULL;
+		p = sql_and_expr_create(pParse->db, pLeft, pRight);
+		if (p == NULL)
+			sql_parser_error(pParse);
 	} else {
 		p = sqlDbMallocRawNN(pParse->db, sizeof(Expr));
 		if (p) {
@@ -1076,30 +1033,26 @@ exprAlwaysFalse(Expr * p)
 	return v == 0;
 }
 
-/*
- * Join two expressions using an AND operator.  If either expression is
- * NULL, then just return the other expression.
- *
- * If one side or the other of the AND is known to be false, then instead
- * of returning an AND expression, just return a constant expression with
- * a value of false.
- */
-Expr *
-sqlExprAnd(sql * db, Expr * pLeft, Expr * pRight)
+struct Expr *
+sql_and_expr_create(struct sql *db, struct Expr *left_expr,
+		    struct Expr *right_expr)
 {
-	if (pLeft == 0) {
-		return pRight;
-	} else if (pRight == 0) {
-		return pLeft;
-	} else if (exprAlwaysFalse(pLeft) || exprAlwaysFalse(pRight)) {
-		sql_expr_delete(db, pLeft, false);
-		sql_expr_delete(db, pRight, false);
-		return sqlExprAlloc(db, TK_INTEGER, &sqlIntTokens[0],
-					0);
+	if (left_expr == NULL) {
+		assert(right_expr != NULL);
+		return right_expr;
+	} else if (right_expr == NULL) {
+		assert(left_expr != NULL);
+		return left_expr;
+	} else if (exprAlwaysFalse(left_expr) || exprAlwaysFalse(right_expr)) {
+		sql_expr_delete(db, left_expr, false);
+		sql_expr_delete(db, right_expr, false);
+		return sql_expr_create(db, TK_INTEGER, &sqlIntTokens[0],
+				       false);
 	} else {
-		Expr *pNew = sqlExprAlloc(db, TK_AND, 0, 0);
-		sqlExprAttachSubtrees(db, pNew, pLeft, pRight);
-		return pNew;
+		struct Expr *new_expr =
+			sql_expr_create(db, TK_AND, NULL, false);
+		sqlExprAttachSubtrees(db, new_expr, left_expr, right_expr);
+		return new_expr;
 	}
 }
 
@@ -1110,18 +1063,18 @@ sqlExprAnd(sql * db, Expr * pLeft, Expr * pRight)
 Expr *
 sqlExprFunction(Parse * pParse, ExprList * pList, Token * pToken)
 {
-	Expr *pNew;
-	sql *db = pParse->db;
-	assert(pToken);
-	pNew = sqlExprAlloc(db, TK_FUNCTION, pToken, 1);
-	if (pNew == 0) {
-		sql_expr_list_delete(db, pList);	/* Avoid memory leak when malloc fails */
-		return 0;
+	struct sql *db = pParse->db;
+	assert(pToken != NULL);
+	struct Expr *new_expr = sql_expr_create(db, TK_FUNCTION, pToken, true);
+	if (new_expr == NULL) {
+		sql_expr_list_delete(db, pList);
+		sql_parser_error(pParse);
+		return NULL;
 	}
-	pNew->x.pList = pList;
-	assert(!ExprHasProperty(pNew, EP_xIsSelect));
-	sqlExprSetHeightAndFlags(pParse, pNew);
-	return pNew;
+	new_expr->x.pList = pList;
+	assert(!ExprHasProperty(new_expr, EP_xIsSelect));
+	sqlExprSetHeightAndFlags(pParse, new_expr);
+	return new_expr;
 }
 
 /*
@@ -2911,10 +2864,12 @@ sqlCodeSubselect(Parse * pParse,	/* Parsing context */
 			}
 			if (pSel->pLimit == NULL) {
 				pSel->pLimit =
-					sqlExprAlloc(pParse->db, TK_INTEGER,
-							 &sqlIntTokens[1],
-							 0);
-				if (pSel->pLimit != NULL) {
+					sql_expr_create(pParse->db, TK_INTEGER,
+							&sqlIntTokens[1],
+							false);
+				if (pSel->pLimit == NULL) {
+					sql_parser_error(pParse);
+				} else {
 					ExprSetProperty(pSel->pLimit,
 							EP_System);
 				}
diff --git a/src/box/sql/fk_constraint.c b/src/box/sql/fk_constraint.c
index 4f761d610..c81eb4ac1 100644
--- a/src/box/sql/fk_constraint.c
+++ b/src/box/sql/fk_constraint.c
@@ -308,32 +308,30 @@ fk_constraint_lookup_parent(struct Parse *parse_context, struct space *parent,
  * regBase is the first of an array of register that contains
  * the data for given space.  regBase+1 holds the first column.
  * regBase+2 holds the second column, and so forth.
- *
- * @param pParse Parsing and code generating context.
+ * @param parser The parsing context.
  * @param def Definition of space whose content is at r[regBase]...
- * @param regBase Contents of table defined by def.
- * @param iCol Which column of space is desired.
- * @return an Expr object that refers to a memory register
- *         corresponding to column iCol of given space.
+ * @param reg_base Contents of table table.
+ * @param column Index of table column is desired.
+ * @retval no NULL expression pointer on success.
+ * @retval NULL otherwise.
  */
-static Expr *
-space_field_register(Parse *pParse, struct space_def *def, int regBase,
-		     i16 iCol)
+static struct Expr *
+sql_register_expr_create(struct Parse *parser, struct space_def *def, int reg_base,
+			 int column)
 {
-	Expr *pExpr;
-	sql *db = pParse->db;
-
-	pExpr = sqlExpr(db, TK_REGISTER, 0);
-	if (pExpr) {
-		if (iCol >= 0) {
-			pExpr->iTable = regBase + iCol + 1;
-			pExpr->type = def->fields[iCol].type;
-		} else {
-			pExpr->iTable = regBase;
-			pExpr->type = FIELD_TYPE_INTEGER;
-		}
+	struct Expr *expr = sql_op_expr_create(parser->db, TK_REGISTER, NULL);
+	if (expr == NULL) {
+		sql_parser_error(parser);
+		return NULL;
+	}
+	if (column >= 0) {
+		expr->iTable = reg_base + column + 1;
+		expr->type = def->fields[column].type;
+	} else {
+		expr->iTable = reg_base;
+		expr->type = FIELD_TYPE_INTEGER;
 	}
-	return pExpr;
+	return expr;
 }
 
 /**
@@ -346,16 +344,17 @@ space_field_register(Parse *pParse, struct space_def *def, int regBase,
  * @retval not NULL on success.
  * @retval NULL on error.
  */
-static Expr *
-exprTableColumn(sql * db, struct space_def *def, int cursor, i16 column)
+static struct Expr *
+sql_column_cursor_expr_create(struct sql *db, struct space_def *def,
+			      int cursor, int column)
 {
-	Expr *pExpr = sqlExpr(db, TK_COLUMN, 0);
-	if (pExpr) {
-		pExpr->space_def = def;
-		pExpr->iTable = cursor;
-		pExpr->iColumn = column;
-	}
-	return pExpr;
+	struct Expr *expr = sql_op_expr_create(db, TK_COLUMN, NULL);
+	if (expr == NULL)
+		return NULL;
+	expr->space_def = def;
+	expr->iTable = cursor;
+	expr->iColumn = column;
+	return expr;
 }
 
 /*
@@ -435,12 +434,20 @@ fk_constraint_scan_children(struct Parse *parser, struct SrcList *src,
 	for (uint32_t i = 0; i < fk_def->field_count; i++) {
 		uint32_t fieldno = fk_def->links[i].parent_field;
 		struct Expr *pexpr =
-			space_field_register(parser, def, reg_data, fieldno);
+			sql_register_expr_create(parser, def, reg_data,
+						 fieldno);
 		fieldno = fk_def->links[i].child_field;
 		const char *field_name = child_space->def->fields[fieldno].name;
-		struct Expr *chexpr = sqlExpr(db, TK_ID, field_name);
+		struct Expr *chexpr =
+			sql_op_expr_create(db, TK_ID, field_name);
+		if (chexpr == NULL)
+			sql_parser_error(parser);
 		struct Expr *eq = sqlPExpr(parser, TK_EQ, pexpr, chexpr);
-		where = sqlExprAnd(db, where, eq);
+		if (where != NULL || eq != NULL) {
+			where = sql_and_expr_create(db, where, eq);
+			if (where == NULL)
+				sql_parser_error(parser);
+		}
 	}
 
 	/*
@@ -456,15 +463,26 @@ fk_constraint_scan_children(struct Parse *parser, struct SrcList *src,
 		struct Expr *expr = NULL, *pexpr, *chexpr, *eq;
 		for (uint32_t i = 0; i < fk_def->field_count; i++) {
 			uint32_t fieldno = fk_def->links[i].parent_field;
-			pexpr = space_field_register(parser, def, reg_data,
-						     fieldno);
-			chexpr = exprTableColumn(db, def, src->a[0].iCursor,
-						 fieldno);
+			pexpr = sql_register_expr_create(parser, def, reg_data,
+							 fieldno);
+			int cursor = src->a[0].iCursor;
+			chexpr = sql_column_cursor_expr_create(db, def, cursor,
+							       fieldno);
+			if (chexpr == NULL)
+				sql_parser_error(parser);
 			eq = sqlPExpr(parser, TK_EQ, pexpr, chexpr);
-			expr = sqlExprAnd(db, expr, eq);
+			if (expr != NULL || eq != NULL) {
+				expr = sql_and_expr_create(db, expr, eq);
+				if (expr == NULL)
+					sql_parser_error(parser);
+			}
 		}
 		struct Expr *pNe = sqlPExpr(parser, TK_NOT, expr, 0);
-		where = sqlExprAnd(db, where, pNe);
+		if (where != NULL || pNe != NULL) {
+			where = sql_and_expr_create(db, where, pNe);
+			if (where == NULL)
+				sql_parser_error(parser);
+		}
 	}
 
 	/* Resolve the references in the WHERE clause. */
@@ -785,14 +803,26 @@ fk_constraint_action_trigger(struct Parse *pParse, struct space_def *def,
 		 * type and collation sequence associated with
 		 * the parent table are used for the comparison.
 		 */
-		struct Expr *to_col =
-			sqlPExpr(pParse, TK_DOT,
-				     sqlExprAlloc(db, TK_ID, &t_old, 0),
-				     sqlExprAlloc(db, TK_ID, &t_to_col, 0));
-		struct Expr *from_col =
-			sqlExprAlloc(db, TK_ID, &t_from_col, 0);
-		struct Expr *eq = sqlPExpr(pParse, TK_EQ, to_col, from_col);
-		where = sqlExprAnd(db, where, eq);
+		struct Expr *old_expr = NULL, *new_expr = NULL, *expr = NULL;
+		old_expr = sql_expr_create(db, TK_ID, &t_old, false);
+		if (old_expr == NULL)
+			sql_parser_error(pParse);
+		expr = sql_expr_create(db, TK_ID, &t_to_col, false);
+		if (expr == NULL)
+			sql_parser_error(pParse);
+		struct Expr *from_col_expr =
+			sql_expr_create(db, TK_ID, &t_from_col, false);
+		if (from_col_expr == NULL)
+			sql_parser_error(pParse);
+		struct Expr *to_col_expr =
+			sqlPExpr(pParse, TK_DOT, old_expr, expr);
+		struct Expr *eq =
+			sqlPExpr(pParse, TK_EQ, to_col_expr, from_col_expr);
+		if (where != NULL || eq != NULL) {
+			where = sql_and_expr_create(db, where, eq);
+			if (where == NULL)
+				sql_parser_error(pParse);
+		}
 
 		/*
 		 * For ON UPDATE, construct the next term of the
@@ -810,12 +840,22 @@ fk_constraint_action_trigger(struct Parse *pParse, struct space_def *def,
 		 *        no_action_needed(colN))
 		 */
 		if (is_update) {
+			old_expr = sql_expr_create(db, TK_ID, &t_old, false);
+			if (old_expr == NULL)
+				sql_parser_error(pParse);
+			expr = sql_expr_create(db, TK_ID, &t_to_col, false);
+			if (expr == NULL)
+				sql_parser_error(pParse);
 			struct Expr *old_val = sqlPExpr(pParse, TK_DOT,
-				sqlExprAlloc(db, TK_ID, &t_old, 0),
-				sqlExprAlloc(db, TK_ID, &t_to_col, 0));
+							old_expr, expr);
+			new_expr = sql_expr_create(db, TK_ID, &t_new, false);
+			if (new_expr == NULL)
+				sql_parser_error(pParse);
+			expr = sql_expr_create(db, TK_ID, &t_to_col, false);
+			if (expr == NULL)
+				sql_parser_error(pParse);
 			struct Expr *new_val = sqlPExpr(pParse, TK_DOT,
-				sqlExprAlloc(db, TK_ID, &t_new, 0),
-				sqlExprAlloc(db, TK_ID, &t_to_col, 0));
+							new_expr, expr);
 			struct Expr *old_is_null = sqlPExpr(
 				pParse, TK_ISNULL,
 				sqlExprDup(db, old_val, 0), NULL);
@@ -828,29 +868,41 @@ fk_constraint_action_trigger(struct Parse *pParse, struct space_def *def,
 			struct Expr *no_action_needed =
 				sqlPExpr(pParse, TK_OR, old_is_null,
 					     non_null_eq);
-			when = sqlExprAnd(db, when, no_action_needed);
+			if (when != NULL || no_action_needed != NULL) {
+				when = sql_and_expr_create(db, when,
+							   no_action_needed);
+				if (when == NULL)
+					sql_parser_error(pParse);
+			}
 		}
 
 		if (action != FKEY_ACTION_RESTRICT &&
 		    (action != FKEY_ACTION_CASCADE || is_update)) {
 			struct Expr *new, *d;
 			if (action == FKEY_ACTION_CASCADE) {
-				new = sqlPExpr(pParse, TK_DOT,
-						   sqlExprAlloc(db, TK_ID,
-								    &t_new, 0),
-						   sqlExprAlloc(db, TK_ID,
-								    &t_to_col,
-								    0));
+				new_expr = sql_expr_create(db, TK_ID, &t_new,
+							   false);
+				if (new_expr == NULL)
+					sql_parser_error(pParse);
+				expr = sql_expr_create(db, TK_ID, &t_to_col,
+						       false);
+				if (expr == NULL)
+					sql_parser_error(pParse);
+				new = sqlPExpr(pParse, TK_DOT, new_expr, expr);
 			} else if (action == FKEY_ACTION_SET_DEFAULT) {
 				d = child_fields[chcol].default_value_expr;
 				if (d != NULL) {
 					new = sqlExprDup(db, d, 0);
 				} else {
-					new = sqlExprAlloc(db, TK_NULL,
-							       NULL, 0);
+					new = sql_expr_create(db, TK_NULL,
+							      NULL, false);
+					if (new == NULL)
+						sql_parser_error(pParse);
 				}
 			} else {
-				new = sqlExprAlloc(db, TK_NULL, NULL, 0);
+				new = sql_expr_create(db, TK_NULL, NULL, false);
+				if (new == NULL)
+					sql_parser_error(pParse);
 			}
 			list = sql_expr_list_append(db, list, new);
 			sqlExprListSetName(pParse, list, &t_from_col, 0);
@@ -864,9 +916,12 @@ fk_constraint_action_trigger(struct Parse *pParse, struct space_def *def,
 		struct Token err;
 		err.z = space_name;
 		err.n = name_len;
-		struct Expr *r = sqlExpr(db, TK_RAISE, "FOREIGN KEY "\
-					     "constraint failed");
-		if (r != NULL)
+		struct Expr *r =
+			sql_op_expr_create(db, TK_RAISE,
+					   "FOREIGN KEY constraint failed");
+		if (r == NULL)
+			sql_parser_error(pParse);
+		else
 			r->on_conflict_action = ON_CONFLICT_ACTION_ABORT;
 		struct SrcList *src_list = sql_src_list_append(db, NULL, &err);
 		if (src_list == NULL)
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index db03714a9..d25995ec0 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -529,12 +529,16 @@ selcollist(A) ::= sclp(A) expr(X) as(Y).     {
    sqlExprListSetSpan(pParse,A,&X);
 }
 selcollist(A) ::= sclp(A) STAR. {
-  Expr *p = sqlExpr(pParse->db, TK_ASTERISK, 0);
+  struct Expr *p = sql_op_expr_create(pParse->db, TK_ASTERISK, NULL);
+  if (p == NULL)
+    sql_parser_error(pParse);
   A = sql_expr_list_append(pParse->db, A, p);
 }
 selcollist(A) ::= sclp(A) nm(X) DOT STAR. {
   Expr *pRight = sqlPExpr(pParse, TK_ASTERISK, 0, 0);
-  Expr *pLeft = sqlExprAlloc(pParse->db, TK_ID, &X, 1);
+  struct Expr *pLeft = sql_expr_create(pParse->db, TK_ID, &X, true);
+  if (pLeft == NULL)
+    sql_parser_error(pParse);
   Expr *pDot = sqlPExpr(pParse, TK_DOT, pLeft, pRight);
   A = sql_expr_list_append(pParse->db,A, pDot);
 }
@@ -887,15 +891,21 @@ term(A) ::= NULL(X).        {spanExpr(&A,pParse, at X,X);/*A-overwrites-X*/}
 expr(A) ::= id(X).          {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
 expr(A) ::= JOIN_KW(X).     {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
 expr(A) ::= nm(X) DOT nm(Y). {
-  Expr *temp1 = sqlExprAlloc(pParse->db, TK_ID, &X, 1);
-  Expr *temp2 = sqlExprAlloc(pParse->db, TK_ID, &Y, 1);
+  struct Expr *temp1 = sql_expr_create(pParse->db, TK_ID, &X, true);
+  if (temp1 == NULL)
+    sql_parser_error(pParse);
+  struct Expr *temp2 = sql_expr_create(pParse->db, TK_ID, &Y, true);
+  if (temp2 == NULL)
+    sql_parser_error(pParse);
   spanSet(&A,&X,&Y); /*A-overwrites-X*/
   A.pExpr = sqlPExpr(pParse, TK_DOT, temp1, temp2);
 }
 term(A) ::= FLOAT|BLOB(X). {spanExpr(&A,pParse, at X,X);/*A-overwrites-X*/}
 term(A) ::= STRING(X).     {spanExpr(&A,pParse, at X,X);/*A-overwrites-X*/}
 term(A) ::= INTEGER(X). {
-  A.pExpr = sqlExprAlloc(pParse->db, TK_INTEGER, &X, 1);
+  A.pExpr = sql_expr_create(pParse->db, TK_INTEGER, &X, true);
+  if (A.pExpr == NULL)
+    sql_parser_error(pParse);
   A.pExpr->type = FIELD_TYPE_INTEGER;
   A.zStart = X.z;
   A.zEnd = X.z + X.n;
@@ -928,7 +938,9 @@ expr(A) ::= expr(A) COLLATE id(C). {
 %ifndef SQL_OMIT_CAST
 expr(A) ::= CAST(X) LP expr(E) AS typedef(T) RP(Y). {
   spanSet(&A,&X,&Y); /*A-overwrites-X*/
-  A.pExpr = sqlExprAlloc(pParse->db, TK_CAST, 0, 1);
+  A.pExpr = sql_expr_create(pParse->db, TK_CAST, NULL, true);
+  if (A.pExpr == NULL)
+    sql_parser_error(pParse);
   A.pExpr->type = T.type;
   sqlExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0);
 }
@@ -1118,7 +1130,9 @@ expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] {
     ** regardless of the value of expr1.
     */
     sql_expr_delete(pParse->db, A.pExpr, false);
-    A.pExpr = sqlExprAlloc(pParse->db, TK_INTEGER,&sqlIntTokens[N],1);
+    A.pExpr = sql_expr_create(pParse->db, TK_INTEGER, &sqlIntTokens[N], true);
+    if (A.pExpr == NULL)
+      sql_parser_error(pParse);
   }else if( Y->nExpr==1 ){
     /* Expressions of the form:
     **
@@ -1462,10 +1476,11 @@ expr(A) ::= RAISE(X) LP IGNORE RP(Y).  {
 }
 expr(A) ::= RAISE(X) LP raisetype(T) COMMA STRING(Z) RP(Y).  {
   spanSet(&A,&X,&Y);  /*A-overwrites-X*/
-  A.pExpr = sqlExprAlloc(pParse->db, TK_RAISE, &Z, 1);
-  if( A.pExpr ) {
+  A.pExpr = sql_expr_create(pParse->db, TK_RAISE, &Z, true);
+  if(A.pExpr == NULL)
+    sql_parser_error(pParse);
+  else
     A.pExpr->on_conflict_action = (enum on_conflict_action) T;
-  }
 }
 
 %type raisetype {int}
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index aed9e261d..3731aee31 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -487,26 +487,20 @@ lookupName(Parse * pParse,	/* The parsing context */
 	}
 }
 
-/*
- * Allocate and return a pointer to an expression to load the column iCol
- * from datasource iSrc in SrcList pSrc.
- */
-Expr *
-sqlCreateColumnExpr(sql * db, SrcList * pSrc, int iSrc, int iCol)
+struct Expr *
+sql_column_expr_create(struct sql *db, struct SrcList *src_list, int src_idx,
+		       int column)
 {
-	Expr *p = sqlExprAlloc(db, TK_COLUMN, 0, 0);
-	if (p) {
-		struct SrcList_item *pItem = &pSrc->a[iSrc];
-		p->space_def = pItem->space->def;
-		p->iTable = pItem->iCursor;
-		p->iColumn = (ynVar) iCol;
-		testcase(iCol == BMS);
-		testcase(iCol == BMS - 1);
-		pItem->colUsed |=
-			((Bitmask) 1) << (iCol >= BMS ? BMS - 1 : iCol);
-		ExprSetProperty(p, EP_Resolved);
-	}
-	return p;
+	struct Expr *expr = sql_expr_create(db, TK_COLUMN, NULL, false);
+	if (expr == NULL)
+		return NULL;
+	struct SrcList_item *item = &src_list->a[src_idx];
+	expr->space_def = item->space->def;
+	expr->iTable = item->iCursor;
+	expr->iColumn = column;
+	item->colUsed |= ((Bitmask) 1) << (column >= BMS ? BMS - 1 : column);
+	ExprSetProperty(expr, EP_Resolved);
+	return expr;
 }
 
 /*
@@ -1000,9 +994,13 @@ resolveCompoundOrderBy(Parse * pParse,	/* Parsing context.  Leave error messages
 				/* Convert the ORDER BY term into an integer column number iCol,
 				 * taking care to preserve the COLLATE clause if it exists
 				 */
-				Expr *pNew = sqlExpr(db, TK_INTEGER, 0);
-				if (pNew == 0)
+				Expr *pNew =
+					sql_op_expr_create(db, TK_INTEGER,
+							   NULL);
+				if (pNew == NULL) {
+					sql_parser_error(pParse);
 					return 1;
+				}
 				pNew->flags |= EP_IntValue;
 				pNew->u.iValue = iCol;
 				if (pItem->pExpr == pE) {
@@ -1348,9 +1346,10 @@ resolveSelectStep(Walker * pWalker, Select * p)
 			 * restrict it directly).
 			 */
 			sql_expr_delete(db, p->pLimit, false);
-			p->pLimit =
-			    sqlExprAlloc(db, TK_INTEGER,
-					     &sqlIntTokens[1], 0);
+			p->pLimit = sql_expr_create(db, TK_INTEGER,
+						    &sqlIntTokens[1], false);
+			if (p->pLimit == NULL)
+				sql_parser_error(pParse);
 		} else {
 			if (sqlResolveExprNames(&sNC, p->pHaving))
 				return WRC_Abort;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index 7eea45dd7..2ae27e6c4 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -164,8 +164,11 @@ sqlSelectNew(Parse * pParse,	/* Parsing context */
 		pNew = &standin;
 	}
 	if (pEList == 0) {
-		pEList = sql_expr_list_append(pParse->db, NULL,
-					      sqlExpr(db, TK_ASTERISK, 0));
+		struct Expr *expr =
+			sql_op_expr_create(db, TK_ASTERISK, NULL);
+		if (expr == NULL)
+			sql_parser_error(pParse);
+		pEList = sql_expr_list_append(pParse->db, NULL, expr);
 	}
 	struct session MAYBE_UNUSED *user_session;
 	user_session = current_session();
@@ -486,7 +489,6 @@ addWhereTerm(Parse * pParse,	/* Parsing context */
 	     int isOuterJoin,	/* True if this is an OUTER join */
 	     Expr ** ppWhere)	/* IN/OUT: The WHERE clause to add to */
 {
-	sql *db = pParse->db;
 	Expr *pE1;
 	Expr *pE2;
 	Expr *pEq;
@@ -496,8 +498,12 @@ addWhereTerm(Parse * pParse,	/* Parsing context */
 	assert(pSrc->a[iLeft].space != NULL);
 	assert(pSrc->a[iRight].space != NULL);
 
-	pE1 = sqlCreateColumnExpr(db, pSrc, iLeft, iColLeft);
-	pE2 = sqlCreateColumnExpr(db, pSrc, iRight, iColRight);
+	pE1 = sql_column_expr_create(pParse->db, pSrc, iLeft, iColLeft);
+	if (pE1 == NULL)
+		sql_parser_error(pParse);
+	pE2 = sql_column_expr_create(pParse->db, pSrc, iRight, iColRight);
+	if (pE2 == NULL)
+		sql_parser_error(pParse);
 
 	pEq = sqlPExpr(pParse, TK_EQ, pE1, pE2);
 	if (pEq && isOuterJoin) {
@@ -506,7 +512,12 @@ addWhereTerm(Parse * pParse,	/* Parsing context */
 		ExprSetVVAProperty(pEq, EP_NoReduce);
 		pEq->iRightJoinTable = (i16) pE2->iTable;
 	}
-	*ppWhere = sqlExprAnd(db, *ppWhere, pEq);
+	if (*ppWhere != NULL || pEq != NULL) {
+		*ppWhere = sql_and_expr_create(pParse->db, *ppWhere, pEq);
+		if (*ppWhere == NULL)
+			sql_parser_error(pParse);
+	}
+	return;
 }
 
 /*
@@ -627,8 +638,13 @@ sqlProcessJoin(Parse * pParse, Select * p)
 		if (pRight->pOn) {
 			if (isOuter)
 				setJoinExpr(pRight->pOn, pRight->iCursor);
-			p->pWhere =
-			    sqlExprAnd(pParse->db, p->pWhere, pRight->pOn);
+			if (p->pWhere != NULL || pRight->pOn != NULL) {
+				p->pWhere = sql_and_expr_create(pParse->db,
+								p->pWhere,
+								pRight->pOn);
+				if (p->pWhere == NULL)
+					sql_parser_error(pParse);
+			}
 			pRight->pOn = 0;
 		}
 
@@ -3332,9 +3348,13 @@ multiSelectOrderBy(Parse * pParse,	/* Parsing context */
 					break;
 			}
 			if (j == nOrderBy) {
-				Expr *pNew = sqlExpr(db, TK_INTEGER, 0);
-				if (pNew == 0)
+				Expr *pNew =
+					sql_op_expr_create(db, TK_INTEGER,
+							   NULL);
+				if (pNew == NULL) {
+					sql_parser_error(pParse);
 					return SQL_NOMEM_BKPT;
+				}
 				pNew->flags |= EP_IntValue;
 				pNew->u.iValue = i;
 				pOrderBy = sql_expr_list_append(pParse->db,
@@ -4207,17 +4227,23 @@ flattenSubquery(Parse * pParse,		/* Parsing context */
 			assert(pParent->pHaving == 0);
 			pParent->pHaving = pParent->pWhere;
 			pParent->pWhere = pWhere;
-			pParent->pHaving = sqlExprAnd(db,
-							  sqlExprDup(db,
-									 pSub->pHaving,
-									 0),
-							  pParent->pHaving);
+			struct Expr *sub_having = sqlExprDup(db, pSub->pHaving, 0);
+			if (sub_having != NULL || pParent->pHaving != NULL) {
+				pParent->pHaving =
+					sql_and_expr_create(db, sub_having,
+							    pParent->pHaving);
+				if (pParent->pHaving == NULL)
+					sql_parser_error(pParse);
+			}
 			assert(pParent->pGroupBy == 0);
 			pParent->pGroupBy =
 			    sql_expr_list_dup(db, pSub->pGroupBy, 0);
-		} else {
+		} else if (pWhere != NULL || pParent->pWhere != NULL) {
 			pParent->pWhere =
-			    sqlExprAnd(db, pWhere, pParent->pWhere);
+				sql_and_expr_create(db, pWhere,
+						    pParent->pWhere);
+			if (pParent->pWhere == NULL)
+				sql_parser_error(pParse);
 		}
 		substSelect(pParse, pParent, iParent, pSub->pEList, 0);
 
@@ -4322,8 +4348,14 @@ pushDownWhereTerms(Parse * pParse,	/* Parse context (for malloc() and error repo
 		while (pSubq) {
 			pNew = sqlExprDup(pParse->db, pWhere, 0);
 			pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
-			pSubq->pWhere =
-			    sqlExprAnd(pParse->db, pSubq->pWhere, pNew);
+			if (pSubq->pWhere != NULL || pNew != NULL) {
+				pSubq->pWhere =
+					sql_and_expr_create(pParse->db,
+							    pSubq->pWhere,
+							    pNew);
+				if (pSubq->pWhere == NULL)
+					sql_parser_error(pParse);
+			}
 			pSubq = pSubq->pPrior;
 		}
 	}
@@ -4505,8 +4537,10 @@ convertCompoundSelectToSubquery(Walker * pWalker, Select * p)
 		return WRC_Abort;
 	*pNew = *p;
 	p->pSrc = pNewSrc;
-	p->pEList = sql_expr_list_append(pParse->db, NULL,
-					 sqlExpr(db, TK_ASTERISK, 0));
+	struct Expr *expr = sql_op_expr_create(db, TK_ASTERISK, NULL);
+	if (expr == NULL)
+		sql_parser_error(pParse);
+	p->pEList = sql_expr_list_append(pParse->db, NULL, expr);
 	p->op = TK_SELECT;
 	p->pWhere = 0;
 	pNew->pGroupBy = 0;
@@ -4990,18 +5024,24 @@ selectExpander(Walker * pWalker, Select * p)
 								continue;
 							}
 						}
-						pRight =
-						    sqlExpr(db, TK_ID,
+						pRight = sql_op_expr_create(
+								db, TK_ID,
 								zName);
+						if (pRight == NULL)
+							sql_parser_error(pParse);
 						zColname = zName;
 						zToFree = 0;
 						if (longNames
 						    || pTabList->nSrc > 1) {
 							Expr *pLeft;
-							pLeft =
-							    sqlExpr(db,
+							pLeft = sql_op_expr_create(
+									db,
 									TK_ID,
 									zTabName);
+							if (pLeft == NULL) {
+								sql_parser_error(
+									pParse);
+							}
 							pExpr =
 							    sqlPExpr(pParse,
 									 TK_DOT,
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 531445f33..82aad0077 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3254,13 +3254,70 @@ void sqlClearTempRegCache(Parse *);
 #ifdef SQL_DEBUG
 int sqlNoTempsInRange(Parse *, int, int);
 #endif
-Expr *sqlExprAlloc(sql *, int, const Token *, int);
-Expr *sqlExpr(sql *, int, const char *);
-Expr *sqlExprInteger(sql *, int);
+
+/*
+ * This routine is the core allocator for Expr nodes.
+ * Construct a new expression node and return a pointer to it.
+ * Memory for this node and for the token argument is a single
+ * allocation obtained from sqlDbMalloc(). The calling function
+ * is responsible for making sure the node eventually gets freed.
+ *
+ * If dequote is true, then the token (if it exists) is dequoted.
+ * If dequote is false, no dequoting is performed.  The deQuote
+ * parameter is ignored if token is NULL or if the token does
+ * not appear to be quoted. If the quotes were of the form "..."
+ * (double-quotes) then the EP_DblQuoted flag is set on the
+ * expression node.
+ *
+ * Special case: If op==TK_INTEGER and token points to a string
+ * that can be translated into a 32-bit integer, then the token is
+ * not stored in u.zToken. Instead, the integer values is written
+ * into u.iValue and the EP_IntValue flag is set. No extra storage
+ * is allocated to hold the integer text and the dequote flag is
+ * ignored.
+ * @param db The database connection.
+ * @param op Expression opcode (TK_*).
+ * @param token Source token. Might be NULL.
+ * @param dequote True to dequote string.
+ * @retval not NULL new expression object on success.
+ * @retval NULL otherwise.
+ */
+struct Expr *
+sql_expr_create(struct sql *db, int op, const Token *token, bool dequote);
+
+/*
+ * Allocate a new expression node from a zero-terminated token
+ * that has already been dequoted.
+ * @param db The database connection.
+ * @param op Expression opcode.
+ * @param name The object name string.
+ * @retval not NULL expression pointer on success.
+ * @retval NULL otherwise.
+ */
+struct Expr *
+sql_op_expr_create(struct sql *db, int op, const char *name);
+
 void sqlExprAttachSubtrees(sql *, Expr *, Expr *, Expr *);
 Expr *sqlPExpr(Parse *, int, Expr *, Expr *);
 void sqlPExprAddSelect(Parse *, Expr *, Select *);
-Expr *sqlExprAnd(sql *, Expr *, Expr *);
+
+/*
+ * Join two expressions using an AND operator.  If either
+ * expression is NULL, then just return the other expression.
+ *
+ * If one side or the other of the AND is known to be false, then
+ * instead of returning an AND expression, just return a constant
+ * expression with a value of false.
+ * @param db The database connection.
+ * @param left_expr The left-branch expresion to join.
+ * @param right_expr The right-branch expression to join.
+ * @retval not NULL new expression root node pointer on success.
+ * @retval NULL otherwise.
+ */
+struct Expr *
+sql_and_expr_create(struct sql *db, struct Expr *left_expr,
+		    struct Expr *right_expr);
+
 Expr *sqlExprFunction(Parse *, ExprList *, Token *);
 void sqlExprAssignVarNumber(Parse *, Expr *, u32);
 ExprList *sqlExprListAppendVector(Parse *, ExprList *, IdList *, Expr *);
@@ -4724,7 +4781,20 @@ void sqlAppendChar(StrAccum *, int, char);
 char *sqlStrAccumFinish(StrAccum *);
 void sqlStrAccumReset(StrAccum *);
 void sqlSelectDestInit(SelectDest *, int, int, int);
-Expr *sqlCreateColumnExpr(sql *, SrcList *, int, int);
+
+/*
+ * Allocate and return a pointer to an expression to load the
+ * column from datasource src_idx in SrcList src_list.
+ * @param db The database connection.
+ * @param src_list The source list described with FROM clause.
+ * @param src_idx The resource index to use in src_list.
+ * @param column The column index.
+ * @retval not NULL expression pointer on success.
+ * @retval NULL otherwise.
+ */
+struct Expr *
+sql_column_expr_create(struct sql *db, struct SrcList *src_list,
+		       int src_idx, int column);
 
 int sqlExprCheckIN(Parse *, Expr *);
 
diff --git a/src/box/sql/wherecode.c b/src/box/sql/wherecode.c
index 04b79ab36..01ecb9464 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -1437,7 +1437,14 @@ sqlWhereCodeOneLoopStart(WhereInfo * pWInfo,	/* Complete information about the W
 					continue;
 				testcase(pWC->a[iTerm].wtFlags & TERM_ORINFO);
 				pExpr = sqlExprDup(db, pExpr, 0);
-				pAndExpr = sqlExprAnd(db, pAndExpr, pExpr);
+				if (pAndExpr != NULL || pExpr != NULL) {
+					pAndExpr =
+						sql_and_expr_create(db,
+								    pAndExpr,
+								    pExpr);
+					if (pAndExpr == NULL)
+						sql_parser_error(pParse);
+				}
 			}
 			if (pAndExpr) {
 				pAndExpr =
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index fa906e305..c2213f229 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -307,8 +307,10 @@ like_optimization_is_valid(Parse *pParse, Expr *pExpr, Expr **ppPrefix,
 			Expr *pPrefix;
 			*pisComplete = c == MATCH_ALL_WILDCARD &&
 				       z[cnt + 1] == 0;
-			pPrefix = sqlExpr(db, TK_STRING, z);
-			if (pPrefix)
+			pPrefix = sql_op_expr_create(db, TK_STRING, z);
+			if (pPrefix == NULL)
+				sql_parser_error(pParse);
+			else
 				pPrefix->u.zToken[cnt] = 0;
 			*ppPrefix = pPrefix;
 			if (op == TK_VARIABLE) {
@@ -1306,10 +1308,12 @@ exprAnalyze(SrcList * pSrc,	/* the FROM clause */
 		Expr *pLeft = pExpr->pLeft;
 		int idxNew;
 		WhereTerm *pNewTerm;
-
-		pNewExpr = sqlPExpr(pParse, TK_GT,
-					sqlExprDup(db, pLeft, 0),
-					sqlExprAlloc(db, TK_NULL, 0, 0));
+		struct Expr *expr =
+			sql_expr_create(db, TK_NULL, NULL, false);
+		if (expr == NULL)
+			sql_parser_error(pParse);
+		pNewExpr = sqlPExpr(pParse, TK_GT, sqlExprDup(db, pLeft, 0),
+				    expr);
 
 		idxNew = whereClauseInsert(pWC, pNewExpr,
 					   TERM_VIRTUAL | TERM_DYNAMIC |
@@ -1502,9 +1506,11 @@ sqlWhereTabFuncArgs(Parse * pParse,	/* Parsing context */
 					space_def->name, j);
 			return;
 		}
-		pColRef = sqlExprAlloc(pParse->db, TK_COLUMN, 0, 0);
-		if (pColRef == 0)
+		pColRef = sql_expr_create(pParse->db, TK_COLUMN, NULL, false);
+		if (pColRef == NULL) {
+			sql_parser_error(pParse);
 			return;
+		}
 		pColRef->iTable = pItem->iCursor;
 		pColRef->iColumn = k++;
 		pColRef->space_def = space_def;
-- 
2.20.1







More information about the Tarantool-patches mailing list