]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Do not flatten a UNION ALL subquery where the column affinities do not match
authordrh <>
Tue, 1 Nov 2022 01:07:29 +0000 (01:07 +0000)
committerdrh <>
Tue, 1 Nov 2022 01:07:29 +0000 (01:07 +0000)
on all arms.  Force that subquery to be materialized.

FossilOrigin-Name: 1b8a128832c1633cbb86999d347fef64ac45fe134dac61132112fc97f24676a0

manifest
manifest.uuid
src/select.c
src/test1.c
test/unionall.test

index 9ddb8723164ce4b78e1a41dfa4c1dacbec44a099..f5ca9134945a4634651f1e7e0e85c666ce2f4ac2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Enforce\scolumn\saffinity\son\sthe\smaterialization\sof\sa\ssubquery\sor\sview.
-D 2022-11-01T00:52:22.740
+C Do\snot\sflatten\sa\sUNION\sALL\ssubquery\swhere\sthe\scolumn\saffinities\sdo\snot\smatch\non\sall\sarms.\s\sForce\sthat\ssubquery\sto\sbe\smaterialized.
+D 2022-11-01T01:07:29.799
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724
@@ -636,7 +636,7 @@ F src/printf.c e99ee9741e79ae3873458146f59644276657340385ade4e76a5f5d1c25793764
 F src/random.c 546d6feb15ec69c1aafe9bb351a277cbb498fd5410e646add673acb805714960
 F src/resolve.c efea4e5fbecfd6d0a9071b0be0d952620991673391b6ffaaf4c277b0bb674633
 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92
-F src/select.c 0c4d77f94a413b355b66b401b977e9dc6994f858fe3a6e0cc0fad18a8199132e
+F src/select.c 12cb5162e606290354f9512ff0c30fc6dc4d7a77a92b6c5b581395f9c4edd047
 F src/shell.c.in bde69ad6a9887396c87d089da84c0fe1e432957faebd9206b9185be735341104
 F src/sqlite.h.in d9c8a6243fc0a1c270d69db33758e34b810af3462f9bc5b4af113b347e07c69d
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
@@ -646,7 +646,7 @@ F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a3
 F src/status.c 160c445d7d28c984a0eae38c144f6419311ed3eace59b44ac6dafc20db4af749
 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1
 F src/tclsqlite.c 4e64ba300a5a26e0f1170e09032429faeb65e45e8f3d1a7833e8edb69fc2979e
-F src/test1.c 790c8cd24d1ac39b8cf4e2f618ce16ecc028accfcde60660f7bd983e0f4c7d28
+F src/test1.c 373e57d7735ee42eb4578f1df4f072a495ae5ce5154a73862e1ef2134fd7a040
 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644
 F src/test4.c 4533b76419e7feb41b40582554663ed3cd77aaa54e135cf76b3205098cd6e664
@@ -1769,7 +1769,7 @@ F test/tt3_vacuum.c 71b254cde1fc49d6c8c44efd54f4668f3e57d7b3a8f4601ade069f75a999
 F test/types.test bf816ce73c7dfcfe26b700c19f97ef4050d194ff
 F test/types2.test 1aeb81976841a91eef292723649b5c4fe3bc3cac
 F test/types3.test 99e009491a54f4dc02c06bdbc0c5eea56ae3e25a
-F test/unionall.test 9706d2a0c03619f5fce3bcadc30e1e74f9cc60aae4398cf28b5359503fb83758
+F test/unionall.test bfeeea6c18c09a46f7e8bed69173e31c71336152e6253fb37c7257c76509f0e4
 F test/unionall2.test 71e8fa08d5699d50dc9f9dc0c9799c2e7a6bb7931a330d369307a4df7f157fa1
 F test/unionallfault.test 652bfbb630e6c43135965dc1e8f0a9a791da83aec885d626a632fe1909c56f73
 F test/unionvtab.test e1704ab1b4c1bb3ffc9da4681f8e85a0b909fd80b937984fc94b27415ac8e5a4
