SQLite

Check-in [d4097364]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Allow unqualified "rowid" references to be used in join queries, provided that only one of the source objects has a rowid. Forum post ab5b077c32636e49
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: d4097364c511709b1874881a0c036640777d1f724165416adf6f53a41f8c6e40
User & Date: dan 2021-07-01 18:19:17
Original Comment: Allow unqualified "rowid" references to be used in join queries, provided that only one of the source objects has a rowid.
References
2021-07-02
12:25
Put ALWAYS() on a branch that is always true due to [d4097364c511709b]. Fix a testcase precondition associated with the same check-in. (check-in: 55e2fbeb user: drh tags: trunk)
Context
2021-07-02
12:08
Fix a harmless assertion fault discovered by OSSFuzz. The assertion fault is harmless because the assert() checks a condition that that is harmless if false and the assert() is disabled in production builds. (check-in: 79443aab user: drh tags: trunk)
2021-07-01
18:19
Allow unqualified "rowid" references to be used in join queries, provided that only one of the source objects has a rowid. Forum post ab5b077c32636e49 (check-in: d4097364 user: dan tags: trunk)
16:57
Import the updated nmakehlp.c file used by the TCL Extension Architecture (TEA) builds in the amalgamation tarballs. Forum post 5a5001f20a. (check-in: 595bf95b user: drh tags: trunk)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/resolve.c.

327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353




