[tarantool-patches] Re: [PATCH 2/2] sql: refactor delete routines
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Thu May 17 17:23:54 MSK 2018
Hello. Thanks for the patch! I can not build, wonder travis is ok.
Maybe Mac travis uses gcc instead of clang?
See my 20 comments below.
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:482:6: error: variable 'where' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
if (src == NULL)
^~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:516:27: note: uninitialized use occurs here
sql_expr_free(parse->db, where, false);
^~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:482:2: note: remove the 'if' if its condition is always false
if (src == NULL)
^~~~~~~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:478:6: error: variable 'where' is used uninitialized whenever 'if' condition is true [-Werror,-Wsometimes-uninitialized]
if (parse->nErr > 0 || parse->db->mallocFailed)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:516:27: note: uninitialized use occurs here
sql_expr_free(parse->db, where, false);
^~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:478:2: note: remove the 'if' if its condition is always false
if (parse->nErr > 0 || parse->db->mallocFailed)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:478:6: error: variable 'where' is used uninitialized whenever '||' condition is true [-Werror,-Wsometimes-uninitialized]
if (parse->nErr > 0 || parse->db->mallocFailed)
^~~~~~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:516:27: note: uninitialized use occurs here
sql_expr_free(parse->db, where, false);
^~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:478:6: note: remove the '||' if its condition is always false
if (parse->nErr > 0 || parse->db->mallocFailed)
^~~~~~~~~~~~~~~~~~
/Users/v.shpilevoy/Work/Repositories/tarantool/src/box/sql/delete.c:488:2: note: variable 'where' is declared here
struct Expr *where = NULL;
^
On 16/05/2018 19:29, Kirill Yukhin wrote:
> Hi Vlad,
> On 16 мая 18:24, Kirill Yukhin wrote:
>> Refactor DELETE FROM statements translation, update
> I've removed one more dead routine. Patch is in the bottom.
>
> --
> Regards, Kirill Yukhin
>
> sql: refactor SQL delete routines
>
> Refactor DELETE FROM statements translation, update
> all live routines according to Tarantool's coding style.
> Use key_def instead of Table* where possible.
> Remove useless index delete routine as well.
>
> Part of #3235
> ---
> src/box/sql/build.c | 6 +-
> src/box/sql/delete.c | 1136 ++++++++++++++++-------------------------------
> src/box/sql/fkey.c | 3 +-
> src/box/sql/insert.c | 26 +-
> src/box/sql/parse.y | 2 +-
> src/box/sql/sqliteInt.h | 206 ++++++++-
> src/box/sql/trigger.c | 12 +-
> src/box/sql/update.c | 9 +-
> src/box/sql/vdbe.c | 6 +-
> src/box/sql/vdbeaux.c | 7 +-
> 10 files changed, 619 insertions(+), 794 deletions(-)
>
> diff --git a/src/box/sql/delete.c b/src/box/sql/delete.c
> index 3455f52..0c77057 100644
> --- a/src/box/sql/delete.c
> +++ b/src/box/sql/delete.c
> -Table *
> -sqlite3SrcListLookup(Parse * pParse, SrcList * pSrc)
> +struct Table *
> +sql_list_lookup_table(struct Parse *parse, SrcList *src_list)
> {
> + struct SrcList_item *item = src_list->a;
> + struct Table *table;
> + assert(item != NULL && src_list->nSrc == 1);
> + table = sqlite3LocateTable(parse, 0, item->zName);
> + sqlite3DeleteTable(parse->db, item->pTab);
> + item->pTab = table;
> + if (table != NULL)
> + table->nTabRef++;
> + if (sqlite3IndexedByLookup(parse, item))
> + table = NULL;
1. What about --nTabRef; ? sqlite3IndexedByLookup does not unref
table. Looks like original SQLite bug.
> +sql_delete_by_where(struct Parse *parse, char *t_name, const char **columns,
> + struct Expr **values, int pairs_count)
> {
> - Expr *where = NULL;
> - SrcList *src;
> -
> - assert(nPairs > 0);
> - if (pParse->nErr > 0 || pParse->db->mallocFailed)
> + if (parse->nErr > 0 || parse->db->mallocFailed)
> goto error;
> - src = sql_alloc_src_list(pParse->db);
> - src->a[0].zName = sqlite3DbStrDup(pParse->db, zTab);
> + struct SrcList *src = sql_alloc_src_list(parse->db);
> + src->a[0].zName = sqlite3DbStrDup(parse->db, t_name);
> if (src == NULL)
2. Maybe first check src on NULL and then use it? Looks like the second SQLite bug.
>
> -/* Make sure "isView" and other macros defined above are undefined. Otherwise
> - * they may interfere with compilation of other functions in this file
> - * (or in another file, if this file becomes part of the amalgamation).
> - */
> -#ifdef isView
> -#undef isView
> -#endif
> -#ifdef pTrigger
> -#undef pTrigger
> -#endif
> -
> -/*
> - * This routine generates VDBE code that causes a single row of a
> - * single table to be deleted. Both the original table entry and
> - * all indices are removed.
> - *
> - * Preconditions:
> - *
> - * 1. iDataCur is an open cursor on the btree that is the canonical data
> - * store for the table. (This will be the PRIMARY KEY index)
> - *
> - * 2. Read/write cursors for all indices of pTab must be open as
> - * cursor number iIdxCur+i for the i-th index.
> - *
> - * 3. The primary key for the row to be deleted must be stored in a
> - * sequence of nPk memory cells starting at iPk. If nPk==0 that means
> - * that a search record formed from OP_MakeRecord is contained in the
> - * single memory location iPk.
> - *
> - * eMode:
> - * Parameter eMode may be passed either ONEPASS_OFF (0), ONEPASS_SINGLE, or
> - * ONEPASS_MULTI. If eMode is not ONEPASS_OFF, then the cursor
> - * iDataCur already points to the row to delete. If eMode is ONEPASS_OFF
> - * then this function must seek iDataCur to the entry identified by iPk
> - * and nPk before reading from it.
> - *
> - * If eMode is ONEPASS_MULTI, then this call is being made as part
> - * of a ONEPASS delete that affects multiple rows. In this case, if
> - * iIdxNoSeek is a valid cursor number (>=0), then its position should
> - * be preserved following the delete operation. Or, if iIdxNoSeek is not
> - * a valid cursor number, the position of iDataCur should be preserved
> - * instead.
> - *
> - * iIdxNoSeek:
> - * If iIdxNoSeek is a valid cursor number (>=0), then it identifies an
> - * index cursor (from within array of cursors starting at iIdxCur) that
> - * already points to the index entry to be deleted.
> - */
> void
> -sqlite3GenerateRowDelete(Parse * pParse, /* Parsing context */
> - Table * pTab, /* Table containing the row to be deleted */
> - Trigger * pTrigger, /* List of triggers to (potentially) fire */
> - int iDataCur, /* Cursor from which column data is extracted */
> - int iIdxCur, /* First index cursor */
> - int iPk, /* First memory cell containing the PRIMARY KEY */
> - i16 nPk, /* Number of PRIMARY KEY memory cells */
> - u8 count, /* If non-zero, increment the row change counter */
> - enum on_conflict_action onconf, /* Default ON CONFLICT policy for triggers */
> - u8 eMode, /* ONEPASS_OFF, _SINGLE, or _MULTI. See above */
> - int iIdxNoSeek) /* Cursor number of cursor that does not need seeking */
> +sql_generate_row_delete(struct Parse *parse, struct Table *table,
> + struct Trigger *trigger_list, int cursor, int reg_pk,
3. I think, it is time to invent a standard name for cursors: I see, that both 'cursor' and 'reg_pk'
are cursors, but their names differs very. My proposal: each cursor variable must end with '_cursor'.
So data_cursor and pk_cursor instead of cursor and reg_pk.
> + short npk, bool is_count,
4. is_count -> need_update_count. This flag means, that global nChanges must be updated.
> diff --git a/src/box/sql/sqliteInt.h b/src/box/sql/sqliteInt.h
> index e056d63..6f23859 100644
> --- a/src/box/sql/sqliteInt.h
> +++ b/src/box/sql/sqliteInt.h
> @@ -3671,15 +3670,69 @@ int sqlite3Select(Parse *, Select *, SelectDest *);
> Select *sqlite3SelectNew(Parse *, ExprList *, SrcList *, Expr *, ExprList *,
> Expr *, ExprList *, u32, Expr *, Expr *);
> void sqlite3SelectDelete(sqlite3 *, Select *);
> -Table *sqlite3SrcListLookup(Parse *, SrcList *);
> +
> +/**
> + * While a SrcList can in general represent multiple tables and
> + * subqueries (as in the FROM clause of a SELECT statement) in
> + * this case it contains the name of a single table, as one might
> + * find in an INSERT, DELETE, or UPDATE statement. Look up that
> + * table in the symbol table and return a pointer. Set an error
> + * message and return NULL if the table name is not found or if
> + * any other error occurs.
> + *
> + * The following fields are initialized appropriate in src_list:
> + *
> + * pSrc->a[0].pTab Pointer to the Table object.
5. No pSrc anymore.
> + * pSrc->a[0].pIndex Pointer to the INDEXED BY index, if
> + * there is one.
> + *
> + * @param parse Parsing context.
> + * @param src_list List containing single table element.
> + * @retval Table object if found, NULL oterwise.
> + */
> +struct Table *
> +sql_list_lookup_table(struct Parse *parse, SrcList *src_list);
> +
> int sqlite3IsReadOnly(Parse *, Table *, int);
6. This function has no implementation.
> void sqlite3OpenTable(Parse *, int iCur, Table *, int);
> -#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT)
> -Expr *sqlite3LimitWhere(Parse *, SrcList *, Expr *, ExprList *, Expr *, Expr *,
> - char *);
> -#endif
> -void sqlite3DeleteFrom(Parse *, SrcList *, Expr *);
7. This function still exists in parse.y, and has no implementation.
> -void sqlite3DeleteByKey(Parse *, char *, const char **, Expr **, int);
> +/**
> + * Generate code for a DELETE FROM statement.
> + *
> + * DELETE FROM table_wxyz WHERE a<5 AND b NOT NULL;
> + * \________/ \________________/
> + * pTabList pWhere
8. No pTabList, no pWhere.
> + *
> + * @param parse Parsing context.
> + * @param tab_list List of single element which table from which
> + * deletetion if performed.
> + * @param where The WHERE clause. May be NULL.
> + */
> +void
> +sql_table_delete_from(struct Parse *parse, struct SrcList *tab_list,
> + struct Expr *where);
> +
> +/**
> + * Generate VDBE code for
> + * DELETE FROM <t_name> WHERE
> + * <columns[0]> = <values[0]>
> + * AND ...
> + * AND <columns[nPairs - 1]> = <values[nPairs - 1]>;
9. No nPairs.
> + *
> + * This function does not increment the nested counter and is
> + * faster than nested parsing of the request above.
> + *
> + * @param parse Parser context.
> + * @param t_name Table name.
> + * @param columns Column names array.
> + * @param values Column values array.
> + * @param pairs_count Length of @columns and @values.
> + *
> + * In case of error the @values elements are deleted.
> + */
> +void
> +sql_delete_by_where(struct Parse *parse, char *t_name, const char **columns,
> + struct Expr **values, int pairs_count);
> +
> void sqlite3Update(Parse *, SrcList *, ExprList *, Expr *,
> enum on_conflict_action);
> WhereInfo *sqlite3WhereBegin(Parse *, SrcList *, Expr *, ExprList *, ExprList *,
> @@ -3782,11 +3835,121 @@ int sqlite3ExprContainsSubquery(Expr *);
> int sqlite3ExprIsInteger(Expr *, int *);
> int sqlite3ExprCanBeNull(const Expr *);
> int sqlite3ExprNeedsNoAffinityChange(const Expr *, char);
> -void sqlite3GenerateRowDelete(Parse *, Table *, Trigger *, int, int, int, i16,
> - u8, enum on_conflict_action, u8, int);
> -void sqlite3GenerateRowIndexDelete(Parse *, Table *, int, int);
> -int sqlite3GenerateIndexKey(Parse *, Index *, int, int, int *, Index *, int);
10. Still exists in where.c and sqliteInt.h.
> -void sqlite3ResolvePartIdxLabel(Parse *, int);
> +
> +/**
> + * This routine generates VDBE code that causes a single row of a
> + * single table to be deleted. Both the original table entry and
> + * all indices are removed.
> + *
> + * Preconditions:
> + *
> + * 1. cursor is an open cursor on the btree that is the
> + * canonical data store for the table. (This will be the
> + * PRIMARY KEY index)
> + *
> + * 2. The primary key for the row to be deleted must be stored
> + * in a sequence of nPk memory cells starting at iPk. If
11. No iPk, no nPk.
> + * nPk==0 that means that a search record formed from
> + * OP_MakeRecord is contained in the single memory location
> + * iPk.
> + *
> + * mode:
> + * Parameter mode may be passed either ONEPASS_OFF (0),
> + * ONEPASS_SINGLE, or ONEPASS_MULTI. If eMode is not
12. No eMode.
> + * ONEPASS_OFF, then the cursor already points to the row to
> + * delete. If eMode is ONEPASS_OFF then this function must seek
> + * cursor to the entry identified by ipk and npk before reading
> + * from it.
> + *
> + * If mode is ONEPASS_MULTI, then this call is being made as
> + * part of a ONEPASS delete that affects multiple rows. In this
> + * case, if idx_noseek is a valid cursor number (>=0), then its
> + * position should be preserved following the delete operation.
> + * Or, if iIdxNoSeek is not a valid cursor number, the position
13. No iIdxNoSeek. Same parameter name mismatches in next functions.
> + * of cursor should be preserved instead.
> + *
> + * idx_noseek:
> + * If idx_noseek is a valid cursor number (>=0), then it
> + * identifies an index cursor that already points to the index
> + * entry to be deleted.
14. I think, it can be moved into @param idx_noseek description. (That
will be named idx_noseek_cursor).
> + *
> + * @param parse Parsing context.
> + * @param table Table containing the row to be deleted.
> + * @param trigger_list List of triggers to (potentially) fire.
> + * @param cursor Cursor from which column data is extracted/
> + * @param ipk First memory cell containing the PRIMARY KEY.
> + * @param npk umber of PRIMARY KEY memory cells.
> + * @param is_count If non-zero, increment the row change counter.
15. need_update_count.
> + * @param onconf Default ON CONFLICT policy for triggers.
> + * @param mode ONEPASS_OFF, _SINGLE, or _MULTI. See above.
> + * @param idx_noseek Cursor number of cursor that does not need
> + seeking.
> + */
> +void
> +sql_generate_row_delete(struct Parse *parse, struct Table *table,
> + struct Trigger *trigger_list, int cursor, int ipk,
> + short npk, bool is_count,
> + enum on_conflict_action onconf, u8 eMode,
> + int idx_noseek);
> +
> diff --git a/src/box/sql/update.c b/src/box/sql/update.c
> index de1349b..60cb229 100644
> --- a/src/box/sql/update.c
> +++ b/src/box/sql/update.c
> @@ -163,7 +163,7 @@ sqlite3Update(Parse * pParse, /* The parser context */
>
> /* Locate the table which we want to update.
> */
> - pTab = sqlite3SrcListLookup(pParse, pTabList);
> + pTab = sql_list_lookup_table(pParse, pTabList);
> if (pTab == 0)
> goto update_cleanup;
>
> @@ -187,7 +187,9 @@ sqlite3Update(Parse * pParse, /* The parser context */
> if (sqlite3ViewGetColumnNames(pParse, pTab)) {
> goto update_cleanup;
> }
> - if (sqlite3IsReadOnly(pParse, pTab, tmask)) {
> + if (isView && tmask == 0) {
> + sqlite3ErrorMsg(pParse, "cannot modify %s because it is a view",
> + pTab->zName);
> goto update_cleanup;
> }
>
> @@ -324,7 +326,7 @@ sqlite3Update(Parse * pParse, /* The parser context */
> */
> #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
> if (isView) {
> - sqlite3MaterializeView(pParse, pTab, pWhere, iDataCur);
> + sql_materialize_view(pParse, pTab->zName, pWhere, iDataCur);
> /* Number of columns from SELECT plus ID.*/
> nKey = pTab->nCol + 1;
> }
> @@ -603,7 +605,6 @@ sqlite3Update(Parse * pParse, /* The parser context */
> nKey);
> VdbeCoverageNeverTaken(v);
> }
> - sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur);
16. Why?
> diff --git a/src/box/sql/vdbe.c b/src/box/sql/vdbe.c
> index b8d4c1a..2ad6f3e 100644
> --- a/src/box/sql/vdbe.c
> +++ b/src/box/sql/vdbe.c
> @@ -3236,20 +3236,20 @@ case OP_OpenTEphemeral: {
> BtCursor *pBtCur;
> assert(pOp->p1 >= 0);
> assert(pOp->p2 > 0);
> - assert(pOp->p4type != P4_KEYDEF || pOp->p4.key_def != NULL);
> + assert(pOp->p4type == P4_KEYDEF);
17. Why was this check needed in the previous patch?
>
> pCx = allocateCursor(p, pOp->p1, pOp->p2, CURTYPE_TARANTOOL);
> if (pCx == 0) goto no_mem;
> pCx->nullRow = 1;
>
> - pCx->key_def = pOp->p4.key_def;
> pBtCur = pCx->uc.pCursor;
> /* Ephemeral spaces don't have space_id */
> pBtCur->eState = CURSOR_INVALID;
> pBtCur->curFlags = BTCF_TEphemCursor;
>
> rc = tarantoolSqlite3EphemeralCreate(pCx->uc.pCursor, pOp->p2,
> - pCx->key_def);
> + pOp->p4.key_def);
> + pCx->key_def = pCx->uc.pCursor->index->def->key_def;
18. Lets merge this into the previous patch.
> diff --git a/src/box/sql/vdbeaux.c b/src/box/sql/vdbeaux.c
> index e67fcae..4a8a9d2 100644
> --- a/src/box/sql/vdbeaux.c
> +++ b/src/box/sql/vdbeaux.c
> @@ -1134,7 +1134,7 @@ sqlite3VdbeChangeP4(Vdbe * p, int addr, const char *zP4, int n)
> } if (n == P4_BOOL) {
> pOp->p4.b = *(bool*)zP4;
> pOp->p4type = P4_BOOL;
> - } else if (zP4 != 0) {
> + } else {
19. Why?
> @@ -1571,7 +1571,10 @@ displayP4(Op * pOp, char *zTemp, int nTemp)
> #endif
> case P4_COLLSEQ:{
> struct coll *pColl = pOp->p4.pColl;
> - sqlite3XPrintf(&x, "(%.20s)", pColl->name);
> + if (pColl != NULL)
> + sqlite3XPrintf(&x, "(%.20s)", pColl->name);
> + else
> + sqlite3XPrintf(&x, "(binary)");
20. Stray change?
> break;
> }
> case P4_FUNCDEF:{
>
More information about the Tarantool-patches
mailing list