SQLite4
Check-in [6c9adc9acc]
Not logged in

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

Overview
Comment:Add an xMkKey callback to the built-in collation sequence "nocase". Fix a bug in encoding text values with collation sequences into database keys.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 6c9adc9acc1d16456dc53e85296753b44929ae37
User & Date: dan 2012-04-23 14:11:49
Context
2012-04-23
14:26
Remove the VDBE merge sorter. check-in: 1073bb477e user: drh tags: trunk
14:11
Add an xMkKey callback to the built-in collation sequence "nocase". Fix a bug in encoding text values with collation sequences into database keys. check-in: 6c9adc9acc user: dan tags: trunk
12:47
Remove the sqlite4_get_table() API. check-in: ff68adaca1 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/main.c.

586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
















606
607
608
609
610
611
612
....
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
....
1946
1947
1948
1949
1950
1951
1952
1953


1954
1955
1956
1957
1958
1959
1960
....
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
**
** This collating sequence is intended to be used for "case independant
** comparison". SQLite's knowledge of upper and lower case equivalents
** extends only to the 26 characters used in the English language.
**
** At the moment there is only a UTF-8 implementation.
*/
static int nocaseCollatingFunc(
  void *NotUsed,
  int nKey1, const void *pKey1,
  int nKey2, const void *pKey2
){
  int r = sqlite4StrNICmp(
      (const char *)pKey1, (const char *)pKey2, (nKey1<nKey2)?nKey1:nKey2);
  UNUSED_PARAMETER(NotUsed);
  if( 0==r ){
    r = nKey1-nKey2;
  }
  return r;
}

















/*
** Return the ROWID of the most recent insert
*/
sqlite_int64 sqlite4_last_insert_rowid(sqlite4 *db){
  return db->lastRowid;
}
................................................................................
*/
static int createCollation(
  sqlite4* db,
  const char *zName, 
  u8 enc,
  void* pCtx,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,const void*,int,const void*,int),
  void(*xDel)(void*)
){
  CollSeq *pColl;
  int enc2;
  int nName = sqlite4Strlen30(zName);
  
  assert( sqlite4_mutex_held(db->mutex) );
................................................................................
  if( db->mallocFailed ){
    goto opendb_out;
  }
  db->pDfltColl = sqlite4FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
  assert( db->pDfltColl!=0 );

  /* Also add a UTF-8 case-insensitive collation sequence. */
  createCollation(db, "NOCASE", SQLITE_UTF8, 0, nocaseCollatingFunc, 0, 0);



  /* Parse the filename/URI argument. */
  db->openFlags = flags;
  rc = sqlite4ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
  if( rc!=SQLITE_OK ){
    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    sqlite4Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
................................................................................
*/
int sqlite4_create_collation(
  sqlite4* db, 
  const char *zName, 
  int enc, 
  void* pCtx,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,int,const void*,int,const void*),
  void(*xDel)(void*)
){
  int rc;
  sqlite4_mutex_enter(db->mutex);
  assert( !db->mallocFailed );
  rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xMakeKey, xDel);
  rc = sqlite4ApiExit(db, rc);







|












>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







|







 







|
>
>







 







|







586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
....
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
....
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
....
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
**
** This collating sequence is intended to be used for "case independant
** comparison". SQLite's knowledge of upper and lower case equivalents
** extends only to the 26 characters used in the English language.
**
** At the moment there is only a UTF-8 implementation.
*/
static int collNocaseCmp(
  void *NotUsed,
  int nKey1, const void *pKey1,
  int nKey2, const void *pKey2
){
  int r = sqlite4StrNICmp(
      (const char *)pKey1, (const char *)pKey2, (nKey1<nKey2)?nKey1:nKey2);
  UNUSED_PARAMETER(NotUsed);
  if( 0==r ){
    r = nKey1-nKey2;
  }
  return r;
}

static int collNocaseMkKey(
  void *NotUsed,
  int nIn, const void *pKey1,
  int nOut, void *pKey2
){
  if( nOut<nIn ){
    int i;
    u8 *aIn = (u8 *)pKey1;
    u8 *aOut = (u8 *)pKey2;
    for(i=0; i<nIn; i++){
      aOut[i] = sqlite4UpperToLower[aIn[i]];
    }
  }
  return nIn;
}

/*
** Return the ROWID of the most recent insert
*/
sqlite_int64 sqlite4_last_insert_rowid(sqlite4 *db){
  return db->lastRowid;
}
................................................................................
*/
static int createCollation(
  sqlite4* db,
  const char *zName, 
  u8 enc,
  void* pCtx,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,int,const void*,int,void*),
  void(*xDel)(void*)
){
  CollSeq *pColl;
  int enc2;
  int nName = sqlite4Strlen30(zName);
  
  assert( sqlite4_mutex_held(db->mutex) );
................................................................................
  if( db->mallocFailed ){
    goto opendb_out;
  }
  db->pDfltColl = sqlite4FindCollSeq(db, SQLITE_UTF8, "BINARY", 0);
  assert( db->pDfltColl!=0 );

  /* Also add a UTF-8 case-insensitive collation sequence. */
  createCollation(db, 
      "NOCASE", SQLITE_UTF8, 0, collNocaseCmp, collNocaseMkKey, 0
  );

  /* Parse the filename/URI argument. */
  db->openFlags = flags;
  rc = sqlite4ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg);
  if( rc!=SQLITE_OK ){
    if( rc==SQLITE_NOMEM ) db->mallocFailed = 1;
    sqlite4Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg);
