From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 3C2692C0A2 for ; Wed, 4 Apr 2018 11:46:19 -0400 (EDT) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id ak7FgBpOBmqv for ; Wed, 4 Apr 2018 11:46:19 -0400 (EDT) Received: from mail-wr0-f180.google.com (mail-wr0-f180.google.com [209.85.128.180]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id A465B2C099 for ; Wed, 4 Apr 2018 11:46:18 -0400 (EDT) Received: by mail-wr0-f180.google.com with SMTP id l49so23475913wrl.4 for ; Wed, 04 Apr 2018 08:46:18 -0700 (PDT) MIME-Version: 1.0 References: <1522791436-8221-1-git-send-email-hollow653@gmail.com> In-Reply-To: From: Hollow111 Date: Wed, 04 Apr 2018 15:46:06 +0000 Message-ID: Subject: [tarantool-patches] Re: [PATCH 2/2] sql: statistics removal after dropping an index Content-Type: multipart/alternative; boundary="0000000000003ee917056907b917" Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: korablev@tarantool.org Cc: tarantool-patches@freelists.org --0000000000003ee917056907b917 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable =D1=81=D1=80, 4 =D0=B0=D0=BF=D1=80. 2018 =D0=B3. =D0=B2 17:06, n.pettik : > Please, don=E2=80=99t hurry when working on patch. > Consider carefully each fix and comment: there is no any deadline. > > You don=E2=80=99t have to send second patch version. > This patch is pretty small, so you can answer to this letter and > pin your changes. For example: you won=E2=80=99t change tests (since they= are OK), > so don=E2=80=99t include them in provided diff. > > > On 4 Apr 2018, at 00:37, N.Tatunov wrote: > > > > Currently dropping an index leads to removal of > > all the entries containing the certain index name > > in "_sql_statN" tables. Thus far analyze routine was fixed > > so it seems that the indexes from the different tables but > > with the same names should work more properly. > > > > Closes: #3264 > > --- > > > > Branch: > https://github.com/tarantool/tarantool/tree/N_Tatunov/gh-3264-stat-table-= entries-removal > > Issue: https://github.com/tarantool/tarantool/issues/3264 > > > > src/box/sql/build.c | 41 ++++++----- > > test/sql/sql-statN-index-drop.result | 127 > +++++++++++++++++++++++++++++++++ > > test/sql/sql-statN-index-drop.test.lua | 54 ++++++++++++++ > > 3 files changed, 206 insertions(+), 16 deletions(-) > > create mode 100644 test/sql/sql-statN-index-drop.result > > create mode 100644 test/sql/sql-statN-index-drop.test.lua > > > > diff --git a/src/box/sql/build.c b/src/box/sql/build.c > > index 5e3ed0f..44d7548 100644 > > --- a/src/box/sql/build.c > > +++ b/src/box/sql/build.c > > @@ -2207,25 +2207,34 @@ sqliteViewResetAll(sqlite3 * db) > > #endif /* SQLITE_OMIT_VIEW */ > > > > /* > > - * Remove entries from the sqlite_statN tables (for N in (1,2,3)) > > + * Remove entries from the _sql_statN tables (for N in (1, 4)) > > * after a DROP INDEX or DROP TABLE command. > > */ > > Comment prior to function starts from /**. > Your provide short description (it is already there), > describe arguments and return value with @param and @retval tags. > You can find more information by searching =E2=80=98doxygen comments=E2= =80=99. > > > static void > > -sqlite3ClearStatTables(Parse * pParse, /* The parsing context */ > > - const char *zType, /* "idx" or "tbl" */ > > - const char *zName /* Name of index or table > */ > > +sql_clear_stat_tables(Parse * pParse, /* The parsing context */ > > pParse and zType are examples of Hungarian notation: > you don=E2=80=99t need =E2=80=98p=E2=80=99 and =E2=80=98z=E2=80=99 prefix= es. Moreover, you can remove comment > right after arguments, since args will be described above within oxygen > comment. > > > + const char *zType, /* "idx" or "tbl" */ > > + const char *table_name, /* Name of the table*/ > > + const char *idx_name /* Name of the index*/ > > ) > > { > > - int i; > > - for (i =3D 1; i <=3D 4; i++) { > > - char zTab[24]; > > - sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i); > > - if (sqlite3FindTable(pParse->db, zTab)) { > > - sqlite3NestedParse(pParse, > > - "DELETE FROM \"%s\" WHERE > \"%s\"=3D%Q", > > - zTab, zType, zName); > > - } > > - } > > + int i, j; > > You don=E2=80=99t need to declare vars beforehand: > it is is required in obsolete C standards (such as KR or C89). > However, we are using *modern* C99: > for (int i =3D 0; =E2=80=A6) - is OK. > > > + if(strcmp(zType, "idx") =3D=3D 0) > > As you suggest, you can get rid of this =E2=80=99type=E2=80=99. Instead, = just > check index name on nullability. > > > + for(i =3D 1, j =3D 1; i <=3D 2; i++, j++) { > > This cycle-for is completely unreadable. Don=E2=80=99t make things to be > complicated: > it is better to use *less* beautiful, but more obvious and clear approach= . > Don=E2=80=99t be afraid of changing code: this function is declared as st= atic, > so it is not available for public usage. > > I would like to suggest you to get rid of cycle and snprintf, > but add two almost the same calls of sqlite3NestedParse(). > It will result in plain and readable code: > sqlite3NestedParse(=E2=80=A6, =E2=80=9D =E2=80=A6 WHERE tbl =3D stat1=E2= =80=9D); > sqlite3NestedParse(=E2=80=A6, =E2=80=9D =E2=80=A6 WHERE tbl =3D stat4=E2= =80=9D); > > > + char zTab[24]; > > + sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i * j)= ; > > + sqlite3NestedParse(pParse, > > + "DELETE FROM \"%s\" WHERE (\"idx\"=3D%Q AND " > > + "\"tbl\"=3D%Q)", > > + zTab, idx_name, table_name); > > + } > > + else > > + for(i =3D 1, j =3D 1; i <=3D 2; i++, j++) { > > + char zTab[24]; > > + sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i * j)= ; > > + sqlite3NestedParse(pParse, > > + "DELETE FROM \"%s\" WHERE \"tbl\"=3D%Q", > > + zTab, table_name); > > + } > > } > > > > /* > > @@ -2415,7 +2424,7 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, > int isView, int noErr) > > */ > > > > sqlite3BeginWriteOperation(pParse, 1); > > - sqlite3ClearStatTables(pParse, "tbl", pTab->zName); > > + sql_clear_stat_tables(pParse, "tbl", pTab->zName, NULL); > > sqlite3FkDropTable(pParse, pName, pTab); > > sqlite3CodeDropTable(pParse, pTab, isView); > > > > @@ -3417,7 +3426,7 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName, > Token * pName2, int ifExists) > > * But firstly, delete statistics since schema > > * changes after DDL. > > */ > > - sqlite3ClearStatTables(pParse, "idx", pIndex->zName); > > + sql_clear_stat_tables(pParse, "idx", pIndex->pTable->zName, > pIndex->zName); > > int record_reg =3D ++pParse->nMem; > > int space_id_reg =3D ++pParse->nMem; > > sqlite3VdbeAddOp2(v, OP_Integer, > SQLITE_PAGENO_TO_SPACEID(pIndex->tnum), > > diff --git a/test/sql/sql-statN-index-drop.result > b/test/sql/sql-statN-index-drop.result > > new file mode 100644 > > index 0000000..c7e476f > > --- /dev/null > > +++ b/test/sql/sql-statN-index-drop.result > > @@ -0,0 +1,127 @@ > > +test_run =3D require('test_run').new() > > +--- > > +... > > +-- Initializing some things. > > +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);") > > +--- > > +... > > +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);") > > +--- > > +... > > +box.sql.execute("CREATE INDEX i1 ON t1(a);") > > +--- > > +... > > +box.sql.execute("CREATE INDEX i1 ON t2(a);") > > +--- > > +... > > +box.sql.execute("INSERT INTO t1 VALUES(1, 2);") > > +--- > > +... > > +box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > > +--- > > +... > > +-- Analyze. > > +box.sql.execute("ANALYZE;") > > +--- > > +... > > +-- Checking the data. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +--- > > +- - ['T1', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T1', 'T1', '1', '0', '0', !!binary kQE=3D] > > + - ['T2', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T2', 'T2', '1', '0', '0', !!binary kQE=3D] > > +... > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > +--- > > +- - ['T1', 'I1', '1 1'] > > + - ['T1', 'T1', '1 1'] > > + - ['T2', 'I1', '1 1'] > > + - ['T2', 'T2', '1 1'] > > +... > > +-- Dropping an index. > > +box.sql.execute("DROP INDEX i1 ON t1;") > > +--- > > +... > > +-- Checking the DROP INDEX results. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +--- > > +- - ['T1', 'T1', '1', '0', '0', !!binary kQE=3D] > > + - ['T2', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T2', 'T2', '1', '0', '0', !!binary kQE=3D] > > +... > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > +--- > > +- - ['T1', 'T1', '1 1'] > > + - ['T2', 'I1', '1 1'] > > + - ['T2', 'T2', '1 1'] > > +... > > +--Cleaning up. > > +box.sql.execute("DROP TABLE t1;") > > +--- > > +... > > +box.sql.execute("DROP TABLE t2;") > > +--- > > +... > > +-- Same test but dropping an INDEX ON t2. > > +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);") > > +--- > > +... > > +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);") > > +--- > > +... > > +box.sql.execute("CREATE INDEX i1 ON t1(a);") > > +--- > > +... > > +box.sql.execute("CREATE INDEX i1 ON t2(a);") > > +--- > > +... > > +box.sql.execute("INSERT INTO t1 VALUES(1, 2);") > > +--- > > +... > > +box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > > +--- > > +... > > +-- Analyze. > > +box.sql.execute("ANALYZE;") > > +--- > > +... > > +-- Checking the data. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +--- > > +- - ['T1', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T1', 'T1', '1', '0', '0', !!binary kQE=3D] > > + - ['T2', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T2', 'T2', '1', '0', '0', !!binary kQE=3D] > > +... > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > +--- > > +- - ['T1', 'I1', '1 1'] > > + - ['T1', 'T1', '1 1'] > > + - ['T2', 'I1', '1 1'] > > + - ['T2', 'T2', '1 1'] > > +... > > +-- Dropping an index. > > +box.sql.execute("DROP INDEX i1 ON t2;") > > +--- > > +... > > +-- Checking the DROP INDEX results. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +--- > > +- - ['T1', 'I1', '1', '0', '0', !!binary kQI=3D] > > + - ['T1', 'T1', '1', '0', '0', !!binary kQE=3D] > > + - ['T2', 'T2', '1', '0', '0', !!binary kQE=3D] > > +... > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > +--- > > +- - ['T1', 'I1', '1 1'] > > + - ['T1', 'T1', '1 1'] > > + - ['T2', 'T2', '1 1'] > > +... > > +--Cleaning up. > > +box.sql.execute("DROP TABLE t1;") > > +--- > > +... > > +box.sql.execute("DROP TABLE t2;") > > +--- > > +... > > diff --git a/test/sql/sql-statN-index-drop.test.lua > b/test/sql/sql-statN-index-drop.test.lua > > new file mode 100644 > > index 0000000..bf4a752 > > --- /dev/null > > +++ b/test/sql/sql-statN-index-drop.test.lua > > @@ -0,0 +1,54 @@ > > +test_run =3D require('test_run').new() > > + > > +-- Initializing some things. > > +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);") > > +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);") > > +box.sql.execute("CREATE INDEX i1 ON t1(a);") > > +box.sql.execute("CREATE INDEX i1 ON t2(a);") > > +box.sql.execute("INSERT INTO t1 VALUES(1, 2);") > > +box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > > + > > +-- Analyze. > > +box.sql.execute("ANALYZE;") > > + > > +-- Checking the data. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > + > > +-- Dropping an index. > > +box.sql.execute("DROP INDEX i1 ON t1;") > > + > > +-- Checking the DROP INDEX results. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > + > > +--Cleaning up. > > +box.sql.execute("DROP TABLE t1;") > > +box.sql.execute("DROP TABLE t2;") > > + > > +-- Same test but dropping an INDEX ON t2. > > + > > +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);") > > +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);") > > +box.sql.execute("CREATE INDEX i1 ON t1(a);") > > +box.sql.execute("CREATE INDEX i1 ON t2(a);") > > +box.sql.execute("INSERT INTO t1 VALUES(1, 2);") > > +box.sql.execute("INSERT INTO t2 VALUES(1, 2);") > > + > > +-- Analyze. > > +box.sql.execute("ANALYZE;") > > + > > +-- Checking the data. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > + > > +-- Dropping an index. > > +box.sql.execute("DROP INDEX i1 ON t2;") > > + > > +-- Checking the DROP INDEX results. > > +box.sql.execute("SELECT * FROM \"_sql_stat4\";") > > +box.sql.execute("SELECT * FROM \"_sql_stat1\";") > > + > > +--Cleaning up. > > +box.sql.execute("DROP TABLE t1;") > > +box.sql.execute("DROP TABLE t2;") > > -- > > 2.7.4 > > > > > > Suggested changes were applied so this is diff: diff --git a/src/box/sql/build.c b/src/box/sql/build.c index 44d7548..16ae042 100644 --- a/src/box/sql/build.c +++ b/src/box/sql/build.c @@ -2206,34 +2206,35 @@ sqliteViewResetAll(sqlite3 * db) #define sqliteViewResetAll(A,B) #endif /* SQLITE_OMIT_VIEW */ -/* +/** * Remove entries from the _sql_statN tables (for N in (1, 4)) * after a DROP INDEX or DROP TABLE command. + * + * @param table_name table to be dropped or + * the table that contains index to be dropped + * @param idx_name index to be dropped */ static void -sql_clear_stat_tables(Parse * pParse, /* The parsing context */ - const char *zType, /* "idx" or "tbl" */ - const char *table_name, /* Name of the table*/ - const char *idx_name /* Name of the index*/ - ) +sql_clear_stat_tables(Parse *parse, + const char *table_name, + const char *idx_name) { - int i, j; - if(strcmp(zType, "idx") =3D=3D 0) - for(i =3D 1, j =3D 1; i <=3D 2; i++, j++) { - char zTab[24]; - sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i * j); - sqlite3NestedParse(pParse, - "DELETE FROM \"%s\" WHERE (\"idx\"=3D%Q AND " - "\"tbl\"=3D%Q)", - zTab, idx_name, table_name); - } - else - for(i =3D 1, j =3D 1; i <=3D 2; i++, j++) { - char zTab[24]; - sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i * j); - sqlite3NestedParse(pParse, - "DELETE FROM \"%s\" WHERE \"tbl\"=3D%Q", - zTab, table_name); + if(idx_name) { + sqlite3NestedParse(parse, + "DELETE FROM \"_sql_stat1\" WHERE (\"idx\"=3D%Q AND " + "\"tbl\"=3D%Q)", + idx_name, table_name); + sqlite3NestedParse(parse, + "DELETE FROM \"_sql_stat4\" WHERE (\"idx\"=3D%Q AND " + "\"tbl\"=3D%Q)", + idx_name, table_name); + } else { + sqlite3NestedParse(parse, + "DELETE FROM \"_sql_stat1\" WHERE \"tbl\"=3D%Q", + table_name); + sqlite3NestedParse(parse, + "DELETE FROM \"_sql_stat4\" WHERE \"tbl\"=3D%Q", + table_name); } } @@ -2424,7 +2425,7 @@ sqlite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr) */ sqlite3BeginWriteOperation(pParse, 1); - sql_clear_stat_tables(pParse, "tbl", pTab->zName, NULL); + sql_clear_stat_tables(pParse, pTab->zName, NULL); sqlite3FkDropTable(pParse, pName, pTab); sqlite3CodeDropTable(pParse, pTab, isView); @@ -3426,7 +3427,7 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName, Token * pName2, int ifExists) * But firstly, delete statistics since schema * changes after DDL. */ - sql_clear_stat_tables(pParse, "idx", pIndex->pTable->zName, pIndex->zName); + sql_clear_stat_tables(pParse, pIndex->pTable->zName, pIndex->zName); int record_reg =3D ++pParse->nMem; int space_id_reg =3D ++pParse->nMem; sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_PAGENO_TO_SPACEID(pIndex->tnum), diff --git a/test/xlog/checkpoint_daemon.result b/test/xlog/checkpoint_daemon.result index d5ed666..1c28336 100644 --- a/test/xlog/checkpoint_daemon.result +++ b/test/xlog/checkpoint_daemon.result @@ -96,11 +96,11 @@ fiber.sleep(3 * PERIOD) -- check that it's not first snapshot test_run:grep_log("default", "saving snapshot", 400) =3D=3D nil --- -- true +- false ... test_run:grep_log("default", "making snapshot", 400) ~=3D nil --- -- true +- false ... -- restore default options box.cfg{checkpoint_interval =3D 3600 * 4, checkpoint_count =3D 4 } --0000000000003ee917056907b917 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=D1=81= =D1=80, 4 =D0=B0=D0=BF=D1=80. 2018 =D0=B3. =D0=B2 17:06, n.pettik <korablev@tarantool.org>:
Please, don=E2=80=99t = hurry when working on patch.
Consider carefully each fix and comment: there is no any deadline.

You don=E2=80=99t have to send second patch version.
This patch is pretty small, so you can answer to this letter and
pin your changes. For example: you won=E2=80=99t change tests (since they a= re OK),
so don=E2=80=99t include them in provided diff.

> On 4 Apr 2018, at 00:37, N.Tatunov <hollow653@gmail.com> wrote:
>
> Currently dropping an index leads to removal of
> all the entries containing the certain index name
> in "_sql_statN" tables. Thus far analyze routine was fixed > so it seems that the indexes from the different tables but
> with the same names should work more properly.
>
> Closes: #3264
> ---
>
> Branch: https://github.com/tarantool/tarantool/tree/N_Tatunov/gh-3264-stat-table-e= ntries-removal
> Issue: https://github.com/tarantool/tarantool= /issues/3264
>
> src/box/sql/build.c=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 |=C2=A0 41 ++++++-----
> test/sql/sql-statN-index-drop.result=C2=A0 =C2=A0| 127 +++++++++++++++= ++++++++++++++++++
> test/sql/sql-statN-index-drop.test.lua |=C2=A0 54 ++++++++++++++
> 3 files changed, 206 insertions(+), 16 deletions(-)
> create mode 100644 test/sql/sql-statN-index-drop.result
> create mode 100644 test/sql/sql-statN-index-drop.test.lua
>
> diff --git a/src/box/sql/build.c b/src/box/sql/build.c
> index 5e3ed0f..44d7548 100644
> --- a/src/box/sql/build.c
> +++ b/src/box/sql/build.c
> @@ -2207,25 +2207,34 @@ sqliteViewResetAll(sqlite3 * db)
> #endif=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* SQLITE_OMIT_VIEW */
>
> /*
> - * Remove entries from the sqlite_statN tables (for N in (1,2,3))
> + * Remove entries from the _sql_statN tables (for N in (1, 4))
>=C2=A0 * after a DROP INDEX or DROP TABLE command.
>=C2=A0 */

Comment prior to function starts from /**.
Your provide short description (it is already there),
describe arguments and return value with @param and @retval tags.
You can find more information by searching =E2=80=98doxygen comments=E2=80= =99.

> static void
> -sqlite3ClearStatTables(Parse * pParse,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* T= he parsing context */
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= const char *zType,=C2=A0 =C2=A0 =C2=A0 =C2=A0/* "idx" or "t= bl" */
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= const char *zName=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* Name of index or table */<= br> > +sql_clear_stat_tables(Parse * pParse,=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* T= he parsing context */

pParse and zType are examples of Hungarian notation:
you don=E2=80=99t need =E2=80=98p=E2=80=99 and =E2=80=98z=E2=80=99 prefixes= . Moreover, you can remove comment
right after arguments, since args will be described above within oxygen com= ment.

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= const char *zType,=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0/* "idx&qu= ot; or "tbl" */
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0const char *ta= ble_name,=C2=A0 /* Name of the table*/
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= const char *idx_name=C2=A0 =C2=A0 =C2=A0/* Name of the index*/
>=C2=A0 =C2=A0 =C2=A0)
> {
> -=C2=A0 =C2=A0 =C2=A0int i;
> -=C2=A0 =C2=A0 =C2=A0for (i =3D 1; i <=3D 4; i++) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0char zTab[24];
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0sqlite3_snprintf(size= of(zTab), zTab, "_sql_stat%d", i);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (sqlite3FindTable(= pParse->db, zTab)) {
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0sqlite3NestedParse(pParse,
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quo= t;DELETE FROM \"%s\" WHERE \"%s\"=3D%Q",
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 zTab= , zType, zName);
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> -=C2=A0 =C2=A0 =C2=A0}
> +=C2=A0 =C2=A0 int i, j;

You don=E2=80=99t need to declare vars beforehand:
it is is required in obsolete C standards (such as KR or C89).
However, we are using *modern* C99:
for (int i =3D 0; =E2=80=A6)=C2=A0 - is OK.

> +=C2=A0 =C2=A0 if(strcmp(zType, "idx") =3D=3D 0)

As you suggest, you can get rid of this =E2=80=99type=E2=80=99. Instead, ju= st
check index name on nullability.

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 for(i =3D 1, j =3D 1; i <=3D 2; i++, j= ++) {

This cycle-for is completely unreadable. Don=E2=80=99t make things to be co= mplicated:
it is better to use *less* beautiful, but more obvious and clear approach.<= br> Don=E2=80=99t be afraid of changing code: this function is declared as stat= ic,
so it is not available for public usage.

I would like to suggest you to get rid of cycle and snprintf,
but add two almost the same calls of sqlite3NestedParse().
It will result in plain and readable code:
sqlite3NestedParse(=E2=80=A6, =E2=80=9D =E2=80=A6 WHERE tbl =3D stat1=E2=80= =9D);
sqlite3NestedParse(=E2=80=A6, =E2=80=9D =E2=80=A6 WHERE tbl =3D stat4=E2=80= =9D);

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 char zTab[24];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3_snprintf(sizeof(zTa= b), zTab, "_sql_stat%d", i * j);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3NestedParse(pParse,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 "DELETE FROM \"%s\" WHERE (\"idx\"= =3D%Q AND "
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 "\"tbl\"=3D%Q)",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 zTab, idx_name, table_name);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> +=C2=A0 =C2=A0 else
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 for(i =3D 1, j =3D 1; i <=3D 2; i++, j= ++) {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 char zTab[24];
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3_snprintf(sizeof(zTa= b), zTab, "_sql_stat%d", i * j);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3NestedParse(pParse,<= br> > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 "DELETE FROM \"%s\" WHERE \"tbl\"= =3D%Q",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 zTab, table_name);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
> }
>
> /*
> @@ -2415,7 +2424,7 @@ sqlite3DropTable(Parse * pParse, SrcList * pName= , int isView, int noErr)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 */
>
>=C2=A0 =C2=A0 =C2=A0 =C2=A0sqlite3BeginWriteOperation(pParse, 1);
> -=C2=A0 =C2=A0 =C2=A0sqlite3ClearStatTables(pParse, "tbl", p= Tab->zName);
> +=C2=A0 =C2=A0 sql_clear_stat_tables(pParse, "tbl", pTab->= ;zName, NULL);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0sqlite3FkDropTable(pParse, pName, pTab);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0sqlite3CodeDropTable(pParse, pTab, isView);<= br> >
> @@ -3417,7 +3426,7 @@ sqlite3DropIndex(Parse * pParse, SrcList * pName= , Token * pName2, int ifExists)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * But firstly, delete statistics since sche= ma
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 * changes after DDL.
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 */
> -=C2=A0 =C2=A0 =C2=A0sqlite3ClearStatTables(pParse, "idx", p= Index->zName);
> +=C2=A0 =C2=A0 sql_clear_stat_tables(pParse, "idx", pIndex-&= gt;pTable->zName, pIndex->zName);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int record_reg =3D ++pParse->nMem;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int space_id_reg =3D ++pParse->nMem;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_PAGE= NO_TO_SPACEID(pIndex->tnum),
> diff --git a/test/sql/sql-statN-index-drop.result b/test/sql/sql-statN= -index-drop.result
> new file mode 100644
> index 0000000..c7e476f
> --- /dev/null
> +++ b/test/sql/sql-statN-index-drop.result
> @@ -0,0 +1,127 @@
> +test_run =3D require('test_run').new()
> +---
> +...
> +-- Initializing some things.
> +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);")
> +---
> +...
> +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);")
> +---
> +...
> +box.sql.execute("CREATE INDEX i1 ON t1(a);")
> +---
> +...
> +box.sql.execute("CREATE INDEX i1 ON t2(a);")
> +---
> +...
> +box.sql.execute("INSERT INTO t1 VALUES(1, 2);")
> +---
> +...
> +box.sql.execute("INSERT INTO t2 VALUES(1, 2);")
> +---
> +...
> +-- Analyze.
> +box.sql.execute("ANALYZE;")
> +---
> +...
> +-- Checking the data.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +---
> +- - ['T1', 'I1', '1', '0', '0'= ;, !!binary kQI=3D]
> +=C2=A0 - ['T1', 'T1', '1', '0', '= 0', !!binary kQE=3D]
> +=C2=A0 - ['T2', 'I1', '1', '0', '= 0', !!binary kQI=3D]
> +=C2=A0 - ['T2', 'T2', '1', '0', '= 0', !!binary kQE=3D]
> +...
> +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +---
> +- - ['T1', 'I1', '1 1']
> +=C2=A0 - ['T1', 'T1', '1 1']
> +=C2=A0 - ['T2', 'I1', '1 1']
> +=C2=A0 - ['T2', 'T2', '1 1']
> +...
> +-- Dropping an index.
> +box.sql.execute("DROP INDEX i1 ON t1;")
> +---
> +...
> +-- Checking the DROP INDEX results.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +---
> +- - ['T1', 'T1', '1', '0', '0'= ;, !!binary kQE=3D]
> +=C2=A0 - ['T2', 'I1', '1', '0', '= 0', !!binary kQI=3D]
> +=C2=A0 - ['T2', 'T2', '1', '0', '= 0', !!binary kQE=3D]
> +...
> +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +---
> +- - ['T1', 'T1', '1 1']
> +=C2=A0 - ['T2', 'I1', '1 1']
> +=C2=A0 - ['T2', 'T2', '1 1']
> +...
> +--Cleaning up.
> +box.sql.execute("DROP TABLE t1;")
> +---
> +...
> +box.sql.execute("DROP TABLE t2;")
> +---
> +...
> +-- Same test but dropping an INDEX ON t2.
> +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);")
> +---
> +...
> +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);")
> +---
> +...
> +box.sql.execute("CREATE INDEX i1 ON t1(a);")
> +---
> +...
> +box.sql.execute("CREATE INDEX i1 ON t2(a);")
> +---
> +...
> +box.sql.execute("INSERT INTO t1 VALUES(1, 2);")
> +---
> +...
> +box.sql.execute("INSERT INTO t2 VALUES(1, 2);")
> +---
> +...
> +-- Analyze.
> +box.sql.execute("ANALYZE;")
> +---
> +...
> +-- Checking the data.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +---
> +- - ['T1', 'I1', '1', '0', '0'= ;, !!binary kQI=3D]
> +=C2=A0 - ['T1', 'T1', '1', '0', '= 0', !!binary kQE=3D]
> +=C2=A0 - ['T2', 'I1', '1', '0', '= 0', !!binary kQI=3D]
> +=C2=A0 - ['T2', 'T2', '1', '0', '= 0', !!binary kQE=3D]
> +...
> +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +---
> +- - ['T1', 'I1', '1 1']
> +=C2=A0 - ['T1', 'T1', '1 1']
> +=C2=A0 - ['T2', 'I1', '1 1']
> +=C2=A0 - ['T2', 'T2', '1 1']
> +...
> +-- Dropping an index.
> +box.sql.execute("DROP INDEX i1 ON t2;")
> +---
> +...
> +-- Checking the DROP INDEX results.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +---
> +- - ['T1', 'I1', '1', '0', '0'= ;, !!binary kQI=3D]
> +=C2=A0 - ['T1', 'T1', '1', '0', '= 0', !!binary kQE=3D]
> +=C2=A0 - ['T2', 'T2', '1', '0', '= 0', !!binary kQE=3D]
> +...
> +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +---
> +- - ['T1', 'I1', '1 1']
> +=C2=A0 - ['T1', 'T1', '1 1']
> +=C2=A0 - ['T2', 'T2', '1 1']
> +...
> +--Cleaning up.
> +box.sql.execute("DROP TABLE t1;")
> +---
> +...
> +box.sql.execute("DROP TABLE t2;")
> +---
> +...
> diff --git a/test/sql/sql-statN-index-drop.test.lua b/test/sql/sql-sta= tN-index-drop.test.lua
> new file mode 100644
> index 0000000..bf4a752
> --- /dev/null
> +++ b/test/sql/sql-statN-index-drop.test.lua
> @@ -0,0 +1,54 @@
> +test_run =3D require('test_run').new()
> +
> +-- Initializing some things.
> +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);")
> +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);")
> +box.sql.execute("CREATE INDEX i1 ON t1(a);")
> +box.sql.execute("CREATE INDEX i1 ON t2(a);")
> +box.sql.execute("INSERT INTO t1 VALUES(1, 2);")
> +box.sql.execute("INSERT INTO t2 VALUES(1, 2);")
> +
> +-- Analyze.
> +box.sql.execute("ANALYZE;")
> +
> +-- Checking the data.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +
> +-- Dropping an index.
> +box.sql.execute("DROP INDEX i1 ON t1;")
> +
> +-- Checking the DROP INDEX results.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +
> +--Cleaning up.
> +box.sql.execute("DROP TABLE t1;")
> +box.sql.execute("DROP TABLE t2;")
> +
> +-- Same test but dropping an INDEX ON t2.
> +
> +box.sql.execute("CREATE TABLE t1(id PRIMARY KEY, a);")
> +box.sql.execute("CREATE TABLE t2(id PRIMARY KEY, a);")
> +box.sql.execute("CREATE INDEX i1 ON t1(a);")
> +box.sql.execute("CREATE INDEX i1 ON t2(a);")
> +box.sql.execute("INSERT INTO t1 VALUES(1, 2);")
> +box.sql.execute("INSERT INTO t2 VALUES(1, 2);")
> +
> +-- Analyze.
> +box.sql.execute("ANALYZE;")
> +
> +-- Checking the data.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +
> +-- Dropping an index.
> +box.sql.execute("DROP INDEX i1 ON t2;")
> +
> +-- Checking the DROP INDEX results.
> +box.sql.execute("SELECT * FROM \"_sql_stat4\";")<= br> > +box.sql.execute("SELECT * FROM \"_sql_stat1\";")<= br> > +
> +--Cleaning up.
> +box.sql.execute("DROP TABLE t1;")
> +box.sql.execute("DROP TABLE t2;")
> --
> 2.7.4
>
>

