From 253695caf33a6cbf8c02e8af1e2f2a7e57ec04a0 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 23 Sep 2024 19:32:06 +0000 Subject: [PATCH 1/6] Fix a couple of problems with the sessions streaming interfaces. FossilOrigin-Name: 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e --- ext/session/sessionnoact.test | 1 + ext/session/sqlite3session.c | 32 ++++++++++++++++++++------------ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 30 insertions(+), 21 deletions(-) diff --git a/ext/session/sessionnoact.test b/ext/session/sessionnoact.test index 1274ecb146..aa1cde4749 100644 --- a/ext/session/sessionnoact.test +++ b/ext/session/sessionnoact.test @@ -82,6 +82,7 @@ do_execsql_test 1.5 { UPDATE p1 SET c=12345 WHERE a = 45; } +breakpoint sqlite3changeset_apply_v2 -noaction db $C conflict do_execsql_test 1.6 { SELECT * FROM c1 diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 5bab39b67f..f2eb942e68 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -74,6 +74,10 @@ struct SessionBuffer { ** input data. Input data may be supplied either as a single large buffer ** (e.g. sqlite3changeset_start()) or using a stream function (e.g. ** sqlite3changeset_start_strm()). +** +** bNoDiscard: +** If true, then the only time data is discarded is as a result of explicit +** sessionDiscardData() calls. Not within every sessionInputBuffer() call. */ struct SessionInput { int bNoDiscard; /* If true, do not discard in InputBuffer() */ @@ -5127,15 +5131,21 @@ static int sessionChangesetApply( int nTab = 0; /* Result of sqlite3Strlen30(zTab) */ SessionApplyCtx sApply; /* changeset_apply() context object */ int bPatchset; + u64 savedFlag = db->flags & SQLITE_FkNoAction; assert( xConflict!=0 ); + sqlite3_mutex_enter(sqlite3_db_mutex(db)); + if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ + db->flags |= ((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } + pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); sApply.bRebase = (ppRebase && pnRebase); sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP); - sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); } @@ -5297,6 +5307,12 @@ static int sessionChangesetApply( sqlite3_free((char*)sApply.azCol); /* cast works around VC++ bug */ sqlite3_free((char*)sApply.constraints.aBuf); sqlite3_free((char*)sApply.rebase.aBuf); + + if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ + assert( db->flags & SQLITE_FkNoAction ); + db->flags &= ~((u64)SQLITE_FkNoAction); + db->aDb[0].pSchema->schema_cookie -= 32; + } sqlite3_mutex_leave(sqlite3_db_mutex(db)); return rc; } @@ -5325,12 +5341,6 @@ int sqlite3changeset_apply_v2( sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ int bInv = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset, bInv, 1); - u64 savedFlag = db->flags & SQLITE_FkNoAction; - - if( flags & SQLITE_CHANGESETAPPLY_FKNOACTION ){ - db->flags |= ((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } if( rc==SQLITE_OK ){ rc = sessionChangesetApply( @@ -5338,11 +5348,6 @@ int sqlite3changeset_apply_v2( ); } - if( (flags & SQLITE_CHANGESETAPPLY_FKNOACTION) && savedFlag==0 ){ - assert( db->flags & SQLITE_FkNoAction ); - db->flags &= ~((u64)SQLITE_FkNoAction); - db->aDb[0].pSchema->schema_cookie -= 32; - } return rc; } @@ -5822,6 +5827,8 @@ static int sessionOneChangeToHash( u8 *aRec = &pIter->in.aData[pIter->in.iCurrent + 2]; int nRec = (pIter->in.iNext - pIter->in.iCurrent) - 2; + assert( nRec>0 ); + /* Ensure that only changesets, or only patchsets, but not a mixture ** of both, are being combined. It is an error to try to combine a ** changeset and a patchset. */ @@ -5899,6 +5906,7 @@ static int sessionChangesetToHash( int nRec; int rc = SQLITE_OK; + pIter->in.bNoDiscard = 1; while( SQLITE_ROW==(sessionChangesetNext(pIter, &aRec, &nRec, 0)) ){ rc = sessionOneChangeToHash(pGrp, pIter, bRebase); if( rc!=SQLITE_OK ) break; diff --git a/manifest b/manifest index ca881335f6..fe36820ed7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\srun-fuzzcheck\starget\sto\sthe\sMSVC\smakefile. -D 2024-09-21T17:27:47.017 +C Fix\sa\scouple\sof\sproblems\swith\sthe\ssessions\sstreaming\sinterfaces. +D 2024-09-23T19:32:06.996 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -586,7 +586,7 @@ F ext/session/sessionfault2.test b0d6a7c1d7398a7e800d84657404909c7d385965ea8576d F ext/session/sessionfault3.test ce0b5d182133935c224d72507dbf1c5be1a1febf7e85d0b0fbd6d2f724b32b96 F ext/session/sessioninvert.test 04075517a9497a80d39c495ba6b44f3982c7371129b89e2c52219819bc105a25 F ext/session/sessionmem.test f2a735db84a3e9e19f571033b725b0b2daf847f3f28b1da55a0c1a4e74f1de09 -F ext/session/sessionnoact.test 506526a5fe29421ecc50d371774ef1bb04cbd9d906a8a468f0556cdbde184c22 +F ext/session/sessionnoact.test 2563dff62a2a80dc7c88002241b2fd1578c3e5438735e180fb7e941ebbc66214 F ext/session/sessionnoop.test a9366a36a95ef85f8a3687856ebef46983df399541174cb1ede2ee53b8011bc7 F ext/session/sessionnoop2.test de4672dce88464396ec9f30ed08c6c01643a69c53ae540fadbbf6d30642d64e8 F ext/session/sessionrebase.test 702378bdcb5062f1106e74457beca8797d09c113a81768734a58b197b5b334e2 @@ -594,7 +594,7 @@ F ext/session/sessionrowid.test 85187c2f1b38861a5844868126f69f9ec62223a03449a98a F ext/session/sessionsize.test 8fcf4685993c3dbaa46a24183940ab9f5aa9ed0d23e5fb63bfffbdb56134b795 F ext/session/sessionstat1.test 5e718d5888c0c49bbb33a7a4f816366db85f59f6a4f97544a806421b85dc2dec F ext/session/sessionwor.test 6fd9a2256442cebde5b2284936ae9e0d54bde692d0f5fd009ecef8511f4cf3fc -F ext/session/sqlite3session.c c42c51c5a9dbc8bfd8c3e30fd96ff52b3357645f626427ccc39364fb2cb0a161 +F ext/session/sqlite3session.c 3d0a7f0f7a1c946e01818c716a55a40ae30542a29a9045cb05daf7fb658cdafa F ext/session/sqlite3session.h 683ccbf16e2c2521661fc4c1cf918ce57002039efbcabcd8097fa4bca569104b F ext/session/test_session.c aa29abdcc9011ac02f4fa38e8ede226106eaeee7c3ea7d8b2b999a124e0c368c F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 62e11a3a78edf9853b74d6495ccd8ae9ac1966c7d78eb3682cf2d5885e3740ec -R 44ce456c4e740a869984e636809287df -U drh -Z fb345da7ed81e5875e018c3667e473a3 +P 2e5194407a1b34dd0659c350ea8098bfef7b3f11aa5b2a07ecd2bce5582655a2 +R c974ccb75dc5dd67146277845a82ef69 +U dan +Z 223489687ee37b4a66c286a9ac7e3cc2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c7adf060ec..18a04f6232 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2e5194407a1b34dd0659c350ea8098bfef7b3f11aa5b2a07ecd2bce5582655a2 +9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e From 415acd09d7d0913002676782da8a3a78c7b38e91 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 24 Sep 2024 00:01:47 +0000 Subject: [PATCH 2/6] In the CLI, when displaying results in a columnar format, take into account zero-width and double-width Unicode characters. FossilOrigin-Name: 47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa --- manifest | 14 ++-- manifest.uuid | 2 +- src/shell.c.in | 217 +++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 211 insertions(+), 22 deletions(-) diff --git a/manifest b/manifest index fe36820ed7..5a7ccac4ee 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scouple\sof\sproblems\swith\sthe\ssessions\sstreaming\sinterfaces. -D 2024-09-23T19:32:06.996 +C In\sthe\sCLI,\swhen\sdisplaying\sresults\sin\sa\scolumnar\sformat,\stake\sinto\saccount\nzero-width\sand\sdouble-width\sUnicode\scharacters. +D 2024-09-24T00:01:47.656 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -768,7 +768,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c b2cd748488012312824508639b6af908461e45403037d5c4e19d9b0e8195507f F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4b14337a2742f0c0beeba490e9a05507e9b4b12184b9cd12773501d08d48e3fe -F src/shell.c.in 375f8a183126be96ec73db4e42c57917ff10a0900846b1b722dd4f8cef537812 +F src/shell.c.in 732f0fba9d956854e540f8f86deba6b65710f2f24aa0aa5381fb365f28c2ca1b F src/sqlite.h.in 77f55bd1978a04a14db211732f0a609077cf60ba4ccf9baf39988f508945419c F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2e5194407a1b34dd0659c350ea8098bfef7b3f11aa5b2a07ecd2bce5582655a2 -R c974ccb75dc5dd67146277845a82ef69 -U dan -Z 223489687ee37b4a66c286a9ac7e3cc2 +P 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e +R 988b7d0f85db9a0b2a0485e0d9883734 +U drh +Z fd42c54152b4ee78f4ca90da8d2b64c2 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 18a04f6232..2557008e97 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e +47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa diff --git a/src/shell.c.in b/src/shell.c.in index 2b0e506ed8..8185e4c4ce 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -670,24 +670,195 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ } #endif +/* Lookup table to determine the number of columns consumed by a Unicode +** character. +*/ +static const struct { + unsigned char w; /* Width of the character in columns */ + int iFirst; /* First character in a span having this width */ +} aUWidth[] = { + /* {0, 0x00000}, {1, 0x00020}, {0, 0x0007f}, {1, 0x000a0}, */ + {0, 0x00300}, {1, 0x00370}, {0, 0x00483}, {1, 0x00487}, {0, 0x00488}, + {1, 0x0048a}, {0, 0x00591}, {1, 0x005be}, {0, 0x005bf}, {1, 0x005c0}, + {0, 0x005c1}, {1, 0x005c3}, {0, 0x005c4}, {1, 0x005c6}, {0, 0x005c7}, + {1, 0x005c8}, {0, 0x00600}, {1, 0x00604}, {0, 0x00610}, {1, 0x00616}, + {0, 0x0064b}, {1, 0x0065f}, {0, 0x00670}, {1, 0x00671}, {0, 0x006d6}, + {1, 0x006e5}, {0, 0x006e7}, {1, 0x006e9}, {0, 0x006ea}, {1, 0x006ee}, + {0, 0x0070f}, {1, 0x00710}, {0, 0x00711}, {1, 0x00712}, {0, 0x00730}, + {1, 0x0074b}, {0, 0x007a6}, {1, 0x007b1}, {0, 0x007eb}, {1, 0x007f4}, + {0, 0x00901}, {1, 0x00903}, {0, 0x0093c}, {1, 0x0093d}, {0, 0x00941}, + {1, 0x00949}, {0, 0x0094d}, {1, 0x0094e}, {0, 0x00951}, {1, 0x00955}, + {0, 0x00962}, {1, 0x00964}, {0, 0x00981}, {1, 0x00982}, {0, 0x009bc}, + {1, 0x009bd}, {0, 0x009c1}, {1, 0x009c5}, {0, 0x009cd}, {1, 0x009ce}, + {0, 0x009e2}, {1, 0x009e4}, {0, 0x00a01}, {1, 0x00a03}, {0, 0x00a3c}, + {1, 0x00a3d}, {0, 0x00a41}, {1, 0x00a43}, {0, 0x00a47}, {1, 0x00a49}, + {0, 0x00a4b}, {1, 0x00a4e}, {0, 0x00a70}, {1, 0x00a72}, {0, 0x00a81}, + {1, 0x00a83}, {0, 0x00abc}, {1, 0x00abd}, {0, 0x00ac1}, {1, 0x00ac6}, + {0, 0x00ac7}, {1, 0x00ac9}, {0, 0x00acd}, {1, 0x00ace}, {0, 0x00ae2}, + {1, 0x00ae4}, {0, 0x00b01}, {1, 0x00b02}, {0, 0x00b3c}, {1, 0x00b3d}, + {0, 0x00b3f}, {1, 0x00b40}, {0, 0x00b41}, {1, 0x00b44}, {0, 0x00b4d}, + {1, 0x00b4e}, {0, 0x00b56}, {1, 0x00b57}, {0, 0x00b82}, {1, 0x00b83}, + {0, 0x00bc0}, {1, 0x00bc1}, {0, 0x00bcd}, {1, 0x00bce}, {0, 0x00c3e}, + {1, 0x00c41}, {0, 0x00c46}, {1, 0x00c49}, {0, 0x00c4a}, {1, 0x00c4e}, + {0, 0x00c55}, {1, 0x00c57}, {0, 0x00cbc}, {1, 0x00cbd}, {0, 0x00cbf}, + {1, 0x00cc0}, {0, 0x00cc6}, {1, 0x00cc7}, {0, 0x00ccc}, {1, 0x00cce}, + {0, 0x00ce2}, {1, 0x00ce4}, {0, 0x00d41}, {1, 0x00d44}, {0, 0x00d4d}, + {1, 0x00d4e}, {0, 0x00dca}, {1, 0x00dcb}, {0, 0x00dd2}, {1, 0x00dd5}, + {0, 0x00dd6}, {1, 0x00dd7}, {0, 0x00e31}, {1, 0x00e32}, {0, 0x00e34}, + {1, 0x00e3b}, {0, 0x00e47}, {1, 0x00e4f}, {0, 0x00eb1}, {1, 0x00eb2}, + {0, 0x00eb4}, {1, 0x00eba}, {0, 0x00ebb}, {1, 0x00ebd}, {0, 0x00ec8}, + {1, 0x00ece}, {0, 0x00f18}, {1, 0x00f1a}, {0, 0x00f35}, {1, 0x00f36}, + {0, 0x00f37}, {1, 0x00f38}, {0, 0x00f39}, {1, 0x00f3a}, {0, 0x00f71}, + {1, 0x00f7f}, {0, 0x00f80}, {1, 0x00f85}, {0, 0x00f86}, {1, 0x00f88}, + {0, 0x00f90}, {1, 0x00f98}, {0, 0x00f99}, {1, 0x00fbd}, {0, 0x00fc6}, + {1, 0x00fc7}, {0, 0x0102d}, {1, 0x01031}, {0, 0x01032}, {1, 0x01033}, + {0, 0x01036}, {1, 0x01038}, {0, 0x01039}, {1, 0x0103a}, {0, 0x01058}, + {1, 0x0105a}, {2, 0x01100}, {0, 0x01160}, {1, 0x01200}, {0, 0x0135f}, + {1, 0x01360}, {0, 0x01712}, {1, 0x01715}, {0, 0x01732}, {1, 0x01735}, + {0, 0x01752}, {1, 0x01754}, {0, 0x01772}, {1, 0x01774}, {0, 0x017b4}, + {1, 0x017b6}, {0, 0x017b7}, {1, 0x017be}, {0, 0x017c6}, {1, 0x017c7}, + {0, 0x017c9}, {1, 0x017d4}, {0, 0x017dd}, {1, 0x017de}, {0, 0x0180b}, + {1, 0x0180e}, {0, 0x018a9}, {1, 0x018aa}, {0, 0x01920}, {1, 0x01923}, + {0, 0x01927}, {1, 0x01929}, {0, 0x01932}, {1, 0x01933}, {0, 0x01939}, + {1, 0x0193c}, {0, 0x01a17}, {1, 0x01a19}, {0, 0x01b00}, {1, 0x01b04}, + {0, 0x01b34}, {1, 0x01b35}, {0, 0x01b36}, {1, 0x01b3b}, {0, 0x01b3c}, + {1, 0x01b3d}, {0, 0x01b42}, {1, 0x01b43}, {0, 0x01b6b}, {1, 0x01b74}, + {0, 0x01dc0}, {1, 0x01dcb}, {0, 0x01dfe}, {1, 0x01e00}, {0, 0x0200b}, + {1, 0x02010}, {0, 0x0202a}, {1, 0x0202f}, {0, 0x02060}, {1, 0x02064}, + {0, 0x0206a}, {1, 0x02070}, {0, 0x020d0}, {1, 0x020f0}, {2, 0x02329}, + {1, 0x0232b}, {2, 0x02e80}, {0, 0x0302a}, {2, 0x03030}, {1, 0x0303f}, + {2, 0x03040}, {0, 0x03099}, {2, 0x0309b}, {1, 0x0a4d0}, {0, 0x0a806}, + {1, 0x0a807}, {0, 0x0a80b}, {1, 0x0a80c}, {0, 0x0a825}, {1, 0x0a827}, + {2, 0x0ac00}, {1, 0x0d7a4}, {2, 0x0f900}, {1, 0x0fb00}, {0, 0x0fb1e}, + {1, 0x0fb1f}, {0, 0x0fe00}, {2, 0x0fe10}, {1, 0x0fe1a}, {0, 0x0fe20}, + {1, 0x0fe24}, {2, 0x0fe30}, {1, 0x0fe70}, {0, 0x0feff}, {2, 0x0ff00}, + {1, 0x0ff61}, {2, 0x0ffe0}, {1, 0x0ffe7}, {0, 0x0fff9}, {1, 0x0fffc}, + {0, 0x10a01}, {1, 0x10a04}, {0, 0x10a05}, {1, 0x10a07}, {0, 0x10a0c}, + {1, 0x10a10}, {0, 0x10a38}, {1, 0x10a3b}, {0, 0x10a3f}, {1, 0x10a40}, + {0, 0x1d167}, {1, 0x1d16a}, {0, 0x1d173}, {1, 0x1d183}, {0, 0x1d185}, + {1, 0x1d18c}, {0, 0x1d1aa}, {1, 0x1d1ae}, {0, 0x1d242}, {1, 0x1d245}, + {2, 0x20000}, {1, 0x2fffe}, {2, 0x30000}, {1, 0x3fffe}, {0, 0xe0001}, + {1, 0xe0002}, {0, 0xe0020}, {1, 0xe0080}, {0, 0xe0100}, {1, 0xe01f0} +}; + /* -** Output string zUtf to Out stream as w characters. If w is negative, +** Return the width, in columns, of the single Unicode character c. +** For normal characters, the answer is always 1. But it might be 0 or 2 +** for zero-width and double-width characters. +*/ +int cli_wcwidth(int c){ + int iFirst, iLast; + + /* Fast path for common characters */ + if( c<0x20 ) return 0; + if( c<0x7f ) return 1; + if( c<0xa0 ) return 0; + if( c<=0x300 ) return 1; + + /* The general case */ + iFirst = 0; + iLast = sizeof(aUWidth)/sizeof(aUWidth[0]) - 1; + while( iFirst c ){ + iLast = iMid - 1; + }else{ + return aUWidth[iMid].w; + } + } + if( aUWidth[iLast].iFirst > c ) return aUWidth[iFirst].w; + return aUWidth[iLast].w; +} + +/* +** Compute the value and length of a multi-byte UTF-8 character that +** begins at z[0]. Return the length. Write the Unicode value into *pU. +*/ +static int decodeUtf8(const unsigned char *z, int *pU){ + if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){ + *pU = ((z[0] & 0x1f)<<6) | (z[1] & 0x3f); + return 2; + } + if( (z[0] & 0xf0)==0xe0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 ){ + *pU = ((z[0] & 0x0f)<<12) | ((z[1] & 0x3f)<<6) | (z[2] & 0x3f); + return 3; + } + if( (z[0] & 0xf8)==0xf0 && (z[1] & 0xc0)==0x80 && (z[2] & 0xc0)==0x80 + && (z[3] & 0xc0)==0x80 + ){ + *pU = ((z[0] & 0x0f)<<18) | ((z[1] & 0x3f)<<12) | ((z[2] & 0x3f))<<6 + | (z[4] & 0x3f); + return 4; + } + *pU = 0; + return 1; +} + + +#if 0 /* NOT USED */ +/* +** Return the width, in display columns, of a UTF-8 string. +** +** Each normal character counts as 1. Zero-width characters count +** as zero, and double-width characters count as 2. +*/ +int cli_wcswidth(const char *z){ + const unsigned char *a = (const unsigned char*)z; + int n = 0; + int i = 0; + unsigned char c; + while( (c = a[i])!=0 ){ + if( c>=0xc0 ){ + int u; + int len = decodeUtf8(&a[i], &u); + i += len; + n += cli_wcwidth(u); + }else if( c>=' ' ){ + n++; + i++; + }else{ + i++; + } + } + return n; +} +#endif + +/* +** Output string zUtf to stdout as w characters. If w is negative, ** then right-justify the text. W is the width in UTF-8 characters, not ** in bytes. This is different from the %*.*s specification in printf ** since with %*.*s the width is measured in bytes, not characters. +** +** Take into account zero-width and double-width Unicode characters. +** In other words, a zero-width character does not count toward the +** the w limit. A double-width character counts as two. */ static void utf8_width_print(int w, const char *zUtf){ - int i; - int n; + const unsigned char *a = (const unsigned char*)zUtf; + unsigned char c; + int i = 0; + int n = 0; int aw = w<0 ? -w : w; if( zUtf==0 ) zUtf = ""; - for(i=n=0; zUtf[i]; i++){ - if( (zUtf[i]&0xc0)!=0x80 ){ - n++; - if( n==aw ){ - do{ i++; }while( (zUtf[i]&0xc0)==0x80 ); + while( (c = a[i])!=0 ){ + if( (c&0xc0)==0xc0 ){ + int u; + int len = decodeUtf8(a+i, &u); + int x = cli_wcwidth(u); + if( x+n>aw ){ break; } + i += len; + n += x; + }else if( n>=aw ){ + break; + }else{ + n++; + i++; } } if( n>=aw ){ @@ -3670,12 +3841,22 @@ static char *translateForDisplayAndDup( if( mxWidth==0 ) mxWidth = 1000000; i = j = n = 0; while( n=' ' ){ - n++; - do{ i++; j++; }while( (z[i]&0xc0)==0x80 ); + unsigned char c = z[i]; + if( c>=0xc0 ){ + int u; + int len = decodeUtf8(&z[i], &u); + i += len; + j += len; + n += cli_wcwidth(u); continue; } - if( z[i]=='\t' ){ + if( c>=' ' ){ + n++; + i++; + j++; + continue; + } + if( c=='\t' ){ do{ n++; j++; @@ -3717,9 +3898,17 @@ static char *translateForDisplayAndDup( shell_check_oom(zOut); i = j = n = 0; while( i=' ' ){ + unsigned char c = z[i]; + if( c>=0xc0 ){ + int u; + int len = decodeUtf8(&z[i], &u); + do{ zOut[j++] = z[i++]; }while( (--len)>0 ); + n += cli_wcwidth(u); + continue; + } + if( c>=' ' ){ n++; - do{ zOut[j++] = z[i++]; }while( (z[i]&0xc0)==0x80 ); + zOut[j++] = z[i++]; continue; } if( z[i]=='\t' ){ From 7d24e6b08076222efc7a4184b268c8776b7b2ff6 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 24 Sep 2024 00:53:27 +0000 Subject: [PATCH 3/6] Remove an ALWAYS() that can sometimes be false, with wildly incorrect SQL inputs. dbsqlfuzz 707afcf73930de2624cdeca0ad1f0deea982dfea FossilOrigin-Name: 766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/resolve.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index fe36820ed7..a5789cf797 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\scouple\sof\sproblems\swith\sthe\ssessions\sstreaming\sinterfaces. -D 2024-09-23T19:32:06.996 +C Remove\san\sALWAYS()\sthat\scan\ssometimes\sbe\sfalse,\swith\swildly\sincorrect\sSQL\ninputs.\s\sdbsqlfuzz\s707afcf73930de2624cdeca0ad1f0deea982dfea +D 2024-09-24T00:53:27.928 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -765,7 +765,7 @@ F src/pragma.h e690a356c18e98414d2e870ea791c1be1545a714ba623719deb63f7f226d8bb7 F src/prepare.c 3ba0ad907b7773ed642f66cea8a2c9c8edc18841aa1050b6218dbb3479e86225 F src/printf.c 6a87534ebfb9e5346011191b1f3a7ebc457f5938c7e4feeea478ecf53f6a41b2 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c -F src/resolve.c b2cd748488012312824508639b6af908461e45403037d5c4e19d9b0e8195507f +F src/resolve.c 9750a281f7ba073b4e6da2be1a6c4071f5d841a7746c5fb3f70d6d793b6675ea F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4b14337a2742f0c0beeba490e9a05507e9b4b12184b9cd12773501d08d48e3fe F src/shell.c.in 375f8a183126be96ec73db4e42c57917ff10a0900846b1b722dd4f8cef537812 @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 2e5194407a1b34dd0659c350ea8098bfef7b3f11aa5b2a07ecd2bce5582655a2 -R c974ccb75dc5dd67146277845a82ef69 -U dan -Z 223489687ee37b4a66c286a9ac7e3cc2 +P 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e +R d5e0e0bf96e6589b06b08a7ed11d078b +U drh +Z 402b4730d643c0eedb6276888911042c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 18a04f6232..87f3e6875d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e +766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08 diff --git a/src/resolve.c b/src/resolve.c index 2e4462ac0a..8e8da66910 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -486,7 +486,7 @@ static int lookupName( */ if( cntTab==0 || (cntTab==1 - && ALWAYS(pMatch!=0) + && pMatch!=0 && ALWAYS(pMatch->pSTab!=0) && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0 && (pTab->tabFlags & TF_Ephemeral)==0) From 3c90b8637239c31084445fa0b515afc1deaddcdb Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 24 Sep 2024 11:26:21 +0000 Subject: [PATCH 4/6] Avoid an error in sqlite3expert if the database has existing indexes on expressions. FossilOrigin-Name: f1d76c8636866424fe0b57d8814b8bb1a0ed4e2ca1b75d8e308d4b962ad8dc3b --- ext/expert/expert1.test | 3 +++ ext/expert/sqlite3expert.c | 5 +++++ manifest | 16 ++++++++-------- manifest.uuid | 2 +- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test index 72c4fd72cd..41c59d49db 100644 --- a/ext/expert/expert1.test +++ b/ext/expert/expert1.test @@ -428,6 +428,8 @@ do_execsql_test 5.0 { WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s; + + CREATE INDEX i1 ON t1( lower(a) ); } do_candidates_test 5.1 { SELECT * FROM t1,t2 WHERE (b=? OR a=?) AND (c=? OR d=?) @@ -457,6 +459,7 @@ do_execsql_test 5.3 { ANALYZE; SELECT * FROM sqlite_stat1 ORDER BY 1, 2; } { + t1 i1 {100 50} t1 t1_idx_00000061 {100 50} t1 t1_idx_00000062 {100 20} t1 t1_idx_000123a7 {100 50 17} diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c index b59a59728d..082ce45a5b 100644 --- a/ext/expert/sqlite3expert.c +++ b/ext/expert/sqlite3expert.c @@ -1623,6 +1623,11 @@ static int idxPopulateOneStat1( const char *zComma = zCols==0 ? "" : ", "; const char *zName = (const char*)sqlite3_column_text(pIndexXInfo, 0); const char *zColl = (const char*)sqlite3_column_text(pIndexXInfo, 1); + if( zName==0 ){ + /* This index contains an expression. Ignore it. */ + sqlite3_free(zCols); + return sqlite3_reset(pIndexXInfo); + } zCols = idxAppendText(&rc, zCols, "%sx.%Q IS sqlite_expert_rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl diff --git a/manifest b/manifest index a5789cf797..04efac87bc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sALWAYS()\sthat\scan\ssometimes\sbe\sfalse,\swith\swildly\sincorrect\sSQL\ninputs.\s\sdbsqlfuzz\s707afcf73930de2624cdeca0ad1f0deea982dfea -D 2024-09-24T00:53:27.928 +C Avoid\san\serror\sin\ssqlite3expert\sif\sthe\sdatabase\shas\sexisting\sindexes\son\sexpressions. +D 2024-09-24T11:26:21.974 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -57,8 +57,8 @@ F ext/consio/console_io.c d2b74afae8d301de2e8447b1045fcd33eb59df13bf581d906d99c7 F ext/consio/console_io.h b5ebe34aa15b357621ebbea3d3f2e2b24750d4280b5802516409e23947fd9ee5 F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3 F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4 -F ext/expert/expert1.test 661f873fd451127edf822ef0d520088faa319135f6a15bd10be6801ac284ac9b -F ext/expert/sqlite3expert.c 8b09aeb2b95a9fca8b6628b522bf4d69aa746ff64c38eb1e99a9b5fad8cf03b9 +F ext/expert/expert1.test fd13123932d60f535e2d589d704dc259d2f00e98e1ddc09deb807d1655aef9d1 +F ext/expert/sqlite3expert.c 79d90612e43ba71818a5d458412489ff80f0c01449e324f83c0d795ef1993974 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c b767b2039a0df707eb3147e86bcf68b252d8455d9a41774b1a836cd052ceca70 F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c7cc3bf59ee @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e -R d5e0e0bf96e6589b06b08a7ed11d078b -U drh -Z 402b4730d643c0eedb6276888911042c +P 766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08 +R f0b2fb4d0f36e0f6f4e7bc3a0dfe75ab +U dan +Z e6e4bf2a760ba7d64af8767b4d70ff5b # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 87f3e6875d..105d181391 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08 +f1d76c8636866424fe0b57d8814b8bb1a0ed4e2ca1b75d8e308d4b962ad8dc3b From 29057f3d185e9c278d48df341805f68ea9cf5509 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 24 Sep 2024 15:11:34 +0000 Subject: [PATCH 5/6] Fix a memory leak in sqlite3expert.c introduced by [f1d76c86]. FossilOrigin-Name: 42bb941584a1ac922ee6b0b6ecadce71c9259555563cf49913a6f820f3f9b887 --- ext/expert/expert1.test | 13 +++++++++++++ ext/expert/sqlite3expert.c | 1 + manifest | 14 +++++++------- manifest.uuid | 2 +- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ext/expert/expert1.test b/ext/expert/expert1.test index 41c59d49db..239450442e 100644 --- a/ext/expert/expert1.test +++ b/ext/expert/expert1.test @@ -494,4 +494,17 @@ USE TEMP B-TREE FOR ORDER BY }} } +do_execsql_test 6.0 { + CREATE TABLE x1(a, b, c, d); + CREATE INDEX x1ab ON x1(a, lower(b)); + CREATE INDEX x1dcba ON x1(d, b+c, a); +} + +do_candidates_test 6.1 { + SELECT * FROM x1 WHERE b=? ORDER BY a; +} { + CREATE INDEX x1_idx_0001267f ON x1(b, a); + CREATE INDEX x1_idx_00000062 ON x1(b); +} + finish_test diff --git a/ext/expert/sqlite3expert.c b/ext/expert/sqlite3expert.c index 082ce45a5b..3177339584 100644 --- a/ext/expert/sqlite3expert.c +++ b/ext/expert/sqlite3expert.c @@ -1626,6 +1626,7 @@ static int idxPopulateOneStat1( if( zName==0 ){ /* This index contains an expression. Ignore it. */ sqlite3_free(zCols); + sqlite3_free(zOrder); return sqlite3_reset(pIndexXInfo); } zCols = idxAppendText(&rc, zCols, diff --git a/manifest b/manifest index 04efac87bc..5a40bbd21d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Avoid\san\serror\sin\ssqlite3expert\sif\sthe\sdatabase\shas\sexisting\sindexes\son\sexpressions. -D 2024-09-24T11:26:21.974 +C Fix\sa\smemory\sleak\sin\ssqlite3expert.c\sintroduced\sby\s[f1d76c86]. +D 2024-09-24T15:11:34.516 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -57,8 +57,8 @@ F ext/consio/console_io.c d2b74afae8d301de2e8447b1045fcd33eb59df13bf581d906d99c7 F ext/consio/console_io.h b5ebe34aa15b357621ebbea3d3f2e2b24750d4280b5802516409e23947fd9ee5 F ext/expert/README.md b321c2762bb93c18ea102d5a5f7753a4b8bac646cb392b3b437f633caf2020c3 F ext/expert/expert.c d548d603a4cc9e61f446cc179c120c6713511c413f82a4a32b1e1e69d3f086a4 -F ext/expert/expert1.test fd13123932d60f535e2d589d704dc259d2f00e98e1ddc09deb807d1655aef9d1 -F ext/expert/sqlite3expert.c 79d90612e43ba71818a5d458412489ff80f0c01449e324f83c0d795ef1993974 +F ext/expert/expert1.test b10f9e20f64102a015c0fcf54cb7b7680266b397e91d93cdad45f57857cdfba6 +F ext/expert/sqlite3expert.c df417a6d91873a74d35daa9259171647c23c6601415e938e8a71702703f3d677 F ext/expert/sqlite3expert.h ca81efc2679a92373a13a3e76a6138d0310e32be53d6c3bfaedabd158ea8969b F ext/expert/test_expert.c b767b2039a0df707eb3147e86bcf68b252d8455d9a41774b1a836cd052ceca70 F ext/fts3/README.content b9078d0843a094d86af0d48dffbff13c906702b4c3558012e67b9c7cc3bf59ee @@ -2213,8 +2213,8 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 766cf5535b9f51decd88c1736b988def929a90f68eb6a52bcaa21bb321586a08 -R f0b2fb4d0f36e0f6f4e7bc3a0dfe75ab +P f1d76c8636866424fe0b57d8814b8bb1a0ed4e2ca1b75d8e308d4b962ad8dc3b +R 3c493af72ec7c0caf9ac1da3817622db U dan -Z e6e4bf2a760ba7d64af8767b4d70ff5b +Z 3984c94792299f2aa3da5c0fd5ebea46 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 105d181391..f9ccf18fa5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f1d76c8636866424fe0b57d8814b8bb1a0ed4e2ca1b75d8e308d4b962ad8dc3b +42bb941584a1ac922ee6b0b6ecadce71c9259555563cf49913a6f820f3f9b887 From f4382b2415fcaf982e6a4732db8168cef133c0e3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 25 Sep 2024 09:33:14 +0000 Subject: [PATCH 6/6] Improvements to comments on data structures and subroutines. FossilOrigin-Name: b217e3004b58af0e777726bdd652b999ad41815261299ef4ce8f8d2f6b0afe8d --- manifest | 13 +++++++------ manifest.uuid | 2 +- src/shell.c.in | 15 +++++++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 5a7ccac4ee..12999b09d5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\swhen\sdisplaying\sresults\sin\sa\scolumnar\sformat,\stake\sinto\saccount\nzero-width\sand\sdouble-width\sUnicode\scharacters. -D 2024-09-24T00:01:47.656 +C Improvements\sto\scomments\son\sdata\sstructures\sand\ssubroutines. +D 2024-09-25T09:33:14.835 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -768,7 +768,7 @@ F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c b2cd748488012312824508639b6af908461e45403037d5c4e19d9b0e8195507f F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 F src/select.c 4b14337a2742f0c0beeba490e9a05507e9b4b12184b9cd12773501d08d48e3fe -F src/shell.c.in 732f0fba9d956854e540f8f86deba6b65710f2f24aa0aa5381fb365f28c2ca1b +F src/shell.c.in 9b68a945f3aafc78eac1a256a4a588a9310dbc61a0cd60378c5b7a78f789af50 F src/sqlite.h.in 77f55bd1978a04a14db211732f0a609077cf60ba4ccf9baf39988f508945419c F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54 @@ -2213,8 +2213,9 @@ F vsixtest/vsixtest.tcl 6195aba1f12a5e10efc2b8c0009532167be5e301abe5b31385638080 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9a1fc8d36b5b262f9d17a4743b4b9bb54510cf257d2d9778ebc42d5224856b1e -R 988b7d0f85db9a0b2a0485e0d9883734 +P 47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa +R 711914e97aae1631ec1aaf0c7dbc2c36 +T +closed 47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa U drh -Z fd42c54152b4ee78f4ca90da8d2b64c2 +Z 9e5bc0454c6f58b185adbeed59d6a33c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2557008e97..a769bd751d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -47cfad71eddc6fc4414ff853ee172da72527620eee743721806072c6e0a80caa +b217e3004b58af0e777726bdd652b999ad41815261299ef4ce8f8d2f6b0afe8d diff --git a/src/shell.c.in b/src/shell.c.in index 8185e4c4ce..f40fdaecbc 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -670,7 +670,7 @@ static void SQLITE_CDECL iotracePrintf(const char *zFormat, ...){ } #endif -/* Lookup table to determine the number of columns consumed by a Unicode +/* Lookup table to estimate the number of columns consumed by a Unicode ** character. */ static const struct { @@ -742,9 +742,14 @@ static const struct { }; /* -** Return the width, in columns, of the single Unicode character c. -** For normal characters, the answer is always 1. But it might be 0 or 2 -** for zero-width and double-width characters. +** Return an estimate of the width, in columns, for the single Unicode +** character c. For normal characters, the answer is always 1. But the +** estimate might be 0 or 2 for zero-width and double-width characters. +** +** Different display devices display unicode using different widths. So +** it is impossible to know that true display width with 100% accuracy. +** Inaccuracies in the width estimates might cause columns to be misaligned. +** Unfortunately, there is nothing we can do about that. */ int cli_wcwidth(int c){ int iFirst, iLast; @@ -776,6 +781,8 @@ int cli_wcwidth(int c){ /* ** Compute the value and length of a multi-byte UTF-8 character that ** begins at z[0]. Return the length. Write the Unicode value into *pU. +** +** This routine only works for *multi-byte* UTF-8 characters. */ static int decodeUtf8(const unsigned char *z, int *pU){ if( (z[0] & 0xe0)==0xc0 && (z[1] & 0xc0)==0x80 ){