SQLite

Check-in [f0674697c9]
Login

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

Overview
Comment:Added support for UTF-8 (CVS 199)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: f0674697c90e4eed630c36e40e724de05d54f74f
User & Date: drh 2001-04-04 21:10:19.000
Context
2001-04-04
21:22
Clean up some compiler warnings (CVS 200) (check-in: 490d08a8c1 user: drh tags: trunk)
21:10
Added support for UTF-8 (CVS 199) (check-in: f0674697c9 user: drh tags: trunk)
12:33
:-) (CVS 198) (check-in: 24bede9027 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to VERSION.
1
1.0.28
|
1
1.0.29
Changes to src/sqliteInt.h.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.38 2001/04/04 11:48:58 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*************************************************************************
** Internal interface definitions for SQLite.
**
** @(#) $Id: sqliteInt.h,v 1.39 2001/04/04 21:10:19 drh Exp $
*/
#include "sqlite.h"
#include "dbbe.h"
#include "vdbe.h"
#include "parse.h"
#include <gdbm.h>
#include <stdio.h>
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int);
Table *sqliteFindTable(sqlite*,char*);
void sqliteCopy(Parse*, Token*, Token*, Token*);
void sqliteVacuum(Parse*, Token*);
int sqliteGlobCompare(const char*,const char*);
int sqliteLikeCompare(const unsigned char*,const unsigned char*);
char *sqliteTableNameFromToken(Token*);
int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);







|







410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
void sqliteWhereEnd(WhereInfo*);
void sqliteExprCode(Parse*, Expr*);
void sqliteExprIfTrue(Parse*, Expr*, int);
void sqliteExprIfFalse(Parse*, Expr*, int);
Table *sqliteFindTable(sqlite*,char*);
void sqliteCopy(Parse*, Token*, Token*, Token*);
void sqliteVacuum(Parse*, Token*);
int sqliteGlobCompare(const unsigned char*,const unsigned char*);
int sqliteLikeCompare(const unsigned char*,const unsigned char*);
char *sqliteTableNameFromToken(Token*);
int sqliteExprCheck(Parse*, Expr*, int, int*);
int sqliteExprCompare(Expr*, Expr*);
int sqliteFuncId(Token*);
int sqliteExprResolveIds(Parse*, IdList*, Expr*);
void sqliteExprResolveInSelect(Parse*, Expr*);
Changes to src/util.c.
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.18 2001/03/14 12:35:57 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If MEMORY_DEBUG is defined, then use versions of malloc() and







|







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
**
*************************************************************************
** Utility functions used throughout sqlite.
**
** This file contains functions for allocating memory, comparing
** strings, and stuff like that.
**
** $Id: util.c,v 1.19 2001/04/04 21:10:19 drh Exp $
*/
#include "sqliteInt.h"
#include <stdarg.h>
#include <ctype.h>

/*
** If MEMORY_DEBUG is defined, then use versions of malloc() and
274
275
276
277
278
279
280

281
282
283
284
285
286
287
288
  fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
#endif
#endif
}

/*
** Works like sqliteSetString, but each string is now followed by

** a length integer.  -1 means use the whole string.
*/
void sqliteSetNString(char **pz, ...){
  va_list ap;
  int nByte;
  const char *z;
  char *zResult;
  int n;







>
|







274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  fprintf(stderr,"string at 0x%x is %s\n", (int)*pz, *pz);
#endif
#endif
}

/*
** Works like sqliteSetString, but each string is now followed by
** a length integer which specifies how much of the source string 
** to copy (in bytes).  -1 means use the whole string.
*/
void sqliteSetNString(char **pz, ...){
  va_list ap;
  int nByte;
  const char *z;
  char *zResult;
  int n;
721
722
723
724
725
726
727






















































































728
729
730
731
732
733
734
735
    }
  }
  if( *a=='-' ) res = -res;
  return res;
}