................................................................................
*/
int sqlite4_create_collation(
  sqlite4* db, 
  const char *zName, 
  int enc, 
  void* pCtx,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,int,const void*,int,void*),
  void(*xDel)(void*)
){
  int rc;
  sqlite4_mutex_enter(db->mutex);
  assert( !db->mallocFailed );
  rc = createCollation(db, zName, (u8)enc, pCtx, xCompare, xMakeKey, xDel);
  rc = sqlite4ApiExit(db, rc);

Changes to src/sqlite.h.in.

3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
*/
int sqlite4_create_collation(
  sqlite4*, 
  const char *zName, 
  int eTextRep, 
  void *pArg,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,int,const void*,int,const void*),
  void(*xDestroy)(void*)
);

/*
** CAPI3REF: Collation Needed Callbacks
**
** ^To avoid having to register all collation sequences before a database







|







3897
3898
3899
3900
3901
3902
3903
3904
3905
3906
3907
3908
3909
3910
3911
*/
int sqlite4_create_collation(
  sqlite4*, 
  const char *zName, 
  int eTextRep, 
  void *pArg,
  int(*xCompare)(void*,int,const void*,int,const void*),
  int(*xMakeKey)(void*,int,const void*,int,void*),
  void(*xDestroy)(void*)
);

/*
** CAPI3REF: Collation Needed Callbacks
**
** ^To avoid having to register all collation sequences before a database

Changes to src/sqliteInt.h.

1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
** collating sequence may not be read or written.
*/
struct CollSeq {
  char *zName;          /* Name of the collating sequence, UTF-8 encoded */
  u8 enc;               /* Text encoding handled by xCmp() */
  void *pUser;          /* First argument to xCmp() */
  int (*xCmp)(void*,int, const void*, int, const void*);
  int (*xMkKey)(void*,const void*,int,const void*,int);
  void (*xDel)(void*);  /* Destructor for pUser */
};

/*
** A sort order can be either ASC or DESC.
*/
#define SQLITE_SO_ASC       0  /* Sort in ascending order */







|







1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
** collating sequence may not be read or written.
*/
struct CollSeq {
  char *zName;          /* Name of the collating sequence, UTF-8 encoded */
  u8 enc;               /* Text encoding handled by xCmp() */
  void *pUser;          /* First argument to xCmp() */
  int (*xCmp)(void*,int, const void*, int, const void*);
  int (*xMkKey)(void*,int, const void*, int, void*);
  void (*xDel)(void*);  /* Destructor for pUser */
};

/*
** A sort order can be either ASC or DESC.
*/
#define SQLITE_SO_ASC       0  /* Sort in ascending order */

Changes to src/vdbecodec.c.

566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  if( flags & MEM_Str ){
    if( enlargeEncoderAllocation(p, pMem->n*4 + 2) ) return SQLITE_NOMEM;
    p->aOut[p->nOut++] = 0x24;   /* Text */
    if( pColl==0 || pColl->xMkKey==0 ){
      memcpy(p->aOut+p->nOut, pMem->z, pMem->n);
      p->nOut += pMem->n;
    }else{
      n = pColl->xMkKey(pColl->pUser, pMem->z, pMem->n, p->aOut+p->nOut,
                        p->nAlloc - p->nOut);
      if( n > p->nAlloc - p->nOut ){
        if( enlargeEncoderAllocation(p, n) ) return SQLITE_NOMEM;
        pColl->xMkKey(pColl->pUser, pMem->z, pMem->n, p->aOut+p->nOut,
                        p->nAlloc - p->nOut);
      }
    }
    p->aOut[p->nOut++] = 0x00;
  }else
  {
    const unsigned char *a;
    unsigned char s, t;
    assert( flags & MEM_Blob );







|
|
|
|
|
|
|







566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
  if( flags & MEM_Str ){
    if( enlargeEncoderAllocation(p, pMem->n*4 + 2) ) return SQLITE_NOMEM;
    p->aOut[p->nOut++] = 0x24;   /* Text */
    if( pColl==0 || pColl->xMkKey==0 ){
      memcpy(p->aOut+p->nOut, pMem->z, pMem->n);
      p->nOut += pMem->n;
    }else{
      int nSpc = p->nAlloc-p->nOut;
      n = pColl->xMkKey(pColl->pUser, pMem->n, pMem->z, nSpc, p->aOut+p->nOut);
      if( n>nSpc ){
        if( enlargeEncoderAllocation(p, n) ) return SQLITE_NOMEM;
        pColl->xMkKey(pColl->pUser, pMem->n, pMem->z, n, p->aOut+p->nOut);
      }
      p->nOut += n;
    }
    p->aOut[p->nOut++] = 0x00;
  }else
  {
    const unsigned char *a;
    unsigned char s, t;
    assert( flags & MEM_Blob );

Changes to test/simple.test.

887
888
889
890
891
892
893













894
895
896
do_execsql_test 46.1 {
  CREATE TABLE t1(x);
  CREATE UNIQUE INDEX i1 ON t1(x);
}

do_execsql_test 46.2 { INSERT INTO t1 VALUES(NULL) }
do_execsql_test 46.3 { INSERT INTO t1 VALUES(NULL) }














finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>



887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
do_execsql_test 46.1 {
  CREATE TABLE t1(x);
  CREATE UNIQUE INDEX i1 ON t1(x);
}

do_execsql_test 46.2 { INSERT INTO t1 VALUES(NULL) }
do_execsql_test 46.3 { INSERT INTO t1 VALUES(NULL) }

#-------------------------------------------------------------------------
reset_db

do_execsql_test 46.1 {
  CREATE TABLE t1(x, y COLLATE nocase);
  CREATE UNIQUE INDEX i1 ON t1(y);
}

do_catchsql_test 46.2 {
  INSERT INTO t1 VALUES(1, 'ABC');
  INSERT INTO t1 VALUES(2, 'abc');
} {1 {column y is not unique}}

finish_test