Compare commits

...

12 Commits

Author SHA1 Message Date
drh a40455276b Improved error handling.
FossilOrigin-Name: cf2d1ad0365b05bc8bb310a90f66123e2f21ff7fd6a9784f65c75add4c7e7062
2024-03-07 18:47:28 +00:00
dan e9a6be4d19 Simplify the parser changes on this branch.
FossilOrigin-Name: 89a6c7b527321f1e824ee8f51b323248b7f0a9d869083c2879f7c4e3ac1931cb
2024-03-07 17:11:12 +00:00
drh 1511157bca Merge all the latest trunk enhancements into the exp-values-clause branch.
FossilOrigin-Name: c4923f266f061c06560e8801a3328167aa5658b3f51019c3470f16560591ba76
2024-03-07 16:25:56 +00:00
dan ca1a5f8c36 Add further tests for the code on this branch.
FossilOrigin-Name: 5d8065e80144ba3e762c353a9f06fd5e4aea2d0125c4e365a3d6394f8e09a13c
2024-03-07 15:44:50 +00:00
dan a21be19757 Avoid making too many calls to sqlite3Select/sqlite3WhereBegin() when processing large VALUES clauses.
FossilOrigin-Name: 356158c1928ddcdc50c3635d677d3d20ab020184c8d91d61df103801a365eb83
2024-03-06 20:34:59 +00:00
dan e51c78fa6a Handle VALUES clauses having different number of values in different rows. Also the case where SQLITE_LIMIT_COMPOUND_SELECT is set to 0.
FossilOrigin-Name: f5074b29d96e8e642e597ce855d2481220628f6892110b9699e27c3806084f5d
2024-03-06 14:55:18 +00:00
dan c5fd44ca8a Add comments for the new code on this branch.
FossilOrigin-Name: 551caba93bc1ab0c57451bc3f0cd29d16a9d577874d22d5083ac53fe09a5e60a
2024-03-05 20:33:48 +00:00
dan a7176860f3 Merge trunk changes into this branch.
FossilOrigin-Name: a003fffafdb532de4ff3876a81e73dbccbdf83debecd83a2a9ae2d449bf02adc
2024-03-05 18:03:28 +00:00
dan ffada0ebcb Fix a problem with large values clauses and named variables.
FossilOrigin-Name: 4784a92e567013632ea833d8747bc304ae39aaa9c2dff66198cda53797ec3ab7
2024-03-05 17:48:20 +00:00
dan 752cb42dc7 Simplify changes on this branch by avoiding any special handling until SQLITE_LIMIT_COMPOUND_SELECT rows are reached.
FossilOrigin-Name: 9cbceaac8f3c557f6eb266e15c57d71d3b6ad5dfdc8c0c39e5fc75e505673d17
2024-03-05 17:23:13 +00:00
dan a175b463a9 Fix some problems with "VALUES(...) UNION ..." and similar on this branch.
FossilOrigin-Name: 5d6797716d4be5b9d448f697b05f36a62c180e836dd142307f06b945a7ddb43c
2024-03-04 18:50:17 +00:00
dan 40df47d151 Attempt to use less memory when handling a large VALUES clause attached to an INSERT statement. This branch is buggy.
FossilOrigin-Name: 6d4f1ae2fcabdaca4e2c12224a8807c6fe2c62353dff435a0c0030fa58312df6
2024-03-02 20:39:17 +00:00
8 changed files with 478 additions and 37 deletions
+11 -9
View File
@@ -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
View File
@@ -1 +1 @@
7fbdc1a849af3440579459bbb8797ebc7f9cce7b34d95675b8baa82db194ea9c
cf2d1ad0365b05bc8bb310a90f66123e2f21ff7fd6a9784f65c75add4c7e7062
+141 -9
View File
@@ -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
View File
@@ -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,
+31
View File
@@ -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*);
+12
View File
@@ -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.
+231
View File
@@ -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
+37
View File
@@ -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