/*






















































































** Compare two strings for equality where the first string can
** potentially be a "glob" expression.  Return true (1) if they
** are the same and false (0) if they are different.
**
** Globbing rules:
**
**      '*'       Matches any sequence of zero or more characters.
**







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
    }
  }
  if( *a=='-' ) res = -res;
  return res;
}

/*
** When the first byte of a UTF-8 character is used as the
** index of the following array, then the value is the number
** of bytes in the whole UTF-8 character.  This matrix assumes
** a well-formed UTF-8 string.  All bets are off if the input
** is not well-formed.
*/
static const unsigned char utf8_width[] = {
        /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */
/* 0x */   0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 1x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 2x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 3x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 4x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 5x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 6x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 7x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 8x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* 9x */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* Ax */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* Bx */   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
/* Cx */   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* Dx */   2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
/* Ex */   3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
/* Fx */   4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 1, 1,
};

/*
** This routine computes the number of bytes to the start of the
** next UTF-8 character.  We could just do 
**
**      z += utf8_width[*z]
**
** accomplish the same thing, if we know that z was a well-formed
** UTF-8 string.  If it is not, then z might be incremented past
** its null terminator.  This function, though slower, will never
** increment z past its terminator.
*/
static int utf8_char_size(const unsigned char *z){
  int i, n = utf8_width[*z];
  for(i=1; i<n && z[i]!=0; i++){}
  return i;
}

/*
** Convert the UTF-8 character pointed to by the input parameter
** into a 31-bit UCS character and return an integer holding the
** 31-bit UCS character.
*/
static int utf8_to_int(const unsigned char *z){
  int n = utf8_width[*z];
  int c;
  switch( n ){
    case 0: {
      return 0;
    }
    case 1: {
      return *z;
    }
    case 2: {
      c = 0x1f & *(z++);
      break;
    }
    case 3: {
      c = 0x0f & *(z++);
      break;
    }
    case 4: {
      c = 0x07 & *(z++);
      break;
    }
    case 5: {
      c = 0x03 & *(z++);
      break;
    }
    case 6: {
      c = 0x01 & *(z++);
      break;
    }
  }
  while( (--n) > 0 ){
    c = (c<<6) | (0x3f & *(z++));
  }
  return c;
}

/*
** Compare two UTF-8 strings for equality where the first string can
** potentially be a "glob" expression.  Return true (1) if they
** are the same and false (0) if they are different.
**
** Globbing rules:
**
**      '*'       Matches any sequence of zero or more characters.
**
748
749
750
751
752
753
754

755
756
757
758
759
760
761
762
763
764

765


766



767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782


783

784

785
786
787
788
789
790
791
792
793
794
795
796
797



798
799



800
801
802
803


804

805
806
807
808
809
810



811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838


839
840
841
842
843
844
845
846
847
848
849
850


851

852
853
854
855
856
857



858
859
860
**
** This routine is usually quick, but can be N**2 in the worst case.
**
** Hints: to match '*' or '?', put them in "[]".  Like this:
**
**         abc[*]xyz        Matches "abc*xyz" only
*/

int sqliteGlobCompare(const char *zPattern, const char *zString){
  register char c;
  int invert;
  int seen;
  char c2;

  while( (c = *zPattern)!=0 ){
    switch( c ){
      case '*':
        while( zPattern[1]=='*' ) zPattern++;

        if( zPattern[1]==0 ) return 1;


        c = zPattern[1];



        if( c=='[' || c=='?' ){
          while( *zString && sqliteGlobCompare(&zPattern[1],zString)==0 ){
            zString++;
          }
          return *zString!=0;
        }else{
          while( (c2 = *zString)!=0 ){
            while( c2 != 0 && c2 != c ){ c2 = *++zString; }
            if( c2==0 ) return 0;
            if( sqliteGlobCompare(&zPattern[1],zString) ) return 1;
            zString++;
          }
          return 0;
        }
      case '?':
        if( *zString==0 ) return 0;


        break;

      case '[':

        seen = 0;
        invert = 0;
        c = *zString;
        if( c==0 ) return 0;
        c2 = *++zPattern;
        if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
        if( c2==']' ){
          if( c==']' ) seen = 1;
          c2 = *++zPattern;
        }
        while( (c2 = *zPattern)!=0 && c2!=']' ){
          if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 ){
            if( c>zPattern[-1] && c<zPattern[1] ) seen = 1;



          }else if( c==c2 ){
            seen = 1;



          }
          zPattern++;
        }
        if( c2==0 || (seen ^ invert)==0 ) return 0;


        break;

      default:
        if( c != *zString ) return 0;
        break;
    }
    zPattern++;
    zString++;



  }
  return *zString==0;
}

