[tarantool-patches] [PATCH v1 3/4] sql: patch sql_expr_create routine to use Parser
Kirill Shcherbatov
kshcherbatov at tarantool.org
Fri Feb 15 16:30:50 MSK 2019
The code was refactored so that the sql_expr_create function
would use the parser object instead of database connection. Also
performed some additional names refactoring in adjacent places.
Needed for #3931
---
src/box/sql/build.c | 18 ++--
src/box/sql/expr.c | 202 +++++++++++++++-------------------------
src/box/sql/fkey.c | 124 ++++++++++++------------
src/box/sql/parse.y | 16 ++--
src/box/sql/resolve.c | 41 ++++----
src/box/sql/select.c | 46 +++++----
src/box/sql/sqlInt.h | 79 +++++++++++++++-
src/box/sql/wherecode.c | 3 +-
src/box/sql/whereexpr.c | 10 +-
9 files changed, 283 insertions(+), 256 deletions(-)
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index 3f4530620..a08148a97 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -691,8 +691,8 @@ sqlAddPrimaryKey(Parse * pParse, /* Parsing context */
struct Token token;
sqlTokenInit(&token, pTab->def->fields[iCol].name);
list = sql_expr_list_append(db, NULL,
- sqlExprAlloc(db, TK_ID,
- &token, 0));
+ sql_expr_create(pParse, TK_ID,
+ &token, false));
if (list == NULL)
goto primary_key_exit;
sql_create_index(pParse, 0, 0, list, 0, SORT_ORDER_ASC,
@@ -1455,10 +1455,11 @@ sql_id_eq_str_expr(struct Parse *parse, const char *col_name,
{
struct sql *db = parse->db;
- struct Expr *col_name_expr = sqlExpr(db, TK_ID, col_name);
+ struct Expr *col_name_expr = sql_op_expr_create(parse, TK_ID, col_name);
if (col_name_expr == NULL)
return NULL;
- struct Expr *col_value_expr = sqlExpr(db, TK_STRING, col_value);
+ struct Expr *col_value_expr =
+ sql_op_expr_create(parse, TK_STRING, col_value);
if (col_value_expr == NULL) {
sql_expr_delete(db, col_name_expr, false);
return NULL;
@@ -1480,12 +1481,12 @@ vdbe_emit_stat_space_clear(struct Parse *parse, const char *stat_table_name,
if (idx_name != NULL) {
struct Expr *expr = sql_id_eq_str_expr(parse, "idx", idx_name);
if (expr != NULL)
- where = sqlExprAnd(db, expr, where);
+ where = sql_and_expr_create(parse, expr, where);
}
if (table_name != NULL) {
struct Expr *expr = sql_id_eq_str_expr(parse, "tbl", table_name);
if (expr != NULL)
- where = sqlExprAnd(db, expr, where);
+ where = sql_and_expr_create(parse, expr, where);
}
/**
* On memory allocation error sql_table delete_from
@@ -2339,8 +2340,9 @@ sql_create_index(struct Parse *parse, struct Token *token,
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));
+ sql_expr_create(parse, TK_ID,
+ &prev_col,
+ false));
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 a6e35df6d..42531c107 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -151,8 +151,7 @@ sqlExprAddCollateToken(Parse * pParse, /* Parsing context */
{
if (pCollName->n > 0) {
Expr *pNew =
- sqlExprAlloc(pParse->db, TK_COLLATE, pCollName,
- dequote);
+ sql_expr_create(pParse, TK_COLLATE, pCollName, dequote);
if (pNew) {
pNew->pLeft = pExpr;
pNew->flags |= EP_Collate | EP_Skip;
@@ -795,113 +794,60 @@ 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 Parse *parser, 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;
+ struct Expr *expr =
+ sqlDbMallocRawNN(parser->db, sizeof(*expr) + extra_sz);
+ if (expr == NULL)
+ return NULL;
+
+ memset(expr, 0, sizeof(*expr));
+ expr->op = (u8)op;
+ expr->iAgg = -1;
+#if SQL_MAX_EXPR_DEPTH > 0
+ expr->nHeight = 1;
#endif
- }
- return pNew;
-}
+ if (token == NULL)
+ return expr;
-/*
- * 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);
+ 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 Parse *parser, 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(parser, op, &name_token, false);
}
/*
@@ -947,8 +893,11 @@ 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.
+ */
+ p = sql_and_expr_create(pParse, pLeft, pRight);
} else {
p = sqlDbMallocRawNN(pParse->db, sizeof(Expr));
if (p) {
@@ -1017,30 +966,25 @@ 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 Parse *parser, 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) {
+ return right_expr;
+ } else if (right_expr == NULL) {
+ return left_expr;
+ } else if (exprAlwaysFalse(left_expr) || exprAlwaysFalse(right_expr)) {
+ sql_expr_delete(parser->db, left_expr, false);
+ sql_expr_delete(parser->db, right_expr, false);
+ return sql_expr_create(parser, 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(parser, TK_AND, NULL, false);
+ sqlExprAttachSubtrees(parser->db, new_expr, left_expr,
+ right_expr);
+ return new_expr;
}
}
@@ -1054,7 +998,7 @@ sqlExprFunction(Parse * pParse, ExprList * pList, Token * pToken)
Expr *pNew;
sql *db = pParse->db;
assert(pToken);
- pNew = sqlExprAlloc(db, TK_FUNCTION, pToken, 1);
+ pNew = sql_expr_create(pParse, TK_FUNCTION, pToken, true);
if (pNew == 0) {
sql_expr_list_delete(db, pList); /* Avoid memory leak when malloc fails */
return 0;
@@ -2860,9 +2804,9 @@ sqlCodeSubselect(Parse * pParse, /* Parsing context */
}
if (pSel->pLimit == NULL) {
pSel->pLimit =
- sqlExprAlloc(pParse->db, TK_INTEGER,
- &sqlIntTokens[1],
- 0);
+ sql_expr_create(pParse, TK_INTEGER,
+ &sqlIntTokens[1],
+ false);
if (pSel->pLimit != NULL) {
ExprSetProperty(pSel->pLimit,
EP_System);
diff --git a/src/box/sql/fkey.c b/src/box/sql/fkey.c
index 69740b39f..8edafe149 100644
--- a/src/box/sql/fkey.c
+++ b/src/box/sql/fkey.c
@@ -308,50 +308,51 @@ fkey_lookup_parent(struct Parse *parse_context, struct space *parent,
* regBase is the first of an array of register that contains the data
* for pTab. regBase+1 holds the first column.
* regBase+2 holds the second column, and so forth.
+ * @param parser The parsing context.
+ * @param table The table whose content is at r[regBase]...
+ * @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 *
-exprTableRegister(Parse * pParse, /* Parsing and code generating context */
- Table * pTab, /* The table whose content is at r[regBase]... */
- int regBase, /* Contents of table pTab */
- i16 iCol /* Which column of pTab is desired */
- )
+static struct Expr *
+sql_register_expr_create(struct Parse *parser, struct Table *table,
+ 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 = pTab->def->fields[iCol].type;
- } else {
- pExpr->iTable = regBase;
- pExpr->type = FIELD_TYPE_INTEGER;
- }
+ struct Expr *expr = sql_op_expr_create(parser, TK_REGISTER, NULL);
+ if (expr == NULL)
+ return NULL;
+ if (column >= 0) {
+ expr->iTable = reg_base + column + 1;
+ expr->type = table->def->fields[column].type;
+ } else {
+ expr->iTable = reg_base;
+ expr->type = FIELD_TYPE_INTEGER;
}
- return pExpr;
+ return expr;
}
/**
* Return an Expr object that refers to column of space_def which
* has cursor cursor.
- * @param db The database connection.
+ * @param parser The parsing context.
* @param def space definition.
* @param cursor The open cursor on the table.
* @param column The column that is wanted.
* @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 Parse *parser, 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(parser, TK_COLUMN, NULL);
+ if (expr == NULL)
+ return NULL;
+ expr->space_def = def;
+ expr->iTable = cursor;
+ expr->iColumn = column;
+ return expr;
}
/*
@@ -430,12 +431,14 @@ fkey_scan_children(struct Parse *parser, struct SrcList *src, struct Table *tab,
for (uint32_t i = 0; i < fkey->field_count; i++) {
uint32_t fieldno = fkey->links[i].parent_field;
struct Expr *pexpr =
- exprTableRegister(parser, tab, reg_data, fieldno);
+ sql_register_expr_create(parser, tab, reg_data,
+ fieldno);
fieldno = fkey->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(parser, TK_ID, field_name);
struct Expr *eq = sqlPExpr(parser, TK_EQ, pexpr, chexpr);
- where = sqlExprAnd(db, where, eq);
+ where = sql_and_expr_create(parser, where, eq);
}
/*
@@ -451,15 +454,16 @@ fkey_scan_children(struct Parse *parser, struct SrcList *src, struct Table *tab,
struct Expr *expr = NULL, *pexpr, *chexpr, *eq;
for (uint32_t i = 0; i < fkey->field_count; i++) {
uint32_t fieldno = fkey->links[i].parent_field;
- pexpr = exprTableRegister(parser, tab, reg_data,
- fieldno);
- chexpr = exprTableColumn(db, tab->def,
- src->a[0].iCursor, fieldno);
+ pexpr = sql_register_expr_create(parser, tab, reg_data,
+ fieldno);
+ int cursor = src->a[0].iCursor;
+ chexpr = sql_column_cursor_expr_create(parser, tab->def,
+ cursor, fieldno);
eq = sqlPExpr(parser, TK_EQ, pexpr, chexpr);
- expr = sqlExprAnd(db, expr, eq);
+ expr = sql_and_expr_create(parser, expr, eq);
}
struct Expr *pNe = sqlPExpr(parser, TK_NOT, expr, 0);
- where = sqlExprAnd(db, where, pNe);
+ where = sql_and_expr_create(parser, where, pNe);
}
/* Resolve the references in the WHERE clause. */
@@ -788,12 +792,13 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey,
*/
struct Expr *to_col =
sqlPExpr(pParse, TK_DOT,
- sqlExprAlloc(db, TK_ID, &t_old, 0),
- sqlExprAlloc(db, TK_ID, &t_to_col, 0));
+ sql_expr_create(pParse, TK_ID, &t_old, false),
+ sql_expr_create(pParse, TK_ID, &t_to_col,
+ false));
struct Expr *from_col =
- sqlExprAlloc(db, TK_ID, &t_from_col, 0);
+ sql_expr_create(pParse, TK_ID, &t_from_col, false);
struct Expr *eq = sqlPExpr(pParse, TK_EQ, to_col, from_col);
- where = sqlExprAnd(db, where, eq);
+ where = sql_and_expr_create(pParse, where, eq);
/*
* For ON UPDATE, construct the next term of the
@@ -812,11 +817,13 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey,
*/
if (is_update) {
struct Expr *old_val = sqlPExpr(pParse, TK_DOT,
- sqlExprAlloc(db, TK_ID, &t_old, 0),
- sqlExprAlloc(db, TK_ID, &t_to_col, 0));
+ sql_expr_create(pParse, TK_ID, &t_old, false),
+ sql_expr_create(pParse, TK_ID, &t_to_col,
+ false));
struct Expr *new_val = sqlPExpr(pParse, TK_DOT,
- sqlExprAlloc(db, TK_ID, &t_new, 0),
- sqlExprAlloc(db, TK_ID, &t_to_col, 0));
+ sql_expr_create(pParse, TK_ID, &t_new, false),
+ sql_expr_create(pParse, TK_ID, &t_to_col,
+ false));
struct Expr *old_is_null = sqlPExpr(
pParse, TK_ISNULL,
sqlExprDup(db, old_val, 0), NULL);
@@ -829,7 +836,8 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey,
struct Expr *no_action_needed =
sqlPExpr(pParse, TK_OR, old_is_null,
non_null_eq);
- when = sqlExprAnd(db, when, no_action_needed);
+ when = sql_and_expr_create(pParse, when,
+ no_action_needed);
}
if (action != FKEY_ACTION_RESTRICT &&
@@ -837,21 +845,22 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey,
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));
+ sql_expr_create(pParse, TK_ID,
+ &t_new, false),
+ sql_expr_create(pParse, TK_ID,
+ &t_to_col,
+ false));
} 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(pParse, TK_NULL,
+ NULL, false);
}
} else {
- new = sqlExprAlloc(db, TK_NULL, NULL, 0);
+ new = sql_expr_create(pParse, TK_NULL, NULL,
+ false);
}
list = sql_expr_list_append(db, list, new);
sqlExprListSetName(pParse, list, &t_from_col, 0);
@@ -865,8 +874,9 @@ fkey_action_trigger(struct Parse *pParse, struct Table *pTab, struct fkey *fkey,
struct Token err;
err.z = space_name;
err.n = name_len;
- struct Expr *r = sqlExpr(db, TK_RAISE, "FOREIGN KEY "\
- "constraint failed");
+ struct Expr *r =
+ sql_op_expr_create(pParse, TK_RAISE,
+ "FOREIGN KEY constraint failed");
if (r != NULL)
r->on_conflict_action = ON_CONFLICT_ACTION_ABORT;
select = sqlSelectNew(pParse,
diff --git a/src/box/sql/parse.y b/src/box/sql/parse.y
index 1a18d5f89..d7b721695 100644
--- a/src/box/sql/parse.y
+++ b/src/box/sql/parse.y
@@ -523,12 +523,12 @@ 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, TK_ASTERISK, NULL);
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, TK_ID, &X, true);
Expr *pDot = sqlPExpr(pParse, TK_DOT, pLeft, pRight);
A = sql_expr_list_append(pParse->db,A, pDot);
}
@@ -868,15 +868,15 @@ 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, TK_ID, &X, true);
+ struct Expr *temp2 = sql_expr_create(pParse, TK_ID, &Y, true);
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, TK_INTEGER, &X, true);
A.pExpr->type = FIELD_TYPE_INTEGER;
A.zStart = X.z;
A.zEnd = X.z + X.n;
@@ -909,7 +909,7 @@ 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, TK_CAST, NULL, true);
A.pExpr->type = T.type;
sqlExprAttachSubtrees(pParse->db, A.pExpr, E.pExpr, 0);
}
@@ -1099,7 +1099,7 @@ 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, TK_INTEGER, &sqlIntTokens[N], true);
}else if( Y->nExpr==1 ){
/* Expressions of the form:
**
@@ -1421,7 +1421,7 @@ 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);
+ A.pExpr = sql_expr_create(pParse, TK_RAISE, &Z, true);
if( A.pExpr ) {
A.pExpr->on_conflict_action = (enum on_conflict_action) T;
}
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 029eb4055..22397d6f5 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -479,26 +479,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 Parse *parser, 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->pTab->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(parser, TK_COLUMN, NULL, true);
+ if (expr == NULL)
+ return NULL;
+ struct SrcList_item *pItem = &src_list->a[src_idx];
+ expr->space_def = pItem->pTab->def;
+ expr->iTable = pItem->iCursor;
+ expr->iColumn = column;
+ pItem->colUsed |= ((Bitmask) 1) << (column >= BMS ? BMS - 1 : column);
+ ExprSetProperty(expr, EP_Resolved);
+ return expr;
}
/*
@@ -999,7 +993,9 @@ 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);
+ Expr *pNew =
+ sql_op_expr_create(pParse, TK_INTEGER,
+ NULL);
if (pNew == 0)
return 1;
pNew->flags |= EP_IntValue;
@@ -1347,9 +1343,8 @@ 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(pParse, TK_INTEGER,
+ &sqlIntTokens[1], false);
} else {
if (sqlResolveExprNames(&sNC, p->pHaving))
return WRC_Abort;
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index dfd3a375e..5a1bc0c81 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -165,7 +165,9 @@ sqlSelectNew(Parse * pParse, /* Parsing context */
}
if (pEList == 0) {
pEList = sql_expr_list_append(pParse->db, NULL,
- sqlExpr(db, TK_ASTERISK, 0));
+ sql_op_expr_create(pParse,
+ TK_ASTERISK,
+ NULL));
}
struct session MAYBE_UNUSED *user_session;
user_session = current_session();
@@ -483,7 +485,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;
@@ -493,8 +494,8 @@ addWhereTerm(Parse * pParse, /* Parsing context */
assert(pSrc->a[iLeft].pTab);
assert(pSrc->a[iRight].pTab);
- pE1 = sqlCreateColumnExpr(db, pSrc, iLeft, iColLeft);
- pE2 = sqlCreateColumnExpr(db, pSrc, iRight, iColRight);
+ pE1 = sql_column_expr_create(pParse, pSrc, iLeft, iColLeft);
+ pE2 = sql_column_expr_create(pParse, pSrc, iRight, iColRight);
pEq = sqlPExpr(pParse, TK_EQ, pE1, pE2);
if (pEq && isOuterJoin) {
@@ -503,7 +504,7 @@ addWhereTerm(Parse * pParse, /* Parsing context */
ExprSetVVAProperty(pEq, EP_NoReduce);
pEq->iRightJoinTable = (i16) pE2->iTable;
}
- *ppWhere = sqlExprAnd(db, *ppWhere, pEq);
+ *ppWhere = sql_and_expr_create(pParse, *ppWhere, pEq);
}
/*
@@ -624,8 +625,8 @@ sqlProcessJoin(Parse * pParse, Select * p)
if (pRight->pOn) {
if (isOuter)
setJoinExpr(pRight->pOn, pRight->iCursor);
- p->pWhere =
- sqlExprAnd(pParse->db, p->pWhere, pRight->pOn);
+ p->pWhere = sql_and_expr_create(pParse, p->pWhere,
+ pRight->pOn);
pRight->pOn = 0;
}
@@ -3314,7 +3315,9 @@ multiSelectOrderBy(Parse * pParse, /* Parsing context */
break;
}
if (j == nOrderBy) {
- Expr *pNew = sqlExpr(db, TK_INTEGER, 0);
+ Expr *pNew =
+ sql_op_expr_create(pParse, TK_INTEGER,
+ NULL);
if (pNew == 0)
return SQL_NOMEM_BKPT;
pNew->flags |= EP_IntValue;
@@ -4201,17 +4204,18 @@ 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);
+ pParent->pHaving =
+ sql_and_expr_create(pParse,
+ sqlExprDup(db,
+ pSub->pHaving, 0),
+ pParent->pHaving);
assert(pParent->pGroupBy == 0);
pParent->pGroupBy =
sql_expr_list_dup(db, pSub->pGroupBy, 0);
} else {
pParent->pWhere =
- sqlExprAnd(db, pWhere, pParent->pWhere);
+ sql_and_expr_create(pParse, pWhere,
+ pParent->pWhere);
}
substSelect(pParse, pParent, iParent, pSub->pEList, 0);
@@ -4317,7 +4321,8 @@ pushDownWhereTerms(Parse * pParse, /* Parse context (for malloc() and error repo
pNew = sqlExprDup(pParse->db, pWhere, 0);
pNew = substExpr(pParse, pNew, iCursor, pSubq->pEList);
pSubq->pWhere =
- sqlExprAnd(pParse->db, pSubq->pWhere, pNew);
+ sql_and_expr_create(pParse, pSubq->pWhere,
+ pNew);
pSubq = pSubq->pPrior;
}
}
@@ -4500,7 +4505,8 @@ convertCompoundSelectToSubquery(Walker * pWalker, Select * p)
*pNew = *p;
p->pSrc = pNewSrc;
p->pEList = sql_expr_list_append(pParse->db, NULL,
- sqlExpr(db, TK_ASTERISK, 0));
+ sql_op_expr_create(pParse, TK_ASTERISK,
+ NULL));
p->op = TK_SELECT;
p->pWhere = 0;
pNew->pGroupBy = 0;
@@ -5002,16 +5008,16 @@ selectExpander(Walker * pWalker, Select * p)
continue;
}
}
- pRight =
- sqlExpr(db, TK_ID,
+ pRight = sql_op_expr_create(
+ pParse, TK_ID,
zName);
zColname = zName;
zToFree = 0;
if (longNames
|| pTabList->nSrc > 1) {
Expr *pLeft;
- pLeft =
- sqlExpr(db,
+ pLeft = sql_op_expr_create(
+ pParse,
TK_ID,
zTabName);
pExpr =
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index 99c8adbdd..048c814e5 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3292,13 +3292,69 @@ 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 parser The parsing context.
+ * @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 Parse *parser, int op, const Token *token, bool dequote);
+
+/*
+ * Allocate a new expression node from a zero-terminated token
+ * that has already been dequoted.
+ * @param parser The parsing context.
+ * @param op Expression opcode.
+ * @param name The object name string.
+ * @retval not NULL expression pointer on success, NULL otherwise.
+ */
+struct Expr *
+sql_op_expr_create(struct Parse *parser, 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 parser The parsing context.
+ * @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 Parse *parser, struct Expr *left_expr,
+ struct Expr *right_expr);
+
Expr *sqlExprFunction(Parse *, ExprList *, Token *);
void sqlExprAssignVarNumber(Parse *, Expr *, u32);
ExprList *sqlExprListAppendVector(Parse *, ExprList *, IdList *, Expr *);
@@ -4725,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 parser The parsing context.
+ * @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 Parse *parser, 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 a0838a26b..23af1693d 100644
--- a/src/box/sql/wherecode.c
+++ b/src/box/sql/wherecode.c
@@ -1437,7 +1437,8 @@ 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);
+ pAndExpr = sql_and_expr_create(pParse, pAndExpr,
+ pExpr);
}
if (pAndExpr) {
pAndExpr =
diff --git a/src/box/sql/whereexpr.c b/src/box/sql/whereexpr.c
index 611a3896d..79cd09d4e 100644
--- a/src/box/sql/whereexpr.c
+++ b/src/box/sql/whereexpr.c
@@ -303,7 +303,7 @@ 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);
+ pPrefix = sql_op_expr_create(pParse, TK_STRING, z);
if (pPrefix)
pPrefix->u.zToken[cnt] = 0;
*ppPrefix = pPrefix;
@@ -1297,9 +1297,9 @@ exprAnalyze(SrcList * pSrc, /* the FROM clause */
int idxNew;
WhereTerm *pNewTerm;
- pNewExpr = sqlPExpr(pParse, TK_GT,
- sqlExprDup(db, pLeft, 0),
- sqlExprAlloc(db, TK_NULL, 0, 0));
+ pNewExpr = sqlPExpr(pParse, TK_GT, sqlExprDup(db, pLeft, 0),
+ sql_expr_create(pParse, TK_NULL, NULL,
+ false));
idxNew = whereClauseInsert(pWC, pNewExpr,
TERM_VIRTUAL | TERM_DYNAMIC |
@@ -1495,7 +1495,7 @@ sqlWhereTabFuncArgs(Parse * pParse, /* Parsing context */
pTab->def->name, j);
return;
}
- pColRef = sqlExprAlloc(pParse->db, TK_COLUMN, 0, 0);
+ pColRef = sql_expr_create(pParse, TK_COLUMN, NULL, false);
if (pColRef == 0)
return;
pColRef->iTable = pItem->iCursor;
--
2.20.1
More information about the Tarantool-patches
mailing list