354
355
356
357
358
359
360
          if( sqlite3StrICmp(zTabName, zTab)!=0 ){
            continue;
          }
          if( IN_RENAME_OBJECT && pItem->zAlias ){
            sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
          }
        }
        if( 0==(cntTab++) ){
          pMatch = pItem;
        }
        hCol = sqlite3StrIHash(zCol);
        for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
          if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
            /* If there has been exactly one prior match and this match
            ** is for the right-hand table of a NATURAL JOIN or is in a 
            ** USING clause, then skip this match.
            */
            if( cnt==1 ){
              if( pItem->fg.jointype & JT_NATURAL ) continue;
              if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
            }
            cnt++;
            pMatch = pItem;
            /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
            pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
            break;
          }




        }
      }
      if( pMatch ){
        pExpr->iTable = pMatch->iCursor;
        pExpr->y.pTab = pMatch->pTab;
        /* RIGHT JOIN not (yet) supported */
        assert( (pMatch->fg.jointype & JT_RIGHT)==0 );







<
<
<

















>
>
>
>







327
328
329
330
331
332
333



334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
          if( sqlite3StrICmp(zTabName, zTab)!=0 ){
            continue;
          }
          if( IN_RENAME_OBJECT && pItem->zAlias ){
            sqlite3RenameTokenRemap(pParse, 0, (void*)&pExpr->y.pTab);
          }
        }



        hCol = sqlite3StrIHash(zCol);
        for(j=0, pCol=pTab->aCol; j<pTab->nCol; j++, pCol++){
          if( pCol->hName==hCol && sqlite3StrICmp(pCol->zName, zCol)==0 ){
            /* If there has been exactly one prior match and this match
            ** is for the right-hand table of a NATURAL JOIN or is in a 
            ** USING clause, then skip this match.
            */
            if( cnt==1 ){
              if( pItem->fg.jointype & JT_NATURAL ) continue;
              if( nameInUsingClause(pItem->pUsing, zCol) ) continue;
            }
            cnt++;
            pMatch = pItem;
            /* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
            pExpr->iColumn = j==pTab->iPKey ? -1 : (i16)j;
            break;
          }
        }
        if( 0==cnt && VisibleRowid(pTab) ){
          cntTab++;
          pMatch = pItem;
        }
      }
      if( pMatch ){
        pExpr->iTable = pMatch->iCursor;
        pExpr->y.pTab = pMatch->pTab;
        /* RIGHT JOIN not (yet) supported */
        assert( (pMatch->fg.jointype & JT_RIGHT)==0 );

Changes to test/autoindex5.test.

119
120
121
122
123
124
125




126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    UNION ALL
    SELECT 0, 0 WHERE 0;

  SELECT (
      SELECT sum(z) FROM vvv WHERE x='aaa'
  ) FROM one;
} {8.0}




do_catchsql_test 2.2 {
  DROP TABLE t1;
  CREATE TABLE t1(aaa);
  INSERT INTO t1(aaa) VALUES(9);
  SELECT (
    SELECT aaa FROM t1 GROUP BY (
      SELECT bbb FROM (
        SELECT ccc AS bbb FROM (
           SELECT 1 ccc
        ) WHERE rowid IS NOT 1
      ) WHERE bbb = 1
    )
  );
} {1 {no such column: rowid}}

# Ticket https://www.sqlite.org/src/info/787fa716be3a7f65
# Segfault due to multiple uses of the same subquery where the
# subquery is implemented via coroutine.
#
ifcapable windowfunc {
sqlite3 db :memory:







>
>
>
>













|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
    UNION ALL
    SELECT 0, 0 WHERE 0;

  SELECT (
      SELECT sum(z) FROM vvv WHERE x='aaa'
  ) FROM one;
} {8.0}

# At one point the following was returning "no such column: rowid". This
# was incorrect - "rowid" matches against the rowid of table t1 in this
# query.
do_catchsql_test 2.2 {
  DROP TABLE t1;
  CREATE TABLE t1(aaa);
  INSERT INTO t1(aaa) VALUES(9);
  SELECT (
    SELECT aaa FROM t1 GROUP BY (
      SELECT bbb FROM (
        SELECT ccc AS bbb FROM (
           SELECT 1 ccc
        ) WHERE rowid IS NOT 1
      ) WHERE bbb = 1
    )
  );
} {0 9}

# Ticket https://www.sqlite.org/src/info/787fa716be3a7f65
# Segfault due to multiple uses of the same subquery where the
# subquery is implemented via coroutine.
#
ifcapable windowfunc {
sqlite3 db :memory:

Changes to test/rowid.test.

14
15
16
17
18
19
20

21
22
23
24
25
26
27
#
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
# special column, usually called the "rowid", that uniquely identifies
# that row within the table.

set testdir [file dirname $argv0]
source $testdir/tester.tcl


# Basic ROWID functionality tests.
#
do_test rowid-1.1 {
  execsql {
    CREATE TABLE t1(x int, y int);
    INSERT INTO t1 VALUES(1,2);







>







14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#
# EVIDENCE-OF: R-36924-43758 By default, every row in SQLite has a
# special column, usually called the "rowid", that uniquely identifies
# that row within the table.

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix rowid

# Basic ROWID functionality tests.
#
do_test rowid-1.1 {
  execsql {
    CREATE TABLE t1(x int, y int);
    INSERT INTO t1 VALUES(1,2);
781
782
783
784
785
786
787
788



789


























790

do_execsql_test rowid-15.2 {
  SELECT 1, NULL INTERSECT SELECT * FROM (
      SELECT t2.c0, t1.c1 FROM t1, t2
      WHERE ((t2.rowid <= 'a')) OR (t1.c0 <= t2.c0) ORDER BY 'a' DESC LIMIT 100
  );
} {1 {}}































finish_test








>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820

do_execsql_test rowid-15.2 {
  SELECT 1, NULL INTERSECT SELECT * FROM (
      SELECT t2.c0, t1.c1 FROM t1, t2
      WHERE ((t2.rowid <= 'a')) OR (t1.c0 <= t2.c0) ORDER BY 'a' DESC LIMIT 100
  );
} {1 {}}

#-------------------------------------------------------------------------
# Check that an unqualified "rowid" can be used in join queries so long 
# as only one of the source objects has a rowid column.
#
reset_db
do_execsql_test 16.0 {
  CREATE TABLE t1(x);
  CREATE TABLE t2(y PRIMARY KEY) WITHOUT ROWID;
  CREATE VIEW v1 AS SELECT x FROM t1;
  CREATE TABLE t3(z);

  INSERT INTO t1(rowid, x) VALUES(1, 1);
  INSERT INTO t2(y) VALUES(2);
  INSERT INTO t3(rowid, z) VALUES(3, 3);
}

do_execsql_test 16.1 { SELECT rowid FROM t1, t2; } {1}
do_execsql_test 16.2 { SELECT rowid FROM t1, v1; } {1}
do_execsql_test 16.3 { SELECT rowid FROM t3, v1; } {3}
do_execsql_test 16.4 { SELECT rowid FROM t3, (SELECT 123); } {3}

do_execsql_test 16.5 { SELECT rowid FROM t2, t1; } {1}
do_execsql_test 16.6 { SELECT rowid FROM v1, t1; } {1}
do_execsql_test 16.7 { SELECT rowid FROM v1, t3; } {3}
do_execsql_test 16.8 { SELECT rowid FROM (SELECT 123), t3; } {3}

do_catchsql_test 16.5 { SELECT rowid FROM t1, t3; } {1 {no such column: rowid}}



finish_test