/*
** Compare two strings for equality using the "LIKE" operator of
** SQL.  The '%' character matches any sequence of 0 or more
** characters and '_' matches any single character.  Case is
** not significant.
**
** This routine is just an adaptation of the sqliteGlobCompare()
** routine above.
*/
int 
sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
  register char c;
  char c2;

  while( (c = UpperToLower[*zPattern])!=0 ){
    switch( c ){
      case '%':
        while( zPattern[1]=='%' ) zPattern++;
        if( zPattern[1]==0 ) return 1;
        c = UpperToLower[0xff & zPattern[1]];
        if( c=='_' ){
          while( *zString && sqliteLikeCompare(&zPattern[1],zString)==0 ){
            zString++;
          }


          return *zString!=0;
        }else{
          while( (c2 = UpperToLower[*zString])!=0 ){
            while( c2 != 0 && c2 != c ){ c2 = UpperToLower[*++zString]; }
            if( c2==0 ) return 0;
            if( sqliteLikeCompare(&zPattern[1],zString) ) return 1;
            zString++;
          }
          return 0;
        }
      case '_':
        if( *zString==0 ) return 0;


        break;

      default:
        if( c != UpperToLower[*zString] ) return 0;
        break;
    }
    zPattern++;
    zString++;



  }
  return *zString==0;
}







>
|
|


|




|
>
|
>
>
|
>
>
>
|

|







|



|

>
>

>
|
>


|







|
|
|
>
>
>


>
>
>

|


>
>

>
|

<
<
|
|
>
>
>





|









|
|



|
<
|
<
|
|
|

>
>
|
|
|
|
|
|
|
|
|
|
|

>
>

>
|

<
<
|
|
>
>
>



835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913


914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939

940

941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964


965
966
967
968
969
970
971
972
**
** This routine is usually quick, but can be N**2 in the worst case.
**
** Hints: to match '*' or '?', put them in "[]".  Like this:
**
**         abc[*]xyz        Matches "abc*xyz" only
*/
int 
sqliteGlobCompare(const unsigned char *zPattern, const unsigned char *zString){
  register int c;
  int invert;
  int seen;
  int c2;

  while( (c = *zPattern)!=0 ){
    switch( c ){
      case '*':
        while( (c=zPattern[1]) == '*' || c == '?' ){
          if( c=='?' ){
            if( *zString==0 ) return 0;
            zString += utf8_char_size(zString);
          }
          zPattern++;
        }
        if( c==0 ) return 1;
        c = UpperToLower[c];
        if( c=='[' ){
          while( *zString && sqliteGlobCompare(&zPattern[1],zString)==0 ){
            zString += utf8_char_size(zString);
          }
          return *zString!=0;
        }else{
          while( (c2 = *zString)!=0 ){
            while( c2 != 0 && c2 != c ){ c2 = *++zString; }
            if( c2==0 ) return 0;
            if( sqliteGlobCompare(&zPattern[1],zString) ) return 1;
            zString += utf8_char_size(zString);
          }
          return 0;
        }
      case '?': {
        if( *zString==0 ) return 0;
        zString += utf8_char_size(zString);
        zPattern++;
        break;
      }
      case '[': {
        int prior_c = 0;
        seen = 0;
        invert = 0;
        c = utf8_to_int(zString);
        if( c==0 ) return 0;
        c2 = *++zPattern;
        if( c2=='^' ){ invert = 1; c2 = *++zPattern; }
        if( c2==']' ){
          if( c==']' ) seen = 1;
          c2 = *++zPattern;
        }
        while( (c2 = utf8_to_int(zPattern))!=0 && c2!=']' ){
          if( c2=='-' && zPattern[1]!=']' && zPattern[1]!=0 && prior_c>0 ){
            zPattern++;
            c2 = utf8_to_int(zPattern);
            if( c>=prior_c && c<=c2 ) seen = 1;
            prior_c = 0;
          }else if( c==c2 ){
            seen = 1;
            prior_c = c2;
          }else{
            prior_c = c2;
          }
          zPattern += utf8_char_size(zPattern);
        }
        if( c2==0 || (seen ^ invert)==0 ) return 0;
        zString += utf8_char_size(zString);
        zPattern++;
        break;
      }
      default: {
        if( c != *zString ) return 0;


        zPattern++;
        zString++;
        break;
      }
    }
  }
  return *zString==0;
}

