Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f7b1b5af96 | |||
| 54c96b2152 |
@@ -1,5 +1,5 @@
|
||||
C Fix\sa\sminor\stypo\sin\sa\scomment.
|
||||
D 2025-08-21T18:47:01.547
|
||||
C Improve\sperformance\sof\sthis\spatch.
|
||||
D 2025-08-22T19:14:35.864
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -739,14 +739,14 @@ F src/pragma.c 30b535d0a66348df844ee36f890617b4cf45e9a22dcbc47ec3ca92909c50aaf1
|
||||
F src/prepare.c 2af0b5c1ec787c8eebd21baa9d79caf4a4dc3a18e76ce2edbf2027d706bca37a
|
||||
F src/printf.c 5f0c957af9699e849d786e8fbaa3baab648ca5612230dc17916434c14bc8698f
|
||||
F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c
|
||||
F src/resolve.c f8d1d011aba0964ff1bdccd049d4d2c2fec217efd90d202a4bb775e926b2c25d
|
||||
F src/resolve.c 0d0b8146eb85c7a4cda2f81bc863f29e6ce3fa2d5651f7a5e77f3cdcce0c0f0e
|
||||
F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97
|
||||
F src/select.c 78ebf432355e820962a5001277cb43ffe3d82441c6dc9c8f0aeb0b15fbd5dd02
|
||||
F src/shell.c.in 0636915df0dbac6c780f04959f5d1055f206fb281b2c8fc8b113fe7bfc7d44ef
|
||||
F src/sqlite.h.in ebfc0358de0e18aabee7fa918f2f846894e23bebc74160fbe265c99046ee61b8
|
||||
F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479
|
||||
F src/sqlite3ext.h 0bfd049bb2088cc44c2ad54f2079d1c6e43091a4e1ce8868779b75f6c1484f1e
|
||||
F src/sqliteInt.h a54f83985985655d1276e9e356dd6ae19b8d0b62c2abc75cc9e8f402ea141207
|
||||
F src/sqliteInt.h b527df450e1b0b7c64a395129fc4fd36684ce81039d22c78c4ed718ca11d0c14
|
||||
F src/sqliteLimit.h fe70bd8983e5d317a264f2ea97473b359faf3ebb0827877a76813f5cf0cdc364
|
||||
F src/status.c 0e72e4f6be6ccfde2488eb63210297e75f569f3ce9920f6c3d77590ec6ce5ffd
|
||||
F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
|
||||
@@ -826,7 +826,7 @@ F src/walker.c d5006d6b005e4ea7302ad390957a8d41ed83faa177e412f89bc5600a7462a014
|
||||
F src/where.c f2f075bd17065922235632feb368efe92a7f03d42797eb575267574fbf6d4218
|
||||
F src/whereInt.h 8d94cb116c9e06205c3d5ac87af065fc044f8cf08bfdccd94b6ea1c1308e65da
|
||||
F src/wherecode.c 71c5c6804b7f882dec8ec858758accae02fcfca13df3cc720f1f258e663ec7c5
|
||||
F src/whereexpr.c 78c28a8da187816d5d82049f2e343fb39f4a8e30b5bf1bda9b96cecde40ca8bd
|
||||
F src/whereexpr.c 403a44eeec1a0f0914fccc6a59376b6924bc00ef6728fe6ffce4cf3051b320fc
|
||||
F src/window.c d01227141f622f24fbe36ca105fbe6ef023f9fd98f1ccd65da95f88886565db5
|
||||
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
|
||||
F test/affinity2.test 4d7a34d328e58ca2a2d78fd76c27614a41ca7ddf4312ded9c68c04f430b3b47d
|
||||
@@ -1335,6 +1335,7 @@ F test/joinD.test 2ce62e7353a0702ca5e70008faf319c1d4686aa19fba34275c6d1da0e960be
|
||||
F test/joinE.test d5d182f3812771e2c0d97c9dcf5dbe4c41c8e21c82560e59358731c4a3981d6b
|
||||
F test/joinF.test 53dd66158806823ea680dd7543b5406af151b5aafa5cd06a7f3231cd94938127
|
||||
F test/joinH.test fd76024ff104baec16417db5cafc0894ad4e0863e70803e63c1bba0322706339
|
||||
F test/joinI.test 78cae6f746a78f32d8aedb8cf7b93bcd802c245db0986330844dfb1a6700ebab
|
||||
F test/journal1.test bc61a4228db11bffca118bd358ba4b868524bf080f3532749de6c539656e20fa
|
||||
F test/journal2.test 9dac6b4ba0ca79c3b21446bbae993a462c2397c4
|
||||
F test/journal3.test e5aeff93a7776cf644dbc48dec277655cff80a1cd24689036abc87869b120ea6
|
||||
@@ -2169,8 +2170,8 @@ F tool/version-info.c 3b36468a90faf1bbd59c65fd0eb66522d9f941eedd364fabccd7227350
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh 1ad0169b022b280bcaaf94a7fa231591be96b514230ab5c98fbf15cd7df842dd
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 9f15182776b30676c9aae9bcb5d4ad7580359fbdd607c2a9227c9cf2c81a4054
|
||||
R e87d0e2ec7db35078d5f7c68106ae850
|
||||
U drh
|
||||
Z a3b0bda8d54e990d1d0f3efd38f275ec
|
||||
P 4bb527d3377f9e0e328c5e9901e5e6d45a90958004db5ff7000baa2ecb3ffeb6
|
||||
R aa93e87aea2d39245eaaa1ac42e84a48
|
||||
U dan
|
||||
Z 6e9f35e4c1e718286f5d03be03b6a9af
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
9ada44eb6d26532e45cdd2ed8d5707f1734d0177a13b493ff9cf070e0a992522
|
||||
3060b2c447fb0d6b239e5a8277306fabf388f5c01ea521a3cd6c5a44f4236132
|
||||
|
||||
+79
-6
@@ -1454,6 +1454,73 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
|
||||
return pParse->nErr ? WRC_Abort : WRC_Continue;
|
||||
}
|
||||
|
||||
/*
|
||||
** True if the SrcList passed as the only argument contains a RIGHT JOIN.
|
||||
*/
|
||||
#define hasRightJoin(pSrc) (((pSrc)->a[0].fg.jointype && JT_LTORJ)!=0)
|
||||
|
||||
/*
|
||||
** Like resolveExprStep(), except this version does some special handling
|
||||
** of ON expressions to ensure they do not illegally refer to tables
|
||||
** to the right of them within the FROM clause.
|
||||
*/
|
||||
static int resolveOnStep(Walker *pWalker, Expr *pExpr){
|
||||
NameContext *pNC = pWalker->u.pNC;
|
||||
int res;
|
||||
|
||||
/* SQLite raises an error if an ON clause refers to tables to the right
|
||||
** of itself in its join if either:
|
||||
**
|
||||
** + the join the ON is attached to is an OUTER JOIN, or
|
||||
** + the FROM clause in question features at least one FULL or RIGHT join.
|
||||
**
|
||||
** SQLite versions 3.0-3.38 treated a ON clause on an INNER JOIN as
|
||||
** equivalent to part of the WHERE clause, and so it was not an error for
|
||||
** them refer to tables to the right of themselves. Starting with 3.39,
|
||||
** SQLite will raise an error in the second case enumerated above as well.
|
||||
** This makes SQLite more like other systems while preserving legacy
|
||||
** behavior.
|
||||
**
|
||||
** So, if this expression is an ON clause and either of the above are true,
|
||||
** then set NameContext.pOn to point to the expression before resolving
|
||||
** its descendants. lookupName() will generate an error if any descendant
|
||||
** expression refers to a table to the right of this ON clause in the current
|
||||
** query. */
|
||||
if( pNC->pOn==0 && (
|
||||
(ExprHasProperty(pExpr, EP_OuterON))
|
||||
|| (ExprHasProperty(pExpr, EP_InnerON) && hasRightJoin(pNC->pSrcList))
|
||||
)){
|
||||
pNC->pOn = pExpr;
|
||||
res = sqlite3WalkExprNN(pWalker, pExpr);
|
||||
if( res==WRC_Continue ) res = WRC_Prune;
|
||||
pNC->pOn = 0;
|
||||
}else{
|
||||
res = resolveExprStep(pWalker, pExpr);
|
||||
if( pExpr->op==TK_COLUMN && pWalker->pParse->nErr==0 ){
|
||||
/* A reference to a table column has just been resolved. Find the
|
||||
** name-context that it matched against: */
|
||||
int iTab = pExpr->iTable;
|
||||
do {
|
||||
SrcList *p = pNC->pSrcList;
|
||||
if( iTab>=p->a[0].iCursor && iTab<=p->a[p->nSrc-1].iCursor ) break;
|
||||
pNC = pNC->pNext;
|
||||
}while( pNC );
|
||||
|
||||
/* If the name-context that was matched against is currently inside
|
||||
** an ON expression, check that the specific FROM object within the
|
||||
** name-context was not to the right of the ON clause. If it was,
|
||||
** it is an error. */
|
||||
if( pNC && pNC->pOn && pNC->pOn->w.iJoin<pExpr->iTable ){
|
||||
sqlite3ErrorMsg(
|
||||
pWalker->pParse, "ON clause references tables to its right"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
** pEList is a list of expressions which are really the result set of the
|
||||
** a SELECT statement. pE is a term in an ORDER BY or GROUP BY clause.
|
||||
@@ -1908,7 +1975,12 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
|
||||
/* Recursively resolve names in all subqueries in the FROM clause
|
||||
*/
|
||||
if( pOuterNC ) pOuterNC->nNestedSelect++;
|
||||
if( pOuterNC ){
|
||||
pOuterNC->nNestedSelect++;
|
||||
if( pOuterNC->pOn ){
|
||||
sNC.ncFlags |= NC_On;
|
||||
}
|
||||
}
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
SrcItem *pItem = &p->pSrc->a[i];
|
||||
assert( pItem->zName!=0
|
||||
@@ -1936,6 +2008,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
pItem->fg.isCorrelated = (pOuterNC->nRef>nRef);
|
||||
}
|
||||
}
|
||||
if( pItem->fg.isOn ) sNC.ncFlags |= NC_On;
|
||||
}
|
||||
if( pOuterNC && ALWAYS(pOuterNC->nNestedSelect>0) ){
|
||||
pOuterNC->nNestedSelect--;
|
||||
@@ -1944,7 +2017,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
/* Set up the local name-context to pass to sqlite3ResolveExprNames() to
|
||||
** resolve the result-set expression list.
|
||||
*/
|
||||
sNC.ncFlags = NC_AllowAgg|NC_AllowWin;
|
||||
sNC.ncFlags |= (NC_AllowAgg|NC_AllowWin);
|
||||
sNC.pSrcList = p->pSrc;
|
||||
sNC.pNext = pOuterNC;
|
||||
|
||||
@@ -1985,7 +2058,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){
|
||||
}
|
||||
sNC.ncFlags |= NC_Where;
|
||||
if( sqlite3ResolveExprNames(&sNC, p->pWhere) ) return WRC_Abort;
|
||||
sNC.ncFlags &= ~NC_Where;
|
||||
sNC.ncFlags &= ~(NC_Where);
|
||||
|
||||
/* Resolve names in table-valued-function arguments */
|
||||
for(i=0; i<p->pSrc->nSrc; i++){
|
||||
@@ -2151,7 +2224,7 @@ int sqlite3ResolveExprNames(
|
||||
savedHasAgg = pNC->ncFlags & (NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||
pNC->ncFlags &= ~(NC_HasAgg|NC_MinMaxAgg|NC_HasWin|NC_OrderAgg);
|
||||
w.pParse = pNC->pParse;
|
||||
w.xExprCallback = resolveExprStep;
|
||||
w.xExprCallback = (pNC->ncFlags & NC_On) ? resolveOnStep : resolveExprStep;
|
||||
w.xSelectCallback = (pNC->ncFlags & NC_NoSelect) ? 0 : resolveSelectStep;
|
||||
w.xSelectCallback2 = 0;
|
||||
w.u.pNC = pNC;
|
||||
@@ -2192,7 +2265,7 @@ int sqlite3ResolveExprListNames(
|
||||
Walker w;
|
||||
if( pList==0 ) return SQLITE_OK;
|
||||
w.pParse = pNC->pParse;
|
||||
w.xExprCallback = resolveExprStep;
|
||||
w.xExprCallback = (pNC->ncFlags & NC_On) ? resolveOnStep : resolveExprStep;
|
||||
w.xSelectCallback = resolveSelectStep;
|
||||
w.xSelectCallback2 = 0;
|
||||
w.u.pNC = pNC;
|
||||
@@ -2247,7 +2320,7 @@ void sqlite3ResolveSelectNames(
|
||||
Walker w;
|
||||
|
||||
assert( p!=0 );
|
||||
w.xExprCallback = resolveExprStep;
|
||||
w.xExprCallback = 0;
|
||||
w.xSelectCallback = resolveSelectStep;
|
||||
w.xSelectCallback2 = 0;
|
||||
w.pParse = pParse;
|
||||
|
||||
@@ -3496,6 +3496,7 @@ struct SrcList {
|
||||
struct NameContext {
|
||||
Parse *pParse; /* The parser */
|
||||
SrcList *pSrcList; /* One or more tables used to resolve names */
|
||||
Expr *pOn; /* Currently inside this ON(...) clause */
|
||||
union {
|
||||
ExprList *pEList; /* Optional list of result-set columns */
|
||||
AggInfo *pAggInfo; /* Information about aggregates at this level */
|
||||
@@ -3541,6 +3542,7 @@ struct NameContext {
|
||||
#define NC_FromDDL 0x040000 /* SQL text comes from sqlite_schema */
|
||||
#define NC_NoSelect 0x080000 /* Do not descend into sub-selects */
|
||||
#define NC_Where 0x100000 /* Processing WHERE clause of a SELECT */
|
||||
#define NC_On 0x200000 /* Requires EP_OuterOn|EP_InnerOn processing */
|
||||
#define NC_OrderAgg 0x8000000 /* Has an aggregate other than count/min/max */
|
||||
|
||||
/*
|
||||
|
||||
@@ -1170,21 +1170,7 @@ static void exprAnalyze(
|
||||
prereqAll |= x;
|
||||
extraRight = x-1; /* ON clause terms may not be used with an index
|
||||
** on left table of a LEFT JOIN. Ticket #3015 */
|
||||
if( (prereqAll>>1)>=x ){
|
||||
sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
||||
return;
|
||||
}
|
||||
}else if( (prereqAll>>1)>=x ){
|
||||
/* The ON clause of an INNER JOIN references a table to its right.
|
||||
** Most other SQL database engines raise an error. But SQLite versions
|
||||
** 3.0 through 3.38 just put the ON clause constraint into the WHERE
|
||||
** clause and carried on. Beginning with 3.39, raise an error only
|
||||
** if there is a RIGHT or FULL JOIN in the query. This makes SQLite
|
||||
** more like other systems, and also preserves legacy. */
|
||||
if( ALWAYS(pSrc->nSrc>0) && (pSrc->a[0].fg.jointype & JT_LTORJ)!=0 ){
|
||||
sqlite3ErrorMsg(pParse, "ON clause references tables to its right");
|
||||
return;
|
||||
}
|
||||
ExprClearProperty(pExpr, EP_InnerON);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
# 2022 May 17
|
||||
#
|
||||
# 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 joinI
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a INT);
|
||||
CREATE TABLE t2(b INT);
|
||||
CREATE TABLE t3(c INT);
|
||||
}
|
||||
|
||||
foreach {tn sql} {
|
||||
1 "SELECT * FROM t1 RIGHT JOIN t2 ON t2.b=t3.c CROSS JOIN t3"
|
||||
2 "SELECT * FROM t1 RIGHT JOIN t2 ON t2.b=(SELECT t3.c) CROSS JOIN t3"
|
||||
3 "SELECT * FROM t1 RIGHT JOIN t2 ON CASE WHEN t2.b THEN t3.c ELSE 1 END CROSS JOIN t3"
|
||||
} {
|
||||
do_catchsql_test 1.1.$tn $sql {1 {ON clause references tables to its right}}
|
||||
}
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
|
||||
do_execsql_test 2.0 {
|
||||
CREATE TABLE t0(c0 INT, c1 INT);
|
||||
CREATE TABLE t1 (c0 INT);
|
||||
|
||||
CREATE VIEW v1(c0) AS SELECT t0.c0 FROM t0 NATURAL RIGHT JOIN t1;
|
||||
CREATE VIEW v2(c0) AS SELECT 0 FROM v1;
|
||||
|
||||
INSERT INTO t0(c0, c1) VALUES (-1, 0);
|
||||
INSERT INTO t1(c0) VALUES (NULL);
|
||||
|
||||
SELECT * FROM v1 INNER JOIN (v2 CROSS JOIN t0) ON (t0.c0 < t0.c1);
|
||||
} {{} 0 -1 0}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 3.0 {
|
||||
CREATE TABLE t0(c0, c1);
|
||||
CREATE TABLE t1(v);
|
||||
CREATE TABLE t2(w);
|
||||
CREATE TABLE t3(x);
|
||||
CREATE TABLE t4(y);
|
||||
CREATE TABLE t5(z);
|
||||
}
|
||||
|
||||
do_execsql_test 3.1 {
|
||||
SELECT 1234 FROM t4
|
||||
RIGHT JOIN t5
|
||||
CROSS JOIN (t2 CROSS JOIN t0) AS a1 ON (a1.c0 < a1.c1);
|
||||
}
|
||||
|
||||
do_execsql_test 3.2 {
|
||||
SELECT 1234 FROM t4
|
||||
RIGHT JOIN t5
|
||||
CROSS JOIN (t2 CROSS JOIN t1 CROSS JOIN t0) AS a1 ON (a1.c0 < a1.c1);
|
||||
}
|
||||
|
||||
do_execsql_test 3.3 {
|
||||
SELECT 5678 FROM t0 RIGHT JOIN t1 ON (
|
||||
SELECT 1 FROM t2 RIGHT JOIN t3 ON t2.w
|
||||
) CROSS JOIN t4;
|
||||
}
|
||||
|
||||
do_catchsql_test 3.4 {
|
||||
SELECT 5678 FROM t0 RIGHT JOIN t1 ON (
|
||||
SELECT 1 FROM t2 RIGHT JOIN t3 ON t4.y
|
||||
) CROSS JOIN t4;
|
||||
} {1 {ON clause references tables to its right}}
|
||||
|
||||
do_execsql_test 3.5 {
|
||||
SELECT 5678 FROM t0 RIGHT JOIN t1 ON (
|
||||
SELECT 1 FROM t2 RIGHT JOIN t3 ON 0=t1.v
|
||||
) CROSS JOIN t4;
|
||||
}
|
||||
|
||||
do_catchsql_test 3.6 {
|
||||
SELECT 5678 FROM t0 RIGHT JOIN t1 ON (
|
||||
SELECT 1 FROM t2 RIGHT JOIN t3 ON max(0,t5.z) CROSS JOIN t5
|
||||
) CROSS JOIN t4;
|
||||
} {1 {ON clause references tables to its right}}
|
||||
|
||||
finish_test
|
||||
Reference in New Issue
Block a user