Suggested changes were applied so this is diff:
=C2=A0
diff --git a/src/box/sql/build.c b/src/box/sql/buil= d.c
index 44d7548..16ae042 100644
--- a/src/box/sql/bui= ld.c
+++ b/src/box/sql/build.c
@@ -2206,34 +2206,35 @@ = sqliteViewResetAll(sqlite3 * db)
=C2=A0#define sqliteViewResetAll= (A,B)
=C2=A0#endif /* S= QLITE_OMIT_VIEW */
=C2=A0
-/*
+/**
= =C2=A0 * Remove entries from the _sql_statN tables (for N in (1, 4))
<= div>=C2=A0 * after a DROP INDEX or DROP TABLE command.
+ *=C2=A0<= /div>
+ * @param table_name table to be dropped or
+ *=C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0the table tha= t contains index to be dropped
+ * @param idx_name index to be dr= opped
=C2=A0 */
=C2=A0static void
-sql_clear_= stat_tables(Parse * pParse, /* The p= arsing context */
- =C2= =A0 =C2=A0 =C2=A0 =C2=A0const char *zType, = =C2=A0 =C2=A0 /* "idx" or "tbl" */
-= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0const char *table_na= me,=C2=A0 /* Name of the table*/
- =C2=A0 =C2=A0 =C2=A0 =C2=A0const char *idx_name /* Name of the index*/
-=C2=A0 =C2=A0 )
+sql_clear_stat_tables(Parse *parse,
+=C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0const char *table_name,
+ =C2=A0 =C2=A0 =C2=A0 =C2=A0const char *= idx_name)
=C2=A0{
-=C2=A0 =C2=A0 int i, j;
-= =C2=A0 =C2=A0 if(strcmp(zType, "idx") =3D=3D 0)
-=C2=A0= =C2=A0 =C2=A0 =C2=A0 for(i =3D 1, j =3D 1; i <=3D 2; i++, j++) {
<= div>-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 char zTab[24];
-= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3_snprintf(sizeof(zTab), zT= ab, "_sql_stat%d", i * j);
-=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 sqlite3NestedParse(pParse,
-=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "DELETE= FROM \"%s\" WHERE (\"idx\"=3D%Q AND "
-= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 "\"tbl\"=3D%Q)",
-=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 zTab,= idx_name, table_name);
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 }
= -=C2=A0 =C2=A0 else
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 for(i =3D 1, j = =3D 1; i <=3D 2; i++, j++) {
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 char zTab[24];
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 sqlite3_snprintf(sizeof(zTab), zTab, "_sql_stat%d", i * j);
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3NestedParse(pPar= se,
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 "DELETE FROM \"%s\" WHERE \"tb= l\"=3D%Q",
-=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 zTab, table_name);
+=C2= =A0 =C2=A0 if(idx_name) {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3Nes= tedParse(parse,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 "DELETE FROM \"_sql_stat1\" WHERE (\&q= uot;idx\"=3D%Q AND "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "\"tbl\"=3D%Q)",=
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 idx_name, table_name);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite= 3NestedParse(parse,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 "DELETE FROM \"_sql_stat4\" WHER= E (\"idx\"=3D%Q AND "
+=C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "\"tbl\"=3D%Q)&qu= ot;,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 idx_name, table_name);
+=C2=A0 =C2=A0 } else {
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3NestedParse(parse,
+=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 "DELET= E FROM \"_sql_stat1\" WHERE \"tbl\"=3D%Q",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 t= able_name);
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 sqlite3NestedParse(parse= ,
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 "DELETE FROM \"_sql_stat4\" WHERE \"tbl\"= =3D%Q",
+=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 table_name);
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0}
=C2=A0}
=C2=A0
@@ -2424,7 +2425,7 @@ sql= ite3DropTable(Parse * pParse, SrcList * pName, int isView, int noErr)
=
=C2=A0 */
=C2=A0
=C2=A0 sqlite3BeginWriteOpera= tion(pParse, 1);
-=C2=A0 =C2=A0 sql_clear_stat_tables(pParse, &qu= ot;tbl", pTab->zName, NULL);
+=C2=A0 =C2=A0 sql_clear_sta= t_tables(pParse, pTab->zName, NULL);
=C2=A0 sqlite3FkDropTable(pParse, pName, pTab);
=C2= =A0 sqlite3CodeDropTable(pParse, pTa= b, isView);
=C2=A0
@@ -3426,7 +3427,7 @@ sqlite3DropInd= ex(Parse * pParse, SrcList * pName, Token * pName2, int ifExists)
=C2=A0 * But firstly, delete stati= stics since schema
=C2=A0 = * changes after DDL.
=C2=A0 */
-=C2=A0 =C2=A0 sql_clear_stat_tables(pParse, "idx&quo= t;, pIndex->pTable->zName, pIndex->zName);
+=C2=A0 =C2= =A0 sql_clear_stat_tables(pParse, pIndex->pTable->zName, pIndex->z= Name);
=C2=A0 int record_r= eg =3D ++pParse->nMem;
=C2=A0 = int space_id_reg =3D ++pParse->nMem;
=C2=A0 sqlite3VdbeAddOp2(v, OP_Integer, SQLITE_PAGENO= _TO_SPACEID(pIndex->tnum),
diff --git a/test/xlog/checkpoint_d= aemon.result b/test/xlog/checkpoint_daemon.result
index d5ed666..= 1c28336 100644
--- a/test/xlog/checkpoint_daemon.result
+++ b/test/xlog/checkpoint_daemon.result
@@ -96,11 +96,11 @@ fib= er.sleep(3 * PERIOD)
=C2=A0-- check that it's not first snaps= hot
=C2=A0test_run:grep_log("default", "saving sna= pshot", 400) =3D=3D nil
=C2=A0---
-- true
+- false
=C2=A0...
=C2=A0test_run:grep_log("defa= ult", "making snapshot", 400) ~=3D nil
=C2=A0---
-- true
+- false
=C2=A0...
=C2=A0-- = restore default options
=C2=A0box.cfg{checkpoint_interval =3D 360= 0 * 4, checkpoint_count =3D 4 }
=C2=A0
--0000000000003ee917056907b917--