/*
** Compare two UTF-8 strings for equality using the "LIKE" operator of
** SQL.  The '%' character matches any sequence of 0 or more
** characters and '_' matches any single character.  Case is
** not significant.
**
** This routine is just an adaptation of the sqliteGlobCompare()
** routine above.
*/
int 
sqliteLikeCompare(const unsigned char *zPattern, const unsigned char *zString){
  register int c;
  int c2;

  while( (c = UpperToLower[*zPattern])!=0 ){
    switch( c ){
      case '%': {

        while( (c=zPattern[1]) == '%' || c == '_' ){

          if( c=='_' ){
            if( *zString==0 ) return 0;
            zString += utf8_char_size(zString);
          }
          zPattern++;
        }
        if( c==0 ) return 1;
        c = UpperToLower[c];
        while( (c2=UpperToLower[*zString])!=0 ){
          while( c2 != 0 && c2 != c ){ c2 = UpperToLower[*++zString]; }
          if( c2==0 ) return 0;
          if( sqliteLikeCompare(&zPattern[1],zString) ) return 1;
          zString += utf8_char_size(zString);
        }
        return 0;
      }
      case '_': {
        if( *zString==0 ) return 0;
        zString += utf8_char_size(zString);
        zPattern++;
        break;
      }
      default: {
        if( c != UpperToLower[*zString] ) return 0;


        zPattern++;
        zString++;
        break;
      }
    }
  }
  return *zString==0;
}
Changes to test/expr.test.
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#   drh@hwaci.com
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing expressions.
#
# $Id: expr.test,v 1.10 2001/04/04 11:48:58 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)}







|







19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#   drh@hwaci.com
#   http://www.hwaci.com/drh/
#
#***********************************************************************
# This file implements regression tests for SQLite library.  The
# focus of this file is testing expressions.
#
# $Id: expr.test,v 1.11 2001/04/04 21:10:19 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Create a table to work with.
#
execsql {CREATE TABLE test1(i1 int, i2 int, r1 real, r2 real, t1 text, t2 text)}
155
156
157
158
159
160
161
















162
163
164
165
166
167
168
test_expr expr-5.8b {t1='abxyzzycy', t2='A%CX'} {t1 LIKE t2} 0
test_expr expr-5.9 {t1='abc', t2='A%_C'} {t1 LIKE t2} 1
test_expr expr-5.9b {t1='ac', t2='A%_C'} {t1 LIKE t2} 0
test_expr expr-5.10 {t1='abxyzzyc', t2='A%_C'} {t1 LIKE t2} 1
test_expr expr-5.11 {t1='abc', t2='xyz'} {t1 NOT LIKE t2} 1
test_expr expr-5.12 {t1='abc', t2='ABC'} {t1 NOT LIKE t2} 0

















