diff --git a/src/box/sql/alter.c b/src/box/sql/alter.c index bd9b034c406def6cc8ec422b25ff1fbf119e692d..bf4f03a17355576977151df1363b154c78a45e30 100644 --- a/src/box/sql/alter.c +++ b/src/box/sql/alter.c @@ -43,9 +43,9 @@ sql_alter_table_rename(struct Parse *parse, struct SrcList *src_tab, { assert(src_tab->nSrc == 1); struct sql *db = parse->db; - char *new_name = sqlNameFromToken(db, new_name_tk); + char *new_name = sql_name_from_token(db, new_name_tk); if (new_name == NULL) - goto exit_rename_table; + goto tnt_error; /* Check that new name isn't occupied by another table. */ if (space_by_name(new_name) != NULL) { diag_set(ClientError, ER_SPACE_EXISTS, new_name); diff --git a/src/box/sql/analyze.c b/src/box/sql/analyze.c index 6ea598c1391617c5fb20c8494cb3b8a6dfc37af2..0663c66b28c1ba69c98d714c2768aa83074faa7b 100644 --- a/src/box/sql/analyze.c +++ b/src/box/sql/analyze.c @@ -1110,32 +1110,33 @@ vdbe_emit_analyze_table(struct Parse *parse, struct space *space) void sqlAnalyze(Parse * pParse, Token * pName) { - sql *db = pParse->db; + struct sql *db = pParse->db; if (pName == NULL) { /* Form 1: Analyze everything */ sql_analyze_database(pParse); } else { /* Form 2: Analyze table named */ - char *z = sqlNameFromToken(db, pName); - if (z != NULL) { - struct space *sp = space_by_name(z); - if (sp != NULL) { - if (sp->def->opts.is_view) { - diag_set(ClientError, - ER_SQL_ANALYZE_ARGUMENT, - sp->def->name); - pParse->is_aborted = true; - } else { - vdbe_emit_analyze_table(pParse, sp); - } - } else { - diag_set(ClientError, ER_NO_SUCH_SPACE, z); + char *z = sql_name_from_token(db, pName); + if (z == NULL) { + pParse->is_aborted = true; + return; + } + struct space *sp = space_by_name(z); + if (sp != NULL) { + if (sp->def->opts.is_view) { + diag_set(ClientError, ER_SQL_ANALYZE_ARGUMENT, + sp->def->name); pParse->is_aborted = true; + } else { + vdbe_emit_analyze_table(pParse, sp); } - sqlDbFree(db, z); + } else { + diag_set(ClientError, ER_NO_SUCH_SPACE, z); + pParse->is_aborted = true; } + sqlDbFree(db, z); } - Vdbe *v = sqlGetVdbe(pParse); + struct Vdbe *v = sqlGetVdbe(pParse); if (v != NULL) sqlVdbeAddOp0(v, OP_Expire); } diff --git a/src/box/sql/build.c b/src/box/sql/build.c index aeb1a33487c1ddd748860638c316cc9995e0a226..2c1b1613fd7aea693bf4e49055c01dab5c53df49 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -229,30 +229,18 @@ sql_space_column_is_in_pk(struct space *space, uint32_t column) return false; } -/* - * Given a token, return a string that consists of the text of that - * token. Space to hold the returned string - * is obtained from sqlMalloc() and must be freed by the calling - * function. - * - * Any quotation marks (ex: "name", 'name', [name], or `name`) that - * surround the body of the token are removed. - * - * Tokens are often just pointers into the original SQL text and so - * are not \000 terminated and are not persistent. The returned string - * is \000 terminated and is persistent. - */ char * -sqlNameFromToken(sql * db, Token * pName) +sql_name_from_token(struct sql *db, struct Token *name_token) { - char *zName; - if (pName) { - zName = sqlDbStrNDup(db, (char *)pName->z, pName->n); - sqlNormalizeName(zName); - } else { - zName = 0; + assert(name_token != NULL && name_token->z != NULL); + char *name = sqlDbStrNDup(db, name_token->z, name_token->n); + if (name == NULL) { + diag_set(OutOfMemory, name_token->n + 1, "sqlDbStrNDup", + "name"); + return NULL; } - return zName; + sqlNormalizeName(name); + return name; } /* @@ -338,11 +326,13 @@ sqlStartTable(Parse *pParse, Token *pName, int noErr) goto cleanup; sqlVdbeCountChanges(v); - zName = sqlNameFromToken(db, pName); + zName = sql_name_from_token(db, pName); + if (zName == NULL) { + pParse->is_aborted = true; + goto cleanup; + } pParse->sNameToken = *pName; - if (zName == 0) - return; if (sqlCheckIdentifierName(pParse, zName) != 0) goto cleanup; @@ -716,11 +706,13 @@ sqlAddCollateType(Parse * pParse, Token * pToken) struct space *space = pParse->new_space; uint32_t i = space->def->field_count - 1; sql *db = pParse->db; - char *zColl = sqlNameFromToken(db, pToken); - if (!zColl) + char *coll_name = sql_name_from_token(db, pToken); + if (coll_name == NULL) { + pParse->is_aborted = true; return; + } uint32_t *coll_id = &space->def->fields[i].coll_id; - if (sql_get_coll_seq(pParse, zColl, coll_id) != NULL) { + if (sql_get_coll_seq(pParse, coll_name, coll_id) != NULL) { /* If the column is declared as "<name> PRIMARY KEY COLLATE <type>", * then an index may have been created on this column before the * collation type was added. Correct this if it is the case. @@ -734,7 +726,7 @@ sqlAddCollateType(Parse * pParse, Token * pToken) } } } - sqlDbFree(db, zColl); + sqlDbFree(db, coll_name); } struct coll * @@ -1282,7 +1274,7 @@ sql_create_view(struct Parse *parse_context, struct Token *begin, struct sql *db = parse_context->db; if (parse_context->nVar > 0) { diag_set(ClientError, ER_CREATE_SPACE, - sqlNameFromToken(db, name), + sql_name_from_token(db, name), "parameters are not allowed in views"); parse_context->is_aborted = true; goto create_view_fail; @@ -1754,10 +1746,9 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child, memset(fk_parse, 0, sizeof(*fk_parse)); rlist_add_entry(&parse_context->new_fk_constraint, fk_parse, link); } - assert(parent != NULL); - parent_name = sqlNameFromToken(db, parent); + parent_name = sql_name_from_token(db, parent); if (parent_name == NULL) - goto exit_create_fk; + goto tnt_error; /* * Within ALTER TABLE ADD CONSTRAINT FK also can be * self-referenced, but in this case parent (which is @@ -1784,12 +1775,18 @@ sql_create_foreign_key(struct Parse *parse_context, struct SrcList *child, sqlMPrintf(db, "FK_CONSTRAINT_%d_%s", ++parse_context->fk_constraint_count, space->def->name); + if (constraint_name == NULL) + goto exit_create_fk; } else { struct Token *cnstr_nm = &parse_context->constraintName; - constraint_name = sqlNameFromToken(db, cnstr_nm); + constraint_name = sql_name_from_token(db, cnstr_nm); + if (constraint_name == NULL) + goto tnt_error; } } else { - constraint_name = sqlNameFromToken(db, constraint); + constraint_name = sql_name_from_token(db, constraint); + if (constraint_name == NULL) + goto tnt_error; } if (constraint_name == NULL) goto exit_create_fk; @@ -1928,11 +1925,14 @@ sql_drop_foreign_key(struct Parse *parse_context, struct SrcList *table, parse_context->is_aborted = true; return; } - char *constraint_name = sqlNameFromToken(parse_context->db, - constraint); - if (constraint_name != NULL) - vdbe_emit_fk_constraint_drop(parse_context, constraint_name, - child->def->id); + char *constraint_name = + sql_name_from_token(parse_context->db, constraint); + if (constraint_name == NULL) { + parse_context->is_aborted = true; + return; + } + vdbe_emit_fk_constraint_drop(parse_context, constraint_name, + child->def->id); /* * We account changes to row count only if drop of * foreign keys take place in a separate @@ -2168,7 +2168,7 @@ sql_create_index(struct Parse *parse, struct Token *token, if (def->opts.is_view) { diag_set(ClientError, ER_MODIFY_INDEX, - sqlNameFromToken(db, token), def->name, + sql_name_from_token(db, token), def->name, "views can not be indexed"); parse->is_aborted = true; goto exit_create_index; @@ -2195,9 +2195,11 @@ sql_create_index(struct Parse *parse, struct Token *token, */ if (token != NULL) { assert(token->z != NULL); - name = sqlNameFromToken(db, token); - if (name == NULL) + name = sql_name_from_token(db, token); + if (name == NULL) { + parse->is_aborted = true; goto exit_create_index; + } if (sql_space_index_by_name(space, name) != NULL) { if (!if_not_exist) { diag_set(ClientError, ER_INDEX_EXISTS_IN_SPACE, @@ -2208,10 +2210,15 @@ sql_create_index(struct Parse *parse, struct Token *token, } } else { char *constraint_name = NULL; - if (parse->constraintName.z != NULL) + if (parse->constraintName.z != NULL) { constraint_name = - sqlNameFromToken(db, - &parse->constraintName); + sql_name_from_token(db, + &parse->constraintName); + if (constraint_name == NULL) { + parse->is_aborted = true; + goto exit_create_index; + } + } /* * This naming is temporary. Now it's not @@ -2454,8 +2461,9 @@ sql_drop_index(struct Parse *parse_context, struct SrcList *index_name_list, /* Never called with prior errors. */ assert(!parse_context->is_aborted); assert(table_token != NULL); - const char *table_name = sqlNameFromToken(db, table_token); - if (db->mallocFailed) { + const char *table_name = sql_name_from_token(db, table_token); + if (table_name == NULL) { + parse_context->is_aborted = true; goto exit_drop_index; } sqlVdbeCountChanges(v); @@ -2557,7 +2565,7 @@ sql_id_list_append(struct sql *db, struct IdList *list, list->a = sqlArrayAllocate(db, list->a, sizeof(list->a[0]), &list->nId, &i); if (i >= 0) { - list->a[i].zName = sqlNameFromToken(db, name_token); + list->a[i].zName = sql_name_from_token(db, name_token); if (list->a[i].zName != NULL) return list; } @@ -2671,7 +2679,13 @@ sql_src_list_append(struct sql *db, struct SrcList *list, list = new_list; } struct SrcList_item *item = &list->a[list->nSrc - 1]; - item->zName = sqlNameFromToken(db, name_token); + if (name_token != NULL) { + item->zName = sql_name_from_token(db, name_token); + if (item->zName == NULL) { + sqlSrcListDelete(db, list); + return NULL; + } + } return list; } @@ -2772,8 +2786,12 @@ sqlSrcListAppendFromTerm(Parse * pParse, /* Parsing context */ assert(p->nSrc != 0); pItem = &p->a[p->nSrc - 1]; assert(pAlias != 0); - if (pAlias->n) { - pItem->zAlias = sqlNameFromToken(db, pAlias); + if (pAlias->n != 0) { + pItem->zAlias = sql_name_from_token(db, pAlias); + if (pItem->zAlias == NULL) { + pParse->is_aborted = true; + goto append_from_error; + } } pItem->pSelect = pSubquery; pItem->pOn = pOn; @@ -2806,10 +2824,14 @@ sqlSrcListIndexedBy(Parse * pParse, SrcList * p, Token * pIndexedBy) * construct "indexed_opt" for details. */ pItem->fg.notIndexed = 1; - } else { + } else if (pIndexedBy->z != NULL) { pItem->u1.zIndexedBy = - sqlNameFromToken(pParse->db, pIndexedBy); - pItem->fg.isIndexedBy = (pItem->u1.zIndexedBy != 0); + sql_name_from_token(pParse->db, pIndexedBy); + if (pItem->u1.zIndexedBy == NULL) { + pParse->is_aborted = true; + return; + } + pItem->fg.isIndexedBy = true; } } } @@ -2894,17 +2916,20 @@ sql_transaction_rollback(Parse *pParse) void sqlSavepoint(Parse * pParse, int op, Token * pName) { - char *zName = sqlNameFromToken(pParse->db, pName); + struct sql *db = pParse->db; + char *zName = sql_name_from_token(db, pName); if (zName) { Vdbe *v = sqlGetVdbe(pParse); if (!v) { - sqlDbFree(pParse->db, zName); + sqlDbFree(db, zName); return; } if (op == SAVEPOINT_BEGIN && sqlCheckIdentifierName(pParse, zName) != 0) return; sqlVdbeAddOp4(v, OP_Savepoint, op, 0, 0, zName, P4_DYNAMIC); + } else { + pParse->is_aborted = true; } } @@ -2980,19 +3005,23 @@ sqlWithAdd(Parse * pParse, /* Parsing context */ { sql *db = pParse->db; With *pNew; - char *zName; - /* Check that the CTE name is unique within this WITH clause. If - * not, store an error in the Parse structure. + /* + * Check that the CTE name is unique within this WITH + * clause. If not, store an error in the Parse structure. */ - zName = sqlNameFromToken(pParse->db, pName); - if (zName && pWith) { + char *name = sql_name_from_token(db, pName); + if (name == NULL) { + pParse->is_aborted = true; + goto error; + } + if (pWith != NULL) { int i; const char *err = "Ambiguous table name in WITH query: %s"; for (i = 0; i < pWith->nCte; i++) { - if (strcmp(zName, pWith->a[i].zName) == 0) { + if (strcmp(name, pWith->a[i].zName) == 0) { diag_set(ClientError, ER_SQL_PARSER_GENERIC, - tt_sprintf(err, zName)); + tt_sprintf(err, name)); pParse->is_aborted = true; } } @@ -3005,17 +3034,18 @@ sqlWithAdd(Parse * pParse, /* Parsing context */ } else { pNew = sqlDbMallocZero(db, sizeof(*pWith)); } - assert((pNew != 0 && zName != 0) || db->mallocFailed); + assert((pNew != NULL && name != NULL) || db->mallocFailed); if (db->mallocFailed) { +error: sql_expr_list_delete(db, pArglist); sql_select_delete(db, pQuery); - sqlDbFree(db, zName); + sqlDbFree(db, name); pNew = pWith; } else { pNew->a[pNew->nCte].pSelect = pQuery; pNew->a[pNew->nCte].pCols = pArglist; - pNew->a[pNew->nCte].zName = zName; + pNew->a[pNew->nCte].zName = name; pNew->a[pNew->nCte].zCteErr = 0; pNew->nCte++; } diff --git a/src/box/sql/pragma.c b/src/box/sql/pragma.c index 2b9c9b441bbfcee7e8b8c4a18755d6c2cd3fa381..53524b61776b0e5ec3c1f5bb4f5c33d904840ad8 100644 --- a/src/box/sql/pragma.c +++ b/src/box/sql/pragma.c @@ -423,19 +423,31 @@ sqlPragma(Parse * pParse, Token * pId, /* First part of [schema.]id field */ sqlVdbeRunOnlyOnce(v); pParse->nMem = 2; - zLeft = sqlNameFromToken(db, pId); - if (!zLeft) { + if (pId == NULL) { vdbe_emit_pragma_status(pParse); return; } - + zLeft = sql_name_from_token(db, pId); + if (zLeft == NULL) { + pParse->is_aborted = true; + goto pragma_out; + } if (minusFlag) { zRight = sqlMPrintf(db, "-%T", pValue); - } else { - zRight = sqlNameFromToken(db, pValue); + } else if (pValue != NULL) { + zRight = sql_name_from_token(db, pValue); + if (zRight == NULL) { + pParse->is_aborted = true; + goto pragma_out; + } + } + if (pValue2 != NULL) { + zTable = sql_name_from_token(db, pValue2); + if (zTable == NULL) { + pParse->is_aborted = true; + goto pragma_out; + } } - zTable = sqlNameFromToken(db, pValue2); - /* Locate the pragma in the lookup table */ pPragma = pragmaLocate(zLeft); if (pPragma == 0) { diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index 6ea658232063cfece8b54a6666f1dc1f945c249e..2d406b30e91599617f7dd3cf71917b267fb453d5 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -3667,7 +3667,26 @@ int sqlExprCodeExprList(Parse *, ExprList *, int, int, u8); void sqlExprIfTrue(Parse *, Expr *, int, int); void sqlExprIfFalse(Parse *, Expr *, int, int); -char *sqlNameFromToken(sql *, Token *); +/** + * Given a token, return a string that consists of the text of + * that token. Space to hold the returned string is obtained + * from sqlMalloc() and must be freed by the calling function. + * + * Any quotation marks (ex: "name", 'name', [name], or `name`) + * that surround the body of the token are removed. + * + * Tokens are often just pointers into the original SQL text and + * so are not \000 terminated and are not persistent. The returned + * string is \000 terminated and is persistent. + * + * @param db The database connection. + * @param name_token The source token with text. + * @retval Not NULL Formatted name on new memory. + * @retval NULL Error. Diag message is set. + */ +char * +sql_name_from_token(struct sql *db, struct Token *name_token); + int sqlExprCompare(Expr *, Expr *, int); int sqlExprListCompare(ExprList *, ExprList *, int); int sqlExprImpliesExpr(Expr *, Expr *, int); diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c index 2c9785fe972c1a72009eb3470daa38774a296b97..34f77515d5688904cfa7cb6c8310c16bced7d7d7 100644 --- a/src/box/sql/trigger.c +++ b/src/box/sql/trigger.c @@ -82,9 +82,9 @@ sql_trigger_begin(struct Parse *parse, struct Token *name, int tr_tm, goto trigger_cleanup; assert(table->nSrc == 1); - trigger_name = sqlNameFromToken(db, name); + trigger_name = sql_name_from_token(db, name); if (trigger_name == NULL) - goto trigger_cleanup; + goto set_tarantool_error_and_cleanup; if (sqlCheckIdentifierName(parse, trigger_name) != 0) goto trigger_cleanup;