Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a40455276b | |||
| e9a6be4d19 | |||
| 1511157bca | |||
| ca1a5f8c36 | |||
| a21be19757 | |||
| e51c78fa6a | |||
| c5fd44ca8a | |||
| a7176860f3 | |||
| ffada0ebcb | |||
| 752cb42dc7 | |||
| a175b463a9 | |||
| 40df47d151 |
@@ -1,5 +1,5 @@
|
||||
C Fix\sharmless\scompiler\swarnings\sin\stest\scode\sfor\sthe\sintck\sextension.
|
||||
D 2024-03-07T15:58:06.345
|
||||
C Improved\serror\shandling.
|
||||
D 2024-03-07T18:47:28.960
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
|
||||
@@ -709,7 +709,7 @@ F src/hash.c 9ee4269fb1d6632a6fecfb9479c93a1f29271bddbbaf215dd60420bcb80c7220
|
||||
F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51
|
||||
F src/hwtime.h f9c2dfb84dce7acf95ce6d289e46f5f9d3d1afd328e53da8f8e9008e3b3caae6
|
||||
F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
|
||||
F src/insert.c 3f0a94082d978bbdd33c38fefea15346c6c6bffb70bc645a71dc0f1f87dd3276
|
||||
F src/insert.c fc8603b247e63bda37f0142df0256871458bfa6171fc75501ac20b1c9336bc17
|
||||
F src/json.c e2e40760d6689134c3e2ece38c6a496b34ff5e2661a8f238444a119af666fdce
|
||||
F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa
|
||||
F src/loadext.c 7432c944ff197046d67a1207790a1b13eec4548c85a9457eb0896bb3641dfb36
|
||||
@@ -739,7 +739,7 @@ F src/os_win.c 6ff43bac175bd9ed79e7c0f96840b139f2f51d01689a638fd05128becf94908a
|
||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||
F src/pager.c ff60e98138d2499082ac6230f01ac508aba545315debccfca2fd6042f5f10fcd
|
||||
F src/pager.h 4b1140d691860de0be1347474c51fee07d5420bd7f802d38cbab8ea4ab9f538a
|
||||
F src/parse.y 6209f01e8e7495379571454744fa82a5cfc2e7eeb89e46dee3f410d73ea6252d
|
||||
F src/parse.y c00b2d30f16654209145d1fe58833cbdcc9e55631d9a6c7416290c097c1e232a
|
||||
F src/pcache.c 040b165f30622a21b7a9a77c6f2e4877a32fb7f22d4c7f0d2a6fa6833a156a75
|
||||
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
|
||||
F src/pcache1.c 602acb23c471bb8d557a6f0083cc2be641d6cafcafa19e481eba7ef4c9ca0f00
|
||||
@@ -755,7 +755,7 @@ F src/shell.c.in 78bbd861cd0128aed67c0136561572ebcf11649be6cea86bee8491576d5958d
|
||||
F src/sqlite.h.in 19a2db3995a699bd7f6dfb423856242bfceb7ec849a93c91d241d19fc28d9f0f
|
||||
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
|
||||
F src/sqlite3ext.h 3f046c04ea3595d6bfda99b781926b17e672fd6d27da2ba6d8d8fc39981dcb54
|
||||
F src/sqliteInt.h 58b7295a748ca5ed9e211510205b4a66a24c68f864225b81e19d4cf6038b40a1
|
||||
F src/sqliteInt.h c59487cb4b80d72b7f9ba72db1dd8eb8c1b5d7413aa344baf8d1ffcd5e6a7ccf
|
||||
F src/sqliteLimit.h 6878ab64bdeb8c24a1d762d45635e34b96da21132179023338c93f820eee6728
|
||||
F src/status.c cb11f8589a6912af2da3bb1ec509a94dd8ef27df4d4c1a97e0bcf2309ece972b
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -1583,7 +1583,7 @@ F test/selectC.test 38c530b0cc5728b793c3c11f52b52c70290d39822224acd39011c89c1853
|
||||
F test/selectD.test 6d1909b49970bf92f45ce657505befcef5fc7cbc13544e18103a316d32189bfb
|
||||
F test/selectE.test a8730ca330fcf40ace158f134f4fe0eb00c7edbf
|
||||
F test/selectF.test 21c94e6438f76537b72532fa9fd4710cdd455fc3
|
||||
F test/selectG.test 089f7d3d7e6db91566f00b036cb353107a2cca6220eb1cb264085a836dae8840
|
||||
F test/selectG.test 4088930ac4c7ad3f94e283bfd65c7a7ed80b448355c94d599fb14855c0a74455
|
||||
F test/selectH.test 0b54599f1917d99568c9b929df22ec6261ed7b6d2f02a46b5945ef81b7871aac
|
||||
F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be
|
||||
F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb
|
||||
@@ -1921,6 +1921,8 @@ F test/vacuum4.test 7ea76b769fffeb41f925303b04cbcf5a5bbeabe55e4c60ae754ff24eeeb7
|
||||
F test/vacuum5.test 263b144d537e92ad8e9ca8a73cc6e1583f41cfd0dda9432b87f7806174a2f48c
|
||||
F test/vacuum6.test b137b04bf3392d3f5c3b8fda0ce85a6775a70ca112f6559f74ff52dc9ce042fd
|
||||
F test/vacuummem.test 4b30f5b95a9ff86e9d5c20741e50a898b2dc10b0962a3211571eb165357003fb
|
||||
F test/values.test 402810384b43afc7b3fdf7b93970debe519ab9fdafdbeb89521df09246639014
|
||||
F test/valuesfault.test 2ef23ed965e3bd08e268cdc38a0d11653390ddbbe1e8e2e98d16f55edd30f6e8
|
||||
F test/varint.test bbce22cda8fc4d135bcc2b589574be8410614e62
|
||||
F test/veryquick.test 57ab846bacf7b90cf4e9a672721ea5c5b669b661
|
||||
F test/view.test d4c4281e1679245829db35597817282f60dc513fc39cc5439078f009bd118487
|
||||
@@ -2177,8 +2179,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P 720ce06d93a9e4cc25c34c873c82165d8801f208c22701e51538f3210de84f65
|
||||
R 78475c96717bed229515f020acd7cf0b
|
||||
P 89a6c7b527321f1e824ee8f51b323248b7f0a9d869083c2879f7c4e3ac1931cb
|
||||
R 5ee06c3938cceca1d2ecdbd013d5e4f0
|
||||
U drh
|
||||
Z b05395e7bb390bd5a3c76ba7c1373e1f
|
||||
Z 2f531ea7e8fe54ce4807ed2d1f0d6eea
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
7fbdc1a849af3440579459bbb8797ebc7f9cce7b34d95675b8baa82db194ea9c
|
||||
cf2d1ad0365b05bc8bb310a90f66123e2f21ff7fd6a9784f65c75add4c7e7062
|
||||
+141
-9
@@ -577,6 +577,129 @@ void sqlite3AutoincrementEnd(Parse *pParse){
|
||||
# define autoIncStep(A,B,C)
|
||||
#endif /* SQLITE_OMIT_AUTOINCREMENT */
|
||||
|
||||
/*
|
||||
** The Select object passed as the second argument is a component of
|
||||
** a multi-row VALUES(...) clause that is part of an INSERT statement.
|
||||
** The entire VALUES clause will be coded as a co-routine. Each component
|
||||
** is coded by loading the N values returned by the select into an array
|
||||
** of registers at pParse->pValues->dest.iSdst followed by an OP_Yield
|
||||
** instruction (using register pParse->pValues->regYield).
|
||||
**
|
||||
** This function generates the co-routine code for the select passed as
|
||||
** the second argument. If argument bDel is true then the Select object
|
||||
** is deleted before returning.
|
||||
*/
|
||||
static void multiValuesSelect(Parse *pParse, Select *p, int bDel){
|
||||
MultiValues *pVal = pParse->pValues;
|
||||
sqlite3SelectPrep(pParse, p, 0);
|
||||
if( pParse->nErr ){
|
||||
/* Do not attempt to continue coding if a prior error has been seen. */
|
||||
}else if( bDel && p->pWin==0 ){
|
||||
/* Code this row directly. This is prefered as calling sqlite3Select()
|
||||
** too many times for a single Parse context leads to excessing realloc()
|
||||
** calls. */
|
||||
sqlite3ExprCodeExprList(pParse, p->pEList, pVal->dest.iSdst, 0, 0);
|
||||
sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pVal->regYield);
|
||||
}else{
|
||||
/* Call the full sqlite3Select() function for this row. This is required
|
||||
** to handle any window functions, or if bDel is false - in this last
|
||||
** case this is because this call to sqlite3Select() is required to
|
||||
** fulling initialize pVal->dest. */
|
||||
sqlite3Select(pParse, p, &pVal->dest);
|
||||
}
|
||||
if( bDel ){
|
||||
sqlite3SelectDelete(pParse->db, p);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** This function is called by the parser to process the second and subsequent
|
||||
** rows of a multi-row VALUES(...) clause. Argument pLeft is the previous
|
||||
** row of the clause, pRow contains the expressions for the new row.
|
||||
**
|
||||
** Usually, this function allocates a new Select object using pRow as its
|
||||
** select-list, links it to pLeft via a TK_ALL operator and returns the
|
||||
** new object. The SF_MultiValue flag is cleared on pLeft and set on
|
||||
** the returned object.
|
||||
**
|
||||
** However, if (a) the VALUES clause is part of an INSERT statement and
|
||||
** (b) it now has more rows than the configured SQLITE_LIMIT_COMPOUND_SELECT
|
||||
** limit, then it is already known that each row of the VALUES clause will
|
||||
** be coded as part of a co-routine that returns all such rows. In this
|
||||
** case the co-routine may be coded incrementally by this routine. This is
|
||||
** done to save memory while parsing the large VALUES clause.
|
||||
*/
|
||||
Select *sqlite3MultiValues(Parse *pParse, Select *pLeft, ExprList *pRow){
|
||||
MultiValues *pVal = pParse->pValues;
|
||||
Select *pRight;
|
||||
|
||||
/* Allocate a new Select structure for the next row of the VALUES clause.
|
||||
** There are then three options: (a) the co-routine has already been
|
||||
** started - in this case code the next row of the co-routine and then
|
||||
** delete the new Select, (b) the co-routine has not been started - in
|
||||
** this case link the new Select to the old using a TK_ALL operator, or
|
||||
** (c) an OOM has occured. */
|
||||
pRight = sqlite3SelectNew(pParse,pRow, 0,0,0,0,0, SF_Values|SF_MultiValue, 0);
|
||||
pLeft->selFlags &= ~SF_MultiValue;
|
||||
if( pRight ){
|
||||
if( pRow->nExpr!=pLeft->pEList->nExpr ){
|
||||
sqlite3SelectWrongNumTermsError(pParse, pRight);
|
||||
}
|
||||
if( pVal && pVal->pSelect==pLeft && pParse->nErr==0 ){
|
||||
/* Option (a) above */
|
||||
multiValuesSelect(pParse, pRight, 1);
|
||||
pRight = pLeft;
|
||||
}else{
|
||||
/* Option (b) above */
|
||||
pRight->op = TK_ALL;
|
||||
pRight->pPrior = pLeft;
|
||||
}
|
||||
}else{
|
||||
/* Option (c) above - an OOM */
|
||||
pRight = pLeft;
|
||||
}
|
||||
|
||||
if( pVal==0 && pParse->zValuesToken ){
|
||||
int iLimit = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT];
|
||||
|
||||
/* If the co-routine has not already been started, but more than
|
||||
** SQLITE_LIMIT_COMPOUND_SELECT select statements have been create
|
||||
** during this parse, check if the co-routine should be started now. */
|
||||
if( pParse->nSelect>iLimit ){
|
||||
int nSelect = 1;
|
||||
Select *p;
|
||||
pParse->zValuesToken = 0;
|
||||
for(p=pRight; p->pPrior; p=p->pPrior ) nSelect++;
|
||||
if( iLimit>0 && nSelect>iLimit && (p->selFlags & SF_InsertValues) ){
|
||||
Vdbe *v = sqlite3GetVdbe(pParse);
|
||||
pVal = (MultiValues*)sqlite3DbMallocZero(pParse->db, sizeof(*pVal));
|
||||
if( v && pVal ){
|
||||
/* Start coding the co-routine */
|
||||
pParse->pValues = pVal;
|
||||
pVal->pSelect = p;
|
||||
pVal->regYield = ++pParse->nMem;
|
||||
pVal->addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine,pVal->regYield,0,pVal->addrTop);
|
||||
sqlite3SelectDestInit(&pVal->dest, SRT_Coroutine, pVal->regYield);
|
||||
for(p=pRight; p->pPrior; p=p->pPrior ){
|
||||
p->pPrior->pNext = p;
|
||||
}
|
||||
pRight = p;
|
||||
while( p ){
|
||||
Select *pNext = p->pNext;
|
||||
p->selFlags = p->selFlags & (~SF_Values);
|
||||
p->pPrior = 0;
|
||||
multiValuesSelect(pParse, p, (p!=pRight));
|
||||
p = pNext;
|
||||
}
|
||||
sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pRight;
|
||||
}
|
||||
|
||||
/* Forward declaration */
|
||||
static int xferOptimization(
|
||||
@@ -915,16 +1038,25 @@ void sqlite3Insert(
|
||||
** Generate a co-routine to run the SELECT. */
|
||||
int regYield; /* Register holding co-routine entry-point */
|
||||
int addrTop; /* Top of the co-routine */
|
||||
int rc; /* Result code */
|
||||
int rc = SQLITE_OK; /* Result code */
|
||||
|
||||
if( pParse->pValues && pParse->pValues->pSelect==pSelect ){
|
||||
MultiValues *pVal = pParse->pValues;
|
||||
/* todo: surely we can use either regYield or dest.iSDParm... */
|
||||
dest.iSDParm = regYield = pVal->regYield;
|
||||
addrTop = pVal->addrTop;
|
||||
regFromSelect = pVal->dest.iSdst;
|
||||
}else{
|
||||
regYield = ++pParse->nMem;
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
||||
dest.iSdst = bIdListInOrder ? regData : 0;
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
}
|
||||
|
||||
regYield = ++pParse->nMem;
|
||||
addrTop = sqlite3VdbeCurrentAddr(v) + 1;
|
||||
sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, addrTop);
|
||||
sqlite3SelectDestInit(&dest, SRT_Coroutine, regYield);
|
||||
dest.iSdst = bIdListInOrder ? regData : 0;
|
||||
dest.nSdst = pTab->nCol;
|
||||
rc = sqlite3Select(pParse, pSelect, &dest);
|
||||
regFromSelect = dest.iSdst;
|
||||
assert( db->pParse==pParse );
|
||||
if( rc || pParse->nErr ) goto insert_cleanup;
|
||||
assert( db->mallocFailed==0 );
|
||||
|
||||
+14
-18
@@ -532,7 +532,7 @@ cmd ::= select(X). {
|
||||
}
|
||||
if( (p->selFlags & SF_MultiValue)==0 &&
|
||||
(mxSelect = pParse->db->aLimit[SQLITE_LIMIT_COMPOUND_SELECT])>0 &&
|
||||
cnt>mxSelect
|
||||
(cnt>mxSelect || (pParse->pValues && pParse->pValues->pSelect==pNext))
|
||||
){
|
||||
sqlite3ErrorMsg(pParse, "too many terms in compound SELECT");
|
||||
}
|
||||
@@ -626,20 +626,12 @@ oneselect(A) ::= values(A).
|
||||
|
||||
%type values {Select*}
|
||||
%destructor values {sqlite3SelectDelete(pParse->db, $$);}
|
||||
values(A) ::= VALUES LP nexprlist(X) RP. {
|
||||
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0);
|
||||
values(A) ::= VALUES(T) LP nexprlist(X) RP. {
|
||||
int f = SF_Values | ((T.z==pParse->zValuesToken) ? SF_InsertValues : 0);
|
||||
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,f,0);
|
||||
}
|
||||
values(A) ::= values(A) COMMA LP nexprlist(Y) RP. {
|
||||
Select *pRight, *pLeft = A;
|
||||
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0);
|
||||
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
|
||||
if( pRight ){
|
||||
pRight->op = TK_ALL;
|
||||
pRight->pPrior = pLeft;
|
||||
A = pRight;
|
||||
}else{
|
||||
A = pLeft;
|
||||
}
|
||||
A = sqlite3MultiValues(pParse,A,Y);
|
||||
}
|
||||
|
||||
// The "distinct" nonterminal is true (1) if the DISTINCT keyword is
|
||||
@@ -1004,16 +996,20 @@ setlist(A) ::= LP idlist(X) RP EQ expr(Y). {
|
||||
}
|
||||
|
||||
////////////////////////// The INSERT command /////////////////////////////////
|
||||
//
|
||||
cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) select(S)
|
||||
upsert(U). {
|
||||
cmd ::= with insert_cmd(R) INTO xfullname(X) inscols(F) select(S) upsert(U). {
|
||||
sqlite3Insert(pParse, X, S, F, R, U);
|
||||
}
|
||||
cmd ::= with insert_cmd(R) INTO xfullname(X) idlist_opt(F) DEFAULT VALUES returning.
|
||||
{
|
||||
cmd ::= with insert_cmd(R) INTO xfullname(X) inscols(F) DEFAULT VALUES returning. {
|
||||
sqlite3Insert(pParse, X, 0, F, R, 0);
|
||||
}
|
||||
|
||||
%type inscols {IdList*}
|
||||
%destructor inscols {sqlite3IdListDelete(pParse->db, $$);}
|
||||
|
||||
inscols(A) ::= idlist_opt(A). {
|
||||
if( yyLookahead==TK_VALUES ) pParse->zValuesToken = yyLookaheadToken.z;
|
||||
}
|
||||
|
||||
%type upsert {Upsert*}
|
||||
|
||||
// Because upsert only occurs at the tip end of the INSERT rule for cmd,
|
||||
|
||||
@@ -1349,6 +1349,7 @@ typedef struct Walker Walker;
|
||||
typedef struct WhereInfo WhereInfo;
|
||||
typedef struct Window Window;
|
||||
typedef struct With With;
|
||||
typedef struct MultiValues MultiValues;
|
||||
|
||||
|
||||
/*
|
||||
@@ -3570,6 +3571,7 @@ struct Select {
|
||||
#define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */
|
||||
#define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */
|
||||
#define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */
|
||||
#define SF_InsertValues 0x20000000 /* Is VALUES that follows an INSERT */
|
||||
|
||||
/* True if S exists and has SF_NestedFrom */
|
||||
#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0)
|
||||
@@ -3907,6 +3909,8 @@ struct Parse {
|
||||
#ifndef SQLITE_OMIT_ALTERTABLE
|
||||
RenameToken *pRename; /* Tokens subject to renaming by ALTER TABLE */
|
||||
#endif
|
||||
MultiValues *pValues;
|
||||
const char *zValuesToken;
|
||||
};
|
||||
|
||||
/* Allowed values for Parse.eParseMode
|
||||
@@ -4483,6 +4487,33 @@ struct Window {
|
||||
** due to the SQLITE_SUBTYPE flag */
|
||||
};
|
||||
|
||||
/*
|
||||
** A single instance of this object is used when parsing "INSERT INTO ...
|
||||
** VALUES" statements when the VALUES clause contains a large number of
|
||||
** rows - more than the configured SQLITE_LIMIT_COMPOUND_SELECT limit.
|
||||
**
|
||||
** An INSERT with a multi-row VALUES clause begins by coding a co-routine
|
||||
** to access each row of the VALUES clause. Usually, this doesn't happen
|
||||
** until after the entire statement has been parsed. Since each row of the
|
||||
** VALUES clause is stored in-memory as a separate Select statement, the
|
||||
** parse tree for very large VALUES clauses might consume significant
|
||||
** amounts of memory.
|
||||
**
|
||||
** In order to avoid this in extreme cases, once a VALUES clause that is
|
||||
** part of an INSERT statement grows to larger than
|
||||
** SQLITE_LIMIT_COMPOUND_SELECT rows, the co-routine is coded incrementally,
|
||||
** while parsing the remainder of the VALUES clause. An instance of this
|
||||
** object is stored in Parse.pValues while this is ongoing.
|
||||
*/
|
||||
struct MultiValues {
|
||||
Select *pSelect; /* The VALUES(...) Select object */
|
||||
SelectDest dest; /* Destination object for the co-routine */
|
||||
int addrTop; /* Address of top of co-routine */
|
||||
int regYield; /* Register used for co-routine */
|
||||
};
|
||||
|
||||
Select *sqlite3MultiValues(Parse*, Select*, ExprList*);
|
||||
|
||||
#ifndef SQLITE_OMIT_WINDOWFUNC
|
||||
void sqlite3WindowDelete(sqlite3*, Window*);
|
||||
void sqlite3WindowUnlinkFromSelect(Window*);
|
||||
|
||||
@@ -35,6 +35,18 @@ do_test 100 {
|
||||
SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1;
|
||||
}
|
||||
} {100000 5000050000 50000.5 1}
|
||||
|
||||
|
||||
reset_db
|
||||
ifcapable scanstatus {
|
||||
sqlite3_db_config db STMT_SCANSTATUS 1
|
||||
do_test 105 {
|
||||
set microsec [lindex [time {db eval $sql}] 0]
|
||||
db eval {
|
||||
SELECT count(x), sum(x), avg(x), $microsec<10000000 FROM t1;
|
||||
}
|
||||
} {100000 5000050000 50000.5 1}
|
||||
}
|
||||
|
||||
# 2018-01-14. A 100K-entry VALUES clause within a scalar expression does
|
||||
# not cause processor stack overflow.
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
# 2024 March 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix values
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
}
|
||||
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 2
|
||||
|
||||
do_execsql_test 1.1.1 {
|
||||
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
|
||||
}
|
||||
do_execsql_test 1.1.2 {
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
}
|
||||
|
||||
do_execsql_test 1.2.0 {
|
||||
DELETE FROM x1
|
||||
}
|
||||
do_catchsql_test 1.2.1 {
|
||||
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 4, 4, 4;
|
||||
} {1 {too many terms in compound SELECT}}
|
||||
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 4
|
||||
|
||||
do_catchsql_test 1.2.2 {
|
||||
INSERT INTO x1
|
||||
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4), (5, 5, 5)
|
||||
UNION ALL SELECT 6, 6, 6;
|
||||
} {1 {too many terms in compound SELECT}}
|
||||
|
||||
do_catchsql_test 1.2.3 {
|
||||
INSERT INTO x1
|
||||
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4)
|
||||
UNION ALL SELECT 6, 6, 6;
|
||||
} {1 {too many terms in compound SELECT}}
|
||||
|
||||
do_execsql_test 1.2.4 {
|
||||
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3) UNION ALL SELECT 6, 6, 6;
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
6 6 6
|
||||
}
|
||||
|
||||
set a 4
|
||||
set b 5
|
||||
set c 6
|
||||
do_execsql_test 1.2.5 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1
|
||||
VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3),
|
||||
(4, 4, $a), (5, 5, $b), (6, 6, $c)
|
||||
}
|
||||
|
||||
do_execsql_test 1.2.6 {
|
||||
SELECT * FROM x1;
|
||||
} {
|
||||
1 1 1
|
||||
2 2 2
|
||||
3 3 3
|
||||
4 4 4
|
||||
5 5 5
|
||||
6 6 6
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
# SQLITE_LIMIT_COMPOUND_SELECT set to 0.
|
||||
#
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
}
|
||||
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 3
|
||||
|
||||
do_catchsql_test 2.1.1 {
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5),
|
||||
(6, 6, 6),
|
||||
(7, 7, 7),
|
||||
(8, 8, 8),
|
||||
(9, 9, 9),
|
||||
(10, 10, 10, 10)
|
||||
} {1 {all VALUES must have the same number of terms}}
|
||||
|
||||
do_catchsql_test 2.1.2 {
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5),
|
||||
(6, 6, 6),
|
||||
(7, 7, 7),
|
||||
(8, 8, 8),
|
||||
(9, 9, 9),
|
||||
(10, 10, 10)
|
||||
} {1 {all VALUES must have the same number of terms}}
|
||||
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 0
|
||||
|
||||
do_execsql_test 2.2 {
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5),
|
||||
(6, 6, 6),
|
||||
(7, 7, 7),
|
||||
(8, 8, 8),
|
||||
(9, 9, 9),
|
||||
(10, 10, 10)
|
||||
} {}
|
||||
do_execsql_test 2.3 {
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1, 1),
|
||||
(2, 2, 2),
|
||||
(3, 3, 3),
|
||||
(4, 4, 4),
|
||||
(5, 5, 5),
|
||||
(6, 6, 6),
|
||||
(7, 7, 7),
|
||||
(8, 8, 8),
|
||||
(9, 9, 9),
|
||||
(10, 10, 10)
|
||||
UNION ALL
|
||||
SELECT 5, 12, 12
|
||||
ORDER BY 1
|
||||
} {}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE y1(x, y);
|
||||
}
|
||||
|
||||
foreach {tn iLimit} {1 0 2 2} {
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT $iLimit
|
||||
|
||||
do_execsql_test 3.$tn.1.1 {
|
||||
DELETE FROM y1;
|
||||
INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 5);
|
||||
}
|
||||
do_execsql_test 3.$tn.1.2 {
|
||||
SELECT * FROM y1;
|
||||
} {1 2 3 4 1 5}
|
||||
do_execsql_test 3.$tn.2.1 {
|
||||
DELETE FROM y1;
|
||||
INSERT INTO y1 VALUES(1, 2), (3, 4), (row_number() OVER (), 6)
|
||||
, (row_number() OVER (), 7)
|
||||
}
|
||||
do_execsql_test 3.$tn.1.2 {
|
||||
SELECT * FROM y1;
|
||||
} {1 2 3 4 1 6 1 7}
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 4.0 {
|
||||
CREATE TABLE x1(a PRIMARY KEY, b) WITHOUT ROWID;
|
||||
}
|
||||
|
||||
foreach {tn iLimit} {1 0 2 3} {
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT $iLimit
|
||||
|
||||
do_execsql_test 4.1.1 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1),
|
||||
(2, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
|
||||
}
|
||||
do_execsql_test 4.1.2 {
|
||||
SELECT * FROM x1
|
||||
} {1 1 2 a}
|
||||
|
||||
do_execsql_test 4.2.1 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES
|
||||
(1, 1),
|
||||
(2, 2),
|
||||
(3, 3),
|
||||
(4, 4),
|
||||
(5, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d')) ))
|
||||
}
|
||||
do_execsql_test 4.2.2 {
|
||||
SELECT * FROM x1
|
||||
} {1 1 2 2 3 3 4 4 5 a}
|
||||
|
||||
do_execsql_test 4.3.1 {
|
||||
DELETE FROM x1;
|
||||
INSERT INTO x1 VALUES
|
||||
(1, (SELECT * FROM (VALUES('a'), ('b'), ('c'), ('d'), ('e')) ))
|
||||
}
|
||||
do_execsql_test 4.3.2 {
|
||||
SELECT * FROM x1
|
||||
} {1 a}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
@@ -0,0 +1,37 @@
|
||||
# 2024 March 3
|
||||
#
|
||||
# The author disclaims copyright to this source code. In place of
|
||||
# a legal notice, here is a blessing:
|
||||
#
|
||||
# May you do good and not evil.
|
||||
# May you find forgiveness for yourself and forgive others.
|
||||
# May you share freely, never taking more than you give.
|
||||
#
|
||||
#***********************************************************************
|
||||
# This file implements regression tests for SQLite library.
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix valuesfault
|
||||
source $testdir/malloc_common.tcl
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE x1(a, b, c);
|
||||
}
|
||||
faultsim_save_and_close
|
||||
|
||||
do_faultsim_test 1 -prep {
|
||||
faultsim_restore_and_reopen
|
||||
sqlite3_limit db SQLITE_LIMIT_COMPOUND_SELECT 2
|
||||
} -body {
|
||||
execsql {
|
||||
INSERT INTO x1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3), (4, 4, 4);
|
||||
}
|
||||
} -test {
|
||||
faultsim_test_result {0 {}}
|
||||
}
|
||||
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user