test_expr expr-6.1 {t1='abc', t2='xyz'} {t1 GLOB t2} 0
test_expr expr-6.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
test_expr expr-6.3 {t1='abc', t2='A?C'} {t1 GLOB t2} 0
test_expr expr-6.4 {t1='abc', t2='a?c'} {t1 GLOB t2} 1
test_expr expr-6.5 {t1='abc', t2='abc?'} {t1 GLOB t2} 0
test_expr expr-6.6 {t1='abc', t2='A*C'} {t1 GLOB t2} 0
test_expr expr-6.7 {t1='abc', t2='a*c'} {t1 GLOB t2} 1







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







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
test_expr expr-5.8b {t1='abxyzzycy', t2='A%CX'} {t1 LIKE t2} 0
test_expr expr-5.9 {t1='abc', t2='A%_C'} {t1 LIKE t2} 1
test_expr expr-5.9b {t1='ac', t2='A%_C'} {t1 LIKE t2} 0
test_expr expr-5.10 {t1='abxyzzyc', t2='A%_C'} {t1 LIKE t2} 1
test_expr expr-5.11 {t1='abc', t2='xyz'} {t1 NOT LIKE t2} 1
test_expr expr-5.12 {t1='abc', t2='ABC'} {t1 NOT LIKE t2} 0

# The following tests only work on versions of TCL that support
# Unicode.
#
test_expr expr-5.13 "t1='a\u0080c', t2='A_C'" {t1 LIKE t2} 1
test_expr expr-5.14 "t1='a\u07FFc', t2='A_C'" {t1 LIKE t2} 1
test_expr expr-5.15 "t1='a\u0800c', t2='A_C'" {t1 LIKE t2} 1
test_expr expr-5.16 "t1='a\uFFFFc', t2='A_C'" {t1 LIKE t2} 1
test_expr expr-5.17 "t1='a\u0080', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.18 "t1='a\u07FF', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.19 "t1='a\u0800', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.20 "t1='a\uFFFF', t2='A__'" {t1 LIKE t2} 0
test_expr expr-5.21 "t1='ax\uABCD', t2='A_\uABCD'" {t1 LIKE t2} 1
test_expr expr-5.22 "t1='ax\u1234', t2='A%\u1234'" {t1 LIKE t2} 1
test_expr expr-5.23 "t1='ax\uFEDC', t2='A_%'" {t1 LIKE t2} 1
test_expr expr-5.24 "t1='ax\uFEDCy\uFEDC', t2='A%\uFEDC'" {t1 LIKE t2} 1

test_expr expr-6.1 {t1='abc', t2='xyz'} {t1 GLOB t2} 0
test_expr expr-6.2 {t1='abc', t2='ABC'} {t1 GLOB t2} 0
test_expr expr-6.3 {t1='abc', t2='A?C'} {t1 GLOB t2} 0
test_expr expr-6.4 {t1='abc', t2='a?c'} {t1 GLOB t2} 1
test_expr expr-6.5 {t1='abc', t2='abc?'} {t1 GLOB t2} 0
test_expr expr-6.6 {t1='abc', t2='A*C'} {t1 GLOB t2} 0
test_expr expr-6.7 {t1='abc', t2='a*c'} {t1 GLOB t2} 1
180
181
182
183
184
185
186




















