NULLs compare equal to each other when computing GROUP BY categories. (CVS 2728)
FossilOrigin-Name: d9b0c9705379a8b3a28a83bb29fc1cd688fe184e
This commit is contained in:
parent
b6fb62d9b4
commit
e313382e3e
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C Update\scomments\sin\swhere.c.\s\sNo\scode\schanges.\s(CVS\s2727)
|
||||
D 2005-09-20T08:47:20
|
||||
C NULLs\scompare\sequal\sto\seach\sother\swhen\scomputing\sGROUP\sBY\scategories.\s(CVS\s2728)
|
||||
D 2005-09-20T13:12:00
|
||||
F Makefile.in 12784cdce5ffc8dfb707300c34e4f1eb3b8a14f1
|
||||
F Makefile.linux-gcc 06be33b2a9ad4f005a5f42b22c4a19dab3cbb5c7
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -63,7 +63,7 @@ F src/pragma.c 6d773e25e8af13ef0820531ad2793417f8a8959d
|
||||
F src/prepare.c fc098db25d2a121affb08686cf04833fd50452d4
|
||||
F src/printf.c bd421c1ad5e01013c89af63c60eab02852ccd15e
|
||||
F src/random.c 90adff4e73a3b249eb4f1fc2a6ff9cf78c7233a4
|
||||
F src/select.c c3fe1994da81df0e09c4604ef75180f249cabe10
|
||||
F src/select.c 52b72b7fe11ce4ddc136074a1b48ea69453f60fd
|
||||
F src/shell.c 3596c1e559b82663057940d19ba533ad421c7dd3
|
||||
F src/sqlite.h.in 461b2535550cf77aedfd44385da11ef7d63e57a2
|
||||
F src/sqliteInt.h 53daa72541b4336c5e89773cf39717ed695bd523
|
||||
@ -80,7 +80,7 @@ F src/update.c c2716c2115533ffae3d08bf8853aaba4f970f37e
|
||||
F src/utf.c bda5eb85039ef16f2d17004c1e18c96e1ab0a80c
|
||||
F src/util.c 55caaffbb2716f9928ab452d20f3e9cbbeab872d
|
||||
F src/vacuum.c 829d9e1a6d7c094b80e0899686670932eafd768c
|
||||
F src/vdbe.c de007d59f036fcd1b89a7d4172aa0d028e8689eb
|
||||
F src/vdbe.c 2a5c9474c9538e18347ab63988bad4e3de074403
|
||||
F src/vdbe.h c8e105979fc7aaf5b8004e9621904e3bd096dfa2
|
||||
F src/vdbeInt.h 7bedbb9553a10e86b53f75d99e197f3f00a732bf
|
||||
F src/vdbeapi.c 85bbe1d0243a89655433d60711b4bd71979b59cd
|
||||
@ -203,7 +203,7 @@ F test/select1.test 480233d4f5a81d7d59a55e40d05084d97e57ecdf
|
||||
F test/select2.test f3c2678c3a9f3cf08ec4988a3845bda64be6d9e3
|
||||
F test/select3.test 576df1a5cc5e01dadae9176384e2d506315afdcf
|
||||
F test/select4.test c239f516aa31f42f2ef7c6d7cd01105f08f934ca
|
||||
F test/select5.test cf5c42137d915b5e866c99d018be67dad9ebed75
|
||||
F test/select5.test 93323dd60ea8dfe2c5fee86644279dee5ad5ea23
|
||||
F test/select6.test 21b72c56e7cbcefd063fdf9bc6c89342aedabccf
|
||||
F test/select7.test 1bf795b948c133a15a2a5e99d3270e652ec58ce6
|
||||
F test/sort.test 0c33a8ae1c238377ad197387c3872175f40d3843
|
||||
@ -311,7 +311,7 @@ F www/tclsqlite.tcl ddcf912ea48695603c8ed7efb29f0812ef8d1b49
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl a99cf5f6d8bd4d5537584a2b342f0fb9fa601d8b
|
||||
F www/whentouse.tcl 97e2b5cd296f7d8057e11f44427dea8a4c2db513
|
||||
P 6ec8883c366532948e619830ff7d9f63b79fc08b
|
||||
R 83e2318d245416067a9bf94d66214656
|
||||
P bb84d27eda64479d65b13fbbcaeef6a00da4d103
|
||||
R ec917b8e5b94d2118eb0bbfbe6d750c0
|
||||
U drh
|
||||
Z 7b8f65438258711df695628d2834385c
|
||||
Z 353c0c657af079f4a5983ad6b31ab9ff
|
||||
|
@ -1 +1 @@
|
||||
bb84d27eda64479d65b13fbbcaeef6a00da4d103
|
||||
d9b0c9705379a8b3a28a83bb29fc1cd688fe184e
|
16
src/select.c
16
src/select.c
@ -12,7 +12,7 @@
|
||||
** This file contains C code routines that are called by the parser
|
||||
** to handle SELECT statements in SQLite.
|
||||
**
|
||||
** $Id: select.c,v 1.272 2005/09/19 21:05:49 drh Exp $
|
||||
** $Id: select.c,v 1.273 2005/09/20 13:12:00 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
|
||||
@ -2852,6 +2852,7 @@ int sqlite3Select(
|
||||
int addrProcessRow; /* Code to process a single input row */
|
||||
int addrEnd; /* End of all processing */
|
||||
int addrSortingIdx; /* The OP_OpenVirtual for the sorting index */
|
||||
int addrReset; /* Subroutine for resetting the accumulator */
|
||||
|
||||
addrEnd = sqlite3VdbeMakeLabel(v);
|
||||
|
||||
@ -2947,12 +2948,19 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
|
||||
|
||||
/* Generate a subroutine that will reset the group-by accumulator
|
||||
*/
|
||||
addrReset = sqlite3VdbeCurrentAddr(v);
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
sqlite3VdbeAddOp(v, OP_Return, 0, 0);
|
||||
|
||||
/* Begin a loop that will extract all source rows in GROUP BY order.
|
||||
** This might involve two separate loops with an OP_Sort in between, or
|
||||
** it might be a single loop that uses an index to extract information
|
||||
** in the right order to begin with.
|
||||
*/
|
||||
sqlite3VdbeResolveLabel(v, addrInitializeLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
|
||||
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, &pGroupBy);
|
||||
if( pWInfo==0 ) goto select_end;
|
||||
if( pGroupBy==0 ){
|
||||
@ -3010,9 +3018,9 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, iAMem+j, 0);
|
||||
if( j==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0, addrProcessRow);
|
||||
sqlite3VdbeAddOp(v, OP_Eq, 0x200, addrProcessRow);
|
||||
}else{
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 0x100, addrGroupByChange);
|
||||
sqlite3VdbeAddOp(v, OP_Ne, 0x300, addrGroupByChange);
|
||||
}
|
||||
sqlite3VdbeChangeP3(v, -1, (void*)pKeyInfo->aColl[j], P3_COLLSEQ);
|
||||
}
|
||||
@ -3033,7 +3041,7 @@ int sqlite3Select(
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, addrOutputRow);
|
||||
sqlite3VdbeAddOp(v, OP_IfMemPos, iAbortFlag, addrEnd);
|
||||
resetAccumulator(pParse, &sAggInfo);
|
||||
sqlite3VdbeAddOp(v, OP_Gosub, 0, addrReset);
|
||||
|
||||
/* Update the aggregate accumulators based on the content of
|
||||
** the current row
|
||||
|
34
src/vdbe.c
34
src/vdbe.c
@ -43,7 +43,7 @@
|
||||
** in this file for details. If in doubt, do not deviate from existing
|
||||
** commenting and indentation practices when changing or adding code.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.488 2005/09/17 15:20:28 drh Exp $
|
||||
** $Id: vdbe.c,v 1.489 2005/09/20 13:12:00 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include "os.h"
|
||||
@ -1411,8 +1411,9 @@ case OP_ToBlob: { /* no-push */
|
||||
** jump to instruction P2. Otherwise, continue to the next instruction.
|
||||
**
|
||||
** If the 0x100 bit of P1 is true and either operand is NULL then take the
|
||||
** jump. If the 0x100 bit of P1 is false then fall thru if either operand
|
||||
** is NULL.
|
||||
** jump. If the 0x100 bit of P1 is clear then fall thru if either operand
|
||||
** is NULL. If the 0x200 bit of P1 is set and both operands are NULL, then
|
||||
** return true or take the jump - treat NULL values as just another number.
|
||||
**
|
||||
** The least significant byte of P1 (mask 0xff) must be an affinity character -
|
||||
** 'n', 't', 'i' or 'o' - or 0x00. An attempt is made to coerce both values
|
||||
@ -1481,14 +1482,29 @@ case OP_Ge: { /* same as TK_GE, no-push */
|
||||
** the stack.
|
||||
*/
|
||||
if( flags&MEM_Null ){
|
||||
popStack(&pTos, 2);
|
||||
if( pOp->p2 ){
|
||||
if( pOp->p1 & 0x100 ) pc = pOp->p2-1;
|
||||
if( (pOp->p1 & 0x200)!=0 && (pTos->flags & pNos->flags & MEM_Null)!=0 ){
|
||||
/* If the 0x200 bit of P1 is set and *both* operands are NULL, then
|
||||
** pretend that both operands are integer 0. This will cause the the
|
||||
** various comparison operators to threat NULL just like any other value.
|
||||
*/
|
||||
pTos->flags = pNos->flags = MEM_Int;
|
||||
pTos->i = pNos->i = 0;
|
||||
}else{
|
||||
pTos++;
|
||||
pTos->flags = MEM_Null;
|
||||
/* If the 0x200 bit of P1 is clear or only one of the operands is NULL,
|
||||
** then the result is always NULL. The jump is taken if the 0x100 bit
|
||||
** of P1 is set.
|
||||
*/
|
||||
popStack(&pTos, 2);
|
||||
if( pOp->p2 ){
|
||||
if( pOp->p1 & 0x100 ){
|
||||
pc = pOp->p2-1;
|
||||
}
|
||||
}else{
|
||||
pTos++;
|
||||
pTos->flags = MEM_Null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
affinity = pOp->p1 & 0xFF;
|
||||
|
@ -12,7 +12,7 @@
|
||||
# focus of this file is testing aggregate functions and the
|
||||
# GROUP BY and HAVING clauses of SELECT statements.
|
||||
#
|
||||
# $Id: select5.test,v 1.13 2005/09/08 20:37:44 drh Exp $
|
||||
# $Id: select5.test,v 1.14 2005/09/20 13:12:00 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
@ -156,4 +156,17 @@ do_test select5-5.5 {
|
||||
}
|
||||
} {1 4 6 4}
|
||||
|
||||
# NULL compare equal to each other for the purposes of processing
|
||||
# the GROUP BY clause.
|
||||
#
|
||||
do_test select5-6.1 {
|
||||
execsql {
|
||||
CREATE TABLE t3(x,y);
|
||||
INSERT INTO t3 VALUES(1,NULL);
|
||||
INSERT INTO t3 VALUES(2,NULL);
|
||||
INSERT INTO t3 VALUES(3,4);
|
||||
SELECT count(x), y FROM t3 GROUP BY y ORDER BY 1
|
||||
}
|
||||
} {1 4 2 {}}
|
||||
|
||||
finish_test
|
||||
|
Loading…
Reference in New Issue
Block a user