@@ -2054,11 +2054,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 d15c9a4a323b825eb80e706e12e9df95e5db458024f51e6e537940efc8234d8b
-R 1fa17b7dffe4e486e0be3f5c9bbb7b7f
-T *branch * tkt-57c47526
-T *sym-tkt-57c47526 *
-T -sym-trunk *
+P b6692de374d7f489d8cf8877bdfef19501bc5ecb0781d42750807eeb58f2e7cd
+R 2239c7e612edeebb85a48ece2742b418
 U drh
-Z 3735a0196c01b073213c0a5a2d772463
+Z 6ea1a8314858728c345b400d643954f7
 # Remove this line to create a well-formed Fossil manifest.
index cee32d755d59e8cadce66f2d0d561f90414d74f0..fa596718f9c44a54481d1f5e9e2a122ea15a224f 100644 (file)
@@ -1 +1 @@
-b6692de374d7f489d8cf8877bdfef19501bc5ecb0781d42750807eeb58f2e7cd
\ No newline at end of file
+1b8a128832c1633cbb86999d347fef64ac45fe134dac61132112fc97f24676a0
\ No newline at end of file
index e8c12b593c0dedea88771c328199c61d02e71b17..602a9d7df46e5acd15ca09dca0373e6b8cc4514c 100644 (file)
@@ -4152,6 +4152,8 @@ static ExprList *findLeftmostExprlist(Select *pSel){
 **        (17g) either the subquery is the first element of the outer
 **              query or there are no RIGHT or FULL JOINs in any arm
 **              of the subquery.  (This is a duplicate of condition (27b).)
+**        (17h) The corresponding result set expressions in all arms of the
+**              compound must have the same affinity.
 **
 **        The parent and sub-query may contain WHERE clauses. Subject to
 **        rules (11), (13) and (14), they may also contain ORDER BY,
@@ -4328,6 +4330,7 @@ static int flattenSubquery(
   ** queries.
   */
   if( pSub->pPrior ){
+    int ii;
     if( pSub->pOrderBy ){
       return 0;  /* Restriction (20) */
     }
@@ -4360,7 +4363,6 @@ static int flattenSubquery(
 
     /* Restriction (18). */
     if( p->pOrderBy ){
-      int ii;
       for(ii=0; ii<p->pOrderBy->nExpr; ii++){
         if( p->pOrderBy->a[ii].u.x.iOrderByCol==0 ) return 0;
       }
@@ -4369,6 +4371,21 @@ static int flattenSubquery(
     /* Restriction (23) */
     if( (p->selFlags & SF_Recursive) ) return 0;
 
+    /* Restriction (17h) */
+    for(ii=0; ii<pSub->pEList->nExpr; ii++){
+      char aff;
+      assert( pSub->pEList->a[ii].pExpr!=0 );
+      aff = sqlite3ExprAffinity(pSub->pEList->a[ii].pExpr);
+      for(pSub1=pSub->pPrior; pSub1; pSub1=pSub1->pPrior){
+        assert( pSub1->pEList!=0 );
+        assert( pSub1->pEList->nExpr>ii );
+        assert( pSub1->pEList->a[ii].pExpr!=0 );
+        if( sqlite3ExprAffinity(pSub1->pEList->a[ii].pExpr)!=aff ){
+          return 0;
+        }
+      }
+    }
+
     if( pSrc->nSrc>1 ){
       if( pParse->nSelect>500 ) return 0;
       if( OptimizationDisabled(db, SQLITE_FlttnUnionAll) ) return 0;
index 994e5d262aa727502cd8ffb6e3545794322b80bd..fda8e206cb5488e0c9f767cf24d60910fac95289 100644 (file)
@@ -7642,6 +7642,7 @@ static int SQLITE_TCLAPI optimization_control(
   const char *zOpt;
   int onoff;
   int mask = 0;
+  int cnt = 0;
   static const struct {
     const char *zOptName;
     int mask;
@@ -7661,7 +7662,6 @@ static int SQLITE_TCLAPI optimization_control(
     { "push-down",           SQLITE_PushDown       },
     { "balanced-merge",      SQLITE_BalancedMerge  },
     { "propagate-const",     SQLITE_PropagateConst },
-    { 0, 0 }
   };
 
   if( objc!=4 ){
@@ -7672,13 +7672,13 @@ static int SQLITE_TCLAPI optimization_control(
   if( Tcl_GetBooleanFromObj(interp, objv[3], &onoff) ) return TCL_ERROR;
   zOpt = Tcl_GetString(objv[2]);
   for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
-    if( strcmp(zOpt, aOpt[i].zOptName)==0 ){
-      mask = aOpt[i].mask;
-      break;
+    if( strstr(zOpt, aOpt[i].zOptName)!=0 ){
+      mask |= aOpt[i].mask;
+      cnt++;
     }
   }
   if( onoff ) mask = ~mask;
-  if( i>=sizeof(aOpt)/sizeof(aOpt[0]) ){
+  if( cnt==0 ){
     Tcl_AppendResult(interp, "unknown optimization - should be one of:",
                      (char*)0);
     for(i=0; i<sizeof(aOpt)/sizeof(aOpt[0]); i++){
index 538a5f77b784204de364107f4f93ba30400061b8..7783c04a67572a0bd73e7530fda5465970c42b64 100644 (file)
@@ -385,4 +385,60 @@ do_execsql_test 7.1 {
    ORDER BY x, y;
 } {0 1 | 0 101 | 0 102 | 1 1 | 1 101 | 1 102 | 100 1 | 100 101 | 100 102 | 101 1 | 101 101 | 101 102 |}
 
+# 2022-10-31 ticket https://sqlite.org/src/info/57c47526c34f01e8
+# dbsqlfuzz 37230460b46b3b6049f0d768eb801f3428189382
+# UNION ALL subqueries or views which have arms with different
+# affinities should not be flattened.
+#
+reset_db
+do_execsql_test 8.1 {
+  CREATE TABLE t0(c0 INT);
+  INSERT INTO t0 VALUES(0);
+  CREATE TABLE t1_a(a INTEGER PRIMARY KEY, b TEXT);
+  INSERT INTO t1_a VALUES(1,'one');
+  INSERT INTO t1_a VALUES(4,'four');
+  CREATE TABLE t1_b(c INTEGER PRIMARY KEY, d TEXT);
+  INSERT INTO t1_b VALUES(2,'two');
+  INSERT INTO t1_b VALUES(5,'five');
+  CREATE TABLE t1_c(e INTEGER PRIMARY KEY, f TEXT);
+  INSERT INTO t1_c VALUES(3,'three');
+  INSERT INTO t1_c VALUES(6,'six');
+  CREATE VIEW v0(c0) AS SELECT CAST(t0.c0 AS INTEGER) FROM t0;
+  CREATE VIEW t1 AS 
+    SELECT a, b FROM t1_a   UNION ALL
+    SELECT c, c FROM t1_b   UNION ALL
+    SELECT e, f FROM t1_c;
+}
+optimization_control db all 1
+do_execsql_test 8.2 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2;
+} {2 2 0 {}}
+do_execsql_test 8.3 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0;
+} {}
+do_execsql_test 8.4 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2';
+} {2 2 0 {}}
+optimization_control db query-flattener,push-down 0
+do_execsql_test 8.5 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2;
+} {2 2 0 {}}
+do_execsql_test 8.6 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0;
+} {}
+do_execsql_test 8.7 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2';
+} {2 2 0 {}}
+optimization_control db all 0
+do_execsql_test 8.8 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2;
+} {2 2 0 {}}
+do_execsql_test 8.9 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b=2.0;
+} {}
+do_execsql_test 8.10 {
+  SELECT * FROM (SELECT t1.a, t1.b, t0.c0 AS c, v0.c0 AS d FROM t0 LEFT JOIN v0 ON v0.c0>'0',t1) WHERE b='2';
+} {2 2 0 {}}
+
+
 finish_test