mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +03:00
Fix a problem in GROUP BY with multiple columns. (CVS 255)
FossilOrigin-Name: 22132ce18cad31482cdb9b380cedc3f53bc532b8
This commit is contained in:
@ -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;
|
||||
|
Reference in New Issue
Block a user