Fix a problem in GROUP BY with multiple columns. (CVS 255)
FossilOrigin-Name: 22132ce18cad31482cdb9b380cedc3f53bc532b8
This commit is contained in:
parent
1eaa2694bf
commit
db5ed6d55d
15
manifest
15
manifest
@ -1,5 +1,5 @@
|
||||
C Bug\sfixes.\s\sTrying\sto\smake\sit\sgo\sfaster.\s(CVS\s254)
|
||||
D 2001-09-18T02:02:23
|
||||
C Fix\sa\sproblem\sin\sGROUP\sBY\swith\smultiple\scolumns.\s(CVS\s255)
|
||||
D 2001-09-18T22:17:44
|
||||
F Makefile.in a7053596881af6f2590a816ad4eb8fbbf20724a7
|
||||
F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
|
||||
F VERSION 3861a21803fcd9eb92a403027b0da2bb7add4de1
|
||||
@ -35,8 +35,8 @@ F src/test2.c 0168b39225b768cfdadd534406f9dec58c27879e
|
||||
F src/test3.c f46bad555db7a6a25be332a96ac99e4d68a1b0c5
|
||||
F src/tokenize.c 2adf0568edf41b3d3c2fcb541ac49bd6e662da0c
|
||||
F src/update.c a1952ad5d53379fa2b2d12efae5993ddb85a1ddb
|
||||
F src/util.c a09c3c12aa0259c12e7385313f527895ba3cdbf9
|
||||
F src/vdbe.c 21f5d1c5418cbf740eefec10b875632e848eb7c1
|
||||
F src/util.c 2cd0bb9693e1c538a5c6f152b7d45cc8567e6724
|
||||
F src/vdbe.c efe564f482c94d361843c5975e2a5724cf0ca8af
|
||||
F src/vdbe.h 900b59b46afdfb9c048a2a31a4478f380ab8504e
|
||||
F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
|
||||
F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
|
||||
@ -53,6 +53,7 @@ F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
|
||||
F test/lock.test 5b4d969ab92c88f8dc10d1b870a2e5fe51ee7f5f
|
||||
F test/main.test 085ece17913a487caacbc0a392638c958c83a75d
|
||||
F test/malloc.test f1400a8d002eb96f1ca0a34abe56d2ab3e324740
|
||||
F test/misc1.test 50a5ca3481fc1f3cd6b978bcd6ed04c06f26a1e6
|
||||
F test/pager.test 59bbc4e3d489529ed33db6e15595789e51056077
|
||||
F test/printf.test 93ecd43cc48e863a325560f36c3b2741f5fe0308
|
||||
F test/quick.test b6ec50f808efc06595fd324bf4f3fabadb9c7e9c
|
||||
@ -95,7 +96,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
|
||||
F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
|
||||
F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
|
||||
F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
|
||||
P b30f2b5e150a219c374f88d13386dbda190ad9ed
|
||||
R 07bb1a4a448dedf9e2b45c7aa5ee5ac1
|
||||
P 8f28a83abac59a2161d486c96386b8df726468d0
|
||||
R 716384b1a17cd98ef2ff77fe086995d1
|
||||
U drh
|
||||
Z ba1b972f8330f9b56b7e933eb997f9fb
|
||||
Z 8f168bc49c168254b9355cae69013087
|
||||
|
@ -1 +1 @@
|
||||
8f28a83abac59a2161d486c96386b8df726468d0
|
||||
22132ce18cad31482cdb9b380cedc3f53bc532b8
|
@ -14,7 +14,7 @@
|
||||
** This file contains functions for allocating memory, comparing
|
||||
** strings, and stuff like that.
|
||||
**
|
||||
** $Id: util.c,v 1.25 2001/09/16 00:13:27 drh Exp $
|
||||
** $Id: util.c,v 1.26 2001/09/18 22:17:44 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <stdarg.h>
|
||||
@ -390,10 +390,10 @@ static unsigned char UpperToLower[] = {
|
||||
*/
|
||||
int sqliteHashNoCase(const char *z, int n){
|
||||
int h = 0;
|
||||
int c;
|
||||
if( n<=0 ) n = strlen(z);
|
||||
while( n-- > 0 && (c = *z++)!=0 ){
|
||||
h = (h<<3) ^ h ^ UpperToLower[c];
|
||||
while( n > 0 ){
|
||||
h = (h<<3) ^ h ^ UpperToLower[*z++];
|
||||
n--;
|
||||
}
|
||||
if( h<0 ) h = -h;
|
||||
return h;
|
||||
|
40
src/vdbe.c
40
src/vdbe.c
@ -30,7 +30,7 @@
|
||||
** But other routines are also provided to help in building up
|
||||
** a program instruction by instruction.
|
||||
**
|
||||
** $Id: vdbe.c,v 1.71 2001/09/18 02:02:23 drh Exp $
|
||||
** $Id: vdbe.c,v 1.72 2001/09/18 22:17:44 drh Exp $
|
||||
*/
|
||||
#include "sqliteInt.h"
|
||||
#include <ctype.h>
|
||||
@ -142,6 +142,7 @@ struct Agg {
|
||||
};
|
||||
struct AggElem {
|
||||
char *zKey; /* The key to this AggElem */
|
||||
int nKey; /* Number of bytes in the key, including '\0' at end */
|
||||
AggElem *pHash; /* Next AggElem with the same hash on zKey */
|
||||
AggElem *pNext; /* Next AggElem in a list of them all */
|
||||
Mem aMem[1]; /* The values for this AggElem */
|
||||
@ -479,7 +480,7 @@ static void AggReset(Agg *p){
|
||||
** Add the given AggElem to the hash array
|
||||
*/
|
||||
static void AggEnhash(Agg *p, AggElem *pElem){
|
||||
int h = sqliteHashNoCase(pElem->zKey, 0) % p->nHash;
|
||||
int h = sqliteHashNoCase(pElem->zKey, pElem->nKey) % p->nHash;
|
||||
pElem->pHash = p->apHash[h];
|
||||
p->apHash[h] = pElem;
|
||||
}
|
||||
@ -509,18 +510,19 @@ static void AggRehash(Agg *p, int nHash){
|
||||
**
|
||||
** Return 0 on success and 1 if memory is exhausted.
|
||||
*/
|
||||
static int AggInsert(Agg *p, char *zKey){
|
||||
static int AggInsert(Agg *p, char *zKey, int nKey){
|
||||
AggElem *pElem;
|
||||
int i;
|
||||
if( p->nHash <= p->nElem*2 ){
|
||||
AggRehash(p, p->nElem*2 + 19);
|
||||
}
|
||||
if( p->nHash==0 ) return 1;
|
||||
pElem = sqliteMalloc( sizeof(AggElem) + strlen(zKey) + 1 +
|
||||
pElem = sqliteMalloc( sizeof(AggElem) + nKey +
|
||||
(p->nMem-1)*sizeof(pElem->aMem[0]) );
|
||||
if( pElem==0 ) return 1;
|
||||
pElem->zKey = (char*)&pElem->aMem[p->nMem];
|
||||
strcpy(pElem->zKey, zKey);
|
||||
memcpy(pElem->zKey, zKey, nKey);
|
||||
pElem->nKey = nKey;
|
||||
AggEnhash(p, pElem);
|
||||
pElem->pNext = p->pFirst;
|
||||
p->pFirst = pElem;
|
||||
@ -541,7 +543,7 @@ static AggElem *_AggInFocus(Agg *p){
|
||||
if( pFocus ){
|
||||
p->pCurrent = pFocus;
|
||||
}else{
|
||||
AggInsert(p,"");
|
||||
AggInsert(p,"",1);
|
||||
pFocus = p->pCurrent = p->pFirst;
|
||||
}
|
||||
return pFocus;
|
||||
@ -2311,6 +2313,22 @@ case OP_NewRecno: {
|
||||
if( VERIFY( i<0 || i>=p->nCursor || ) p->aCsr[i].pCursor==0 ){
|
||||
v = 0;
|
||||
}else{
|
||||
/* A probablistic algorithm is used to locate an unused rowid.
|
||||
** We select a rowid at random and see if it exists in the table.
|
||||
** If it does not exist, we have succeeded. If the random rowid
|
||||
** does exist, we select a new one and try again, up to 1000 times.
|
||||
**
|
||||
** For a table with less than 2 billion entries, the probability
|
||||
** of not finding a unused rowid is about 1.0e-300. This is a
|
||||
** non-zero probability, but it is still vanishingly small and should
|
||||
** never cause a problem. You are much, much more likely to have a
|
||||
** hardware failure than for this algorithm to fail.
|
||||
**
|
||||
** To promote locality of reference for repetitive inserts, the
|
||||
** first few attempts at chosing a rowid pick values just a little
|
||||
** larger than the previous rowid. This has been shown experimentally
|
||||
** to double the speed of the COPY operation.
|
||||
*/
|
||||
int res, rx, cnt;
|
||||
static int x = 0;
|
||||
union {
|
||||
@ -2319,7 +2337,7 @@ case OP_NewRecno: {
|
||||
} ux;
|
||||
cnt = 0;
|
||||
do{
|
||||
if( x==0 || cnt>5 ){
|
||||
if( cnt>5 ){
|
||||
x = sqliteRandomInteger();
|
||||
}else{
|
||||
x += sqliteRandomByte() + 1;
|
||||
@ -2332,7 +2350,7 @@ case OP_NewRecno: {
|
||||
v = ux.i;
|
||||
rx = sqliteBtreeMoveto(p->aCsr[i].pCursor, &v, sizeof(v), &res);
|
||||
cnt++;
|
||||
}while( cnt<200 && rx==SQLITE_OK && res==0 );
|
||||
}while( cnt<1000 && rx==SQLITE_OK && res==0 );
|
||||
if( rx==SQLITE_OK && res==0 ){
|
||||
rc = SQLITE_FULL;
|
||||
goto abort_due_to_error;
|
||||
@ -3457,16 +3475,16 @@ case OP_AggFocus: {
|
||||
if( p->agg.nHash<=0 ){
|
||||
pElem = 0;
|
||||
}else{
|
||||
int h = sqliteHashNoCase(zKey, nKey-1) % p->agg.nHash;
|
||||
int h = sqliteHashNoCase(zKey, nKey) % p->agg.nHash;
|
||||
for(pElem=p->agg.apHash[h]; pElem; pElem=pElem->pHash){
|
||||
if( strcmp(pElem->zKey, zKey)==0 ) break;
|
||||
if( pElem->nKey==nKey && memcmp(pElem->zKey, zKey, nKey)==0 ) break;
|
||||
}
|
||||
}
|
||||
if( pElem ){
|
||||
p->agg.pCurrent = pElem;
|
||||
pc = pOp->p2 - 1;
|
||||
}else{
|
||||
AggInsert(&p->agg, zKey);
|
||||
AggInsert(&p->agg, zKey, nKey);
|
||||
if( sqlite_malloc_failed ) goto no_mem;
|
||||
}
|
||||
POPSTACK;
|
||||
|
104
test/misc1.test
Normal file
104
test/misc1.test
Normal file
@ -0,0 +1,104 @@
|
||||
# 2001 September 15
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
# This file implements tests for miscellanous features that were
|
||||
# left out of other test files.
|
||||
#
|
||||
# $Id: misc1.test,v 1.1 2001/09/18 22:17:45 drh Exp $
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
|
||||
# Test the creation and use of tables that have a large number
|
||||
# of columns.
|
||||
#
|
||||
do_test misc1-1.1 {
|
||||
set cmd "CREATE TABLE manycol(x0 text"
|
||||
for {set i 1} {$i<=99} {incr i} {
|
||||
append cmd ",x$i text"
|
||||
}
|
||||
append cmd ")";
|
||||
execsql $cmd
|
||||
set cmd "INSERT INTO manycol VALUES(0"
|
||||
for {set i 1} {$i<=99} {incr i} {
|
||||
append cmd ",$i"
|
||||
}
|
||||
append cmd ")";
|
||||
execsql $cmd
|
||||
execsql "SELECT x99 FROM manycol"
|
||||
} 99
|
||||
do_test misc1-1.2 {
|
||||
execsql {SELECT x0, x10, x25, x50, x75 FROM manycol}
|
||||
} {0 10 25 50 75}
|
||||
do_test misc1-1.3 {
|
||||
for {set j 100} {$j<=1000} {incr j 100} {
|
||||
set cmd "INSERT INTO manycol VALUES($j"
|
||||
for {set i 1} {$i<=99} {incr i} {
|
||||
append cmd ",[expr {$i+$j}]"
|
||||
}
|
||||
append cmd ")"
|
||||
execsql $cmd
|
||||
}
|
||||
execsql {SELECT x50 FROM manycol ORDER BY x80}
|
||||
} {50 150 250 350 450 550 650 750 850 950 1050}
|
||||
do_test misc1-1.4 {
|
||||
execsql {SELECT x75 FROM manycol WHERE x50=350}
|
||||
} 375
|
||||
do_test misc1-1.5 {
|
||||
execsql {SELECT x50 FROM manycol WHERE x99=599}
|
||||
} 550
|
||||
do_test misc1-1.6 {
|
||||
execsql {CREATE INDEX manycol_idx1 ON manycol(x99)}
|
||||
execsql {SELECT x50 FROM manycol WHERE x99=899}
|
||||
} 850
|
||||
do_test misc1-1.7 {
|
||||
execsql {SELECT count(*) FROM manycol}
|
||||
} 11
|
||||
do_test misc1-1.8 {
|
||||
execsql {DELETE FROM manycol WHERE x98=1234}
|
||||
execsql {SELECT count(*) FROM manycol}
|
||||
} 11
|
||||
do_test misc1-1.9 {
|
||||
execsql {DELETE FROM manycol WHERE x98=998}
|
||||
execsql {SELECT count(*) FROM manycol}
|
||||
} 10
|
||||
do_test misc1-1.10 {
|
||||
execsql {DELETE FROM manycol WHERE x99=500}
|
||||
execsql {SELECT count(*) FROM manycol}
|
||||
} 10
|
||||
do_test misc1-1.11 {
|
||||
execsql {DELETE FROM manycol WHERE x99=599}
|
||||
execsql {SELECT count(*) FROM manycol}
|
||||
} 9
|
||||
|
||||
# Check GROUP BY expressions that name two or more columns.
|
||||
#
|
||||
do_test misc1-2.1 {
|
||||
execsql {
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE agger(one text, two text, three text, four text);
|
||||
INSERT INTO agger VALUES(1, 'one', 'hello', 'yes');
|
||||
INSERT INTO agger VALUES(2, 'two', 'howdy', 'no');
|
||||
INSERT INTO agger VALUES(3, 'thr', 'howareya', 'yes');
|
||||
INSERT INTO agger VALUES(4, 'two', 'lothere', 'yes');
|
||||
INSERT INTO agger VALUES(5, 'one', 'atcha', 'yes');
|
||||
INSERT INTO agger VALUES(6, 'two', 'hello', 'no');
|
||||
COMMIT
|
||||
}
|
||||
execsql {SELECT count(*) FROM agger}
|
||||
} 6
|
||||
do_test misc1-2.2 {
|
||||
execsql {SELECT sum(one), two, four FROM agger
|
||||
GROUP BY two, four ORDER BY sum(one) desc}
|
||||
} {8 two no 6 one yes 4 two yes 3 thr yes}
|
||||
|
||||
finish_test
|
Loading…
x
Reference in New Issue
Block a user