187
188
189
190
191
192
193
test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1
test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0
test_expr expr-6.21 {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0
test_expr expr-6.22 {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1
test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1
test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1
test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0





















# The sqliteExprIfFalse and sqliteExprIfTrue routines are only
# executed as part of a WHERE clause.  Create a table suitable
# for testing these functions.
#
execsql {DROP TABLE test1}
execsql {CREATE TABLE test1(a int, b int);}







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







196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
test_expr expr-6.19 {t1='abc', t2='a[]b]c'} {t1 GLOB t2} 1
test_expr expr-6.20 {t1='abc', t2='a[^]b]c'} {t1 GLOB t2} 0
test_expr expr-6.21 {t1='abcdefg', t2='a*[de]g'} {t1 GLOB t2} 0
test_expr expr-6.22 {t1='abcdefg', t2='a*[^de]g'} {t1 GLOB t2} 1
test_expr expr-6.23 {t1='abcdefg', t2='a*?g'} {t1 GLOB t2} 1
test_expr expr-6.24 {t1='ac', t2='a*c'} {t1 GLOB t2} 1
test_expr expr-6.25 {t1='ac', t2='a*?c'} {t1 GLOB t2} 0

# These tests only work on versions of TCL that support Unicode
#
test_expr expr-6.26 "t1='a\u0080c', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.27 "t1='a\u07ffc', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.28 "t1='a\u0800c', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.29 "t1='a\uffffc', t2='a?c'" {t1 GLOB t2} 1
test_expr expr-6.30 "t1='a\u1234', t2='a?'" {t1 GLOB t2} 1
test_expr expr-6.31 "t1='a\u1234', t2='a??'" {t1 GLOB t2} 0
test_expr expr-6.32 "t1='ax\u1234', t2='a?\u1234'" {t1 GLOB t2} 1
test_expr expr-6.33 "t1='ax\u1234', t2='a*\u1234'" {t1 GLOB t2} 1
test_expr expr-6.34 "t1='ax\u1234y\u1234', t2='a*\u1234'" {t1 GLOB t2} 1
test_expr expr-6.35 "t1='a\u1234b', t2='a\[x\u1234y\]b'" {t1 GLOB t2} 1
test_expr expr-6.36 "t1='a\u1234b', t2='a\[\u1233-\u1235\]b'" {t1 GLOB t2} 1
test_expr expr-6.37 "t1='a\u1234b', t2='a\[\u1234-\u124f\]b'" {t1 GLOB t2} 1
test_expr expr-6.38 "t1='a\u1234b', t2='a\[\u1235-\u124f\]b'" {t1 GLOB t2} 0
test_expr expr-6.39 "t1='a\u1234b', t2='a\[a-\u1235\]b'" {t1 GLOB t2} 1
test_expr expr-6.40 "t1='a\u1234b', t2='a\[a-\u1234\]b'" {t1 GLOB t2} 1
test_expr expr-6.41 "t1='a\u1234b', t2='a\[a-\u1233\]b'" {t1 GLOB t2} 0


# The sqliteExprIfFalse and sqliteExprIfTrue routines are only
# executed as part of a WHERE clause.  Create a table suitable
# for testing these functions.
#
execsql {DROP TABLE test1}
execsql {CREATE TABLE test1(a int, b int);}
Changes to www/changes.tcl.
12
13
14
15
16
17
18







19
20
21
22
23
24
25
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}








chng {2001 Apr 4 (1.0.28)} {
<li>Added limited support for transactions.  At this point, transactions
    will do table locking on the GDBM backend.  There is no support (yet)
    for rollback or atomic commit.</li>
<li>Added special column names ROWID, OID, and _ROWID_ that refer to the
    unique random integer key associated with every row of every table.</li>







>
>
>
>
>
>
>







12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
}


proc chng {date desc} {
  puts "<DT><B>$date</B></DT>"
  puts "<DD><P><UL>$desc</UL></P></DD>"
}

chng {2001 Apr 5 (1.0.29)} {
<li>The LIKE and GLOB operators now assume both operands are
    UTF-8 strings.
    <font color="red">** This change could potentially
    break existing code **</font></li>
}

chng {2001 Apr 4 (1.0.28)} {
<li>Added limited support for transactions.  At this point, transactions
    will do table locking on the GDBM backend.  There is no support (yet)
    for rollback or atomic commit.</li>
<li>Added special column names ROWID, OID, and _ROWID_ that refer to the
    unique random integer key associated with every row of every table.</li>
Changes to www/index.tcl.
1
2
3
4
5
6
7
8
9
10
11
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.33 2001/04/04 12:33:36 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Database Library Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Library Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}



|







1
2
3
4
5
6
7
8
9
10
11
#
# Run this TCL script to generate HTML for the index.html file.
#
set rcsid {$Id: index.tcl,v 1.34 2001/04/04 21:10:19 drh Exp $}

puts {<html>
<head><title>SQLite: An SQL Database Library Built Atop GDBM</title></head>
<body bgcolor=white>
<h1 align=center>SQLite: An SQL Database Library Built Atop
<a href="http://www.gnu.org/software/gdbm/gdbm.html">GDBM</a></h1>
<p align=center>}
42
43
44
45
46
47
48
49

50
51
52
53
54
55
56
57
58
59
60
61
62
63
64


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
three functions and one opaque structure.</li>
<li>A <a href="tclsqlite.html">Tcl</a> interface is
included.</li>
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
the <a href="http://www.google.com/search?q=gnu+readline+library">GNU
Readline library</a></li>
<li>A Tcl-based test suite provides near 100% code coverage</li>
<li>7500+ lines of C code.  No external dependencies other than GDBM.</li>

<li>Built and tested under Linux, HPUX, and WinNT.</li>
</ul>
</p>

<h2>Current Status</h2>

<p>A <a href="changes.html">change history</a> is available online.
There are currently no <em>known</em> bugs or memory leaks
in the library.  <a href="http://gcc.gnu.org/onlinedocs/gcov_1.html">Gcov</a>
is used to verify test coverage.  The test suite currently exercises
all code except for a few areas which are unreachable or which are
only reached when <tt>malloc()</tt> fails.  The code has been tested
for memory leaks and is found to be clean.</p>

<p><b>Important Note:</b>  A bug was found in the processing of UPDATE


statements when the WHERE clause contained some terms that could be 
satisfied using indices and other terms which could not.  The problem
was fixed in version 1.0.22.  Users of prior versions of SQLite should
consider upgrading.</p>

<p>
Among the SQL features that SQLite does not currently implement are:</p>

<p>
<ul>
<li>constraints are parsed but are not enforced</li>
</ul>
</p>

<h2>Documentation</h2>

<p>The following documentation is currently available:</p>

<p><ul>
<li>Information on the <a href="sqlite.html">sqlite</a>







|
>














|
>
>
|
|
|
<

<
|
|
<
<
<
<
|







42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70

71

72
73




74
75
76
77
78
79
80
81
three functions and one opaque structure.</li>
<li>A <a href="tclsqlite.html">Tcl</a> interface is
included.</li>
<li>Command-line access program <a href="sqlite.html">sqlite</a> uses
the <a href="http://www.google.com/search?q=gnu+readline+library">GNU
Readline library</a></li>
<li>A Tcl-based test suite provides near 100% code coverage</li>
<li>Approximately 9500 lines of C code.  No external dependencies other 
than GDBM.</li>
<li>Built and tested under Linux, HPUX, and WinNT.</li>
</ul>
</p>

<h2>Current Status</h2>

<p>A <a href="changes.html">change history</a> is available online.
There are currently no <em>known</em> bugs or memory leaks
in the library.  <a href="http://gcc.gnu.org/onlinedocs/gcov_1.html">Gcov</a>
is used to verify test coverage.  The test suite currently exercises
all code except for a few areas which are unreachable or which are
only reached when <tt>malloc()</tt> fails.  The code has been tested
for memory leaks and is found to be clean.</p>

<p><b>Important Note:</b>  Beginning with version 1.0.29, the LIKE and
GLOB operators assume both operands are UTF-8 strings.  Prior to that,
both operators assumed plain ASCII strings.  Users of earlier versions
of SQLite that invoke LIKE or GLOB to compare strings containing
characters greater than 127 may have problems when they upgrade to
version 1.0.29 or later.</p>



<p><b>Important Note:</b>  Serious bugs have been found in versions
1.0.22 on Unix and 1.0.26 on Windows.  Users of these or earlier




versions of SQLite should upgrade.</p>

<h2>Documentation</h2>

<p>The following documentation is currently available:</p>

<p><ul>
<li>Information on the <a href="sqlite.html">sqlite</a>