Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Support for UTF-8 and ISO8859 characters in identifiers. Bug fix in the column name generator for selects (was coreing). (CVS 290) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
22948fc685299ca888907eea68edb8a6 |
User & Date: | drh 2001-10-18 12:34:47.000 |
Context
2001-10-19
| ||
16:44 | Version 2.0.6 (CVS 291) (check-in: 8467d84fc6 user: drh tags: trunk) | |
2001-10-18
| ||
12:34 | Support for UTF-8 and ISO8859 characters in identifiers. Bug fix in the column name generator for selects (was coreing). (CVS 290) (check-in: 22948fc685 user: drh tags: trunk) | |
2001-10-15
| ||
00:45 | Version 2.0.5 (CVS 465) (check-in: e2d84f71ed user: drh tags: trunk) | |
Changes
Changes to src/os.c.
︙ | ︙ | |||
573 574 575 576 577 578 579 | rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; id.pLock->cnt = -1; needSysLock = 1; } }else{ | | | 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; id.pLock->cnt = -1; needSysLock = 1; } }else{ if( id.pLock->cnt<0 ){ rc = SQLITE_BUSY; }else{ rc = SQLITE_OK; needSysLock = id.pLock->cnt==0; id.pLock->cnt++; } } |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
14 15 16 17 18 19 20 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** | | | 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | ** The pager is used to access a database disk file. It implements ** atomic commit and rollback through the use of a journal file that ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** ** @(#) $Id: pager.c,v 1.28 2001/10/18 12:34:47 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" #include "os.h" #include <assert.h> #include <string.h> |
︙ | ︙ | |||
1072 1073 1074 1075 1076 1077 1078 | rc = pager_playback(pPager); if( rc!=SQLITE_OK ){ rc = SQLITE_CORRUPT; pPager->errMask |= PAGER_ERR_CORRUPT; } pPager->dbSize = -1; return rc; | < > | 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 | rc = pager_playback(pPager); if( rc!=SQLITE_OK ){ rc = SQLITE_CORRUPT; pPager->errMask |= PAGER_ERR_CORRUPT; } pPager->dbSize = -1; return rc; } /* ** Return TRUE if the database file is opened read-only. Return FALSE ** if the database is (in theory) writable. */ int sqlitepager_isreadonly(Pager *pPager){ return pPager->readOnly; |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.41 2001/10/18 12:34:47 drh Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. */ |
︙ | ︙ | |||
252 253 254 255 256 257 258 | if( p->span.z && p->span.z[0] && !showFullNames ){ int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0); sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n); sqliteVdbeCompressSpace(v, addr); }else if( p->op==TK_COLUMN && pTabList ){ if( pTabList->nId>1 || showFullNames ){ char *zName = 0; | | | | 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 | if( p->span.z && p->span.z[0] && !showFullNames ){ int addr = sqliteVdbeAddOp(v,OP_ColumnName, i, 0); sqliteVdbeChangeP3(v, -1, p->span.z, p->span.n); sqliteVdbeCompressSpace(v, addr); }else if( p->op==TK_COLUMN && pTabList ){ if( pTabList->nId>1 || showFullNames ){ char *zName = 0; Table *pTab = pTabList->a[p->iTable - pParse->nTab].pTab; char *zTab; zTab = pTabList->a[p->iTable - pParse->nTab].zAlias; if( zTab==0 ) zTab = pTab->zName; sqliteSetString(&zName, zTab, ".", pTab->aCol[p->iColumn].zName, 0); sqliteVdbeAddOp(v, OP_ColumnName, i, 0); sqliteVdbeChangeP3(v, -1, zName, strlen(zName)); sqliteFree(zName); }else{ Table *pTab = pTabList->a[0].pTab; |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.63 2001/10/18 12:34:47 drh Exp $ */ #include "sqlite.h" #include "hash.h" #include "vdbe.h" #include "parse.h" #include "btree.h" #include <stdio.h> |
︙ | ︙ | |||
408 409 410 411 412 413 414 | #else void *sqliteMalloc(int); void sqliteFree(void*); void *sqliteRealloc(void*,int); char *sqliteStrDup(const char*); char *sqliteStrNDup(const char*, int); #endif | < | 408 409 410 411 412 413 414 415 416 417 418 419 420 421 | #else void *sqliteMalloc(int); void sqliteFree(void*); void *sqliteRealloc(void*,int); char *sqliteStrDup(const char*); char *sqliteStrNDup(const char*, int); #endif void sqliteSetString(char **, const char *, ...); void sqliteSetNString(char **, ...); void sqliteDequote(char*); int sqliteRunParser(Parse*, char*, char **); void sqliteExec(Parse*); Expr *sqliteExpr(int, Expr*, Expr*, Token*); void sqliteExprSpan(Expr*,Token*,Token*); |
︙ | ︙ |
Changes to src/tclsqlite.c.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** A TCL Interface to SQLite ** | | > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | /* ** 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. ** ************************************************************************* ** A TCL Interface to SQLite ** ** $Id: tclsqlite.c,v 1.25 2001/10/18 12:34:47 drh Exp $ */ #ifndef NO_TCL /* Omit this whole file if TCL is unavailable */ #include "sqlite.h" #include "tcl.h" #include <stdlib.h> #include <string.h> /* ** If TCL uses UTF-8 and SQLite is configured to use iso8859, then we ** have to do a translation when going between the two. Set the ** UTF_TRANSLATION_NEEDED macro to indicate that we need to do ** this translation. */ #if defined(TCL_UTF_MAX) && !defined(SQLITE_UTF8) # define UTF_TRANSLATION_NEEDED 1 #endif /* ** There is one instance of this structure for each SQLite database ** that has been opened by the SQLite TCL interface. */ typedef struct SqliteDb SqliteDb; struct SqliteDb { sqlite *db; /* The "real" database structure */ |
︙ | ︙ | |||
38 39 40 41 42 43 44 | typedef struct CallbackData CallbackData; struct CallbackData { Tcl_Interp *interp; /* The TCL interpreter */ char *zArray; /* The array into which data is written */ Tcl_Obj *pCode; /* The code to execute for each row */ int once; /* Set only for the first invocation of callback */ int tcl_rc; /* Return code from TCL script */ | < < < < < | > | < < < > | 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | typedef struct CallbackData CallbackData; struct CallbackData { Tcl_Interp *interp; /* The TCL interpreter */ char *zArray; /* The array into which data is written */ Tcl_Obj *pCode; /* The code to execute for each row */ int once; /* Set only for the first invocation of callback */ int tcl_rc; /* Return code from TCL script */ #ifdef UTF_TRANSLATION_NEEDED int nColName; /* Number of entries in the azColName[] array */ char **azColName; /* Column names translated to UTF-8 */ #endif }; /* ** Called for each row of the result. */ static int DbEvalCallback( void *clientData, /* An instance of CallbackData */ int nCol, /* Number of columns in the result */ |
︙ | ︙ |
Changes to src/tokenize.c.
︙ | ︙ | |||
11 12 13 14 15 16 17 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** | | | 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | ************************************************************************* ** An tokenizer for SQL ** ** This file contains C code that splits an SQL input string up into ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** ** $Id: tokenize.c,v 1.28 2001/10/18 12:34:48 drh Exp $ */ #include "sqliteInt.h" #include "os.h" #include <ctype.h> #include <stdlib.h> /* |
︙ | ︙ | |||
133 134 135 136 137 138 139 140 141 142 143 144 145 | for(p=apHashTable[h]; p; p=p->pNext){ if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){ return p->tokenType; } } return TK_ID; } /* ** Return the length of the token that begins at z[0]. Return ** -1 if the token is (or might be) incomplete. Store the token ** type in *tokenType before returning. */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 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 185 | for(p=apHashTable[h]; p; p=p->pNext){ if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){ return p->tokenType; } } return TK_ID; } /* ** If X is a character that can be used in an identifier then ** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0. ** ** In this implementation, an identifier can be a string of ** alphabetic characters, digits, and "_" plus any character ** with the high-order bit set. The latter rule means that ** any sequence of UTF-8 characters or characters taken from ** an extended ISO8859 character set can form an identifier. */ static const char isIdChar[] = { /* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 1x */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 2x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 3x */ 0, 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, 0, 0, 0, 0, 1, /* 5x */ 0, 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, 0, 0, 0, 0, 0, /* 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 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */ }; /* ** Return the length of the token that begins at z[0]. Return ** -1 if the token is (or might be) incomplete. Store the token ** type in *tokenType before returning. */ static int sqliteGetToken(const unsigned char *z, int *tokenType){ int i; switch( *z ){ case ' ': case '\t': case '\n': case '\f': case '\r': { for(i=1; z[i] && isspace(z[i]); i++){} *tokenType = TK_SPACE; return i; } |
︙ | ︙ | |||
290 291 292 293 294 295 296 | while( z[i] && isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; }else if( z[0]=='.' ){ *tokenType = TK_FLOAT; } return i; } | < < < < < < < < < | > > > | < < < | 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | while( z[i] && isdigit(z[i]) ){ i++; } *tokenType = TK_FLOAT; }else if( z[0]=='.' ){ *tokenType = TK_FLOAT; } return i; } default: { if( !isIdChar[*z] ){ break; } for(i=1; isIdChar[z[i]]; i++){} *tokenType = sqliteKeywordCode(z, i); return i; } } *tokenType = TK_ILLEGAL; return 1; } /* ** Run the parser on the given SQL string. The parser structure is |
︙ | ︙ | |||
346 347 348 349 350 351 352 | if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){ pParse->rc = SQLITE_INTERRUPT; sqliteSetString(pzErrMsg, "interrupt", 0); break; } pParse->sLastToken.z = &zSql[i]; | | | 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 | if( (pParse->db->flags & SQLITE_Interrupt)!=0 ){ pParse->rc = SQLITE_INTERRUPT; sqliteSetString(pzErrMsg, "interrupt", 0); break; } pParse->sLastToken.z = &zSql[i]; pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType); i += pParse->sLastToken.n; if( once ){ pParse->sFirstToken = pParse->sLastToken; once = 0; } switch( tokenType ){ case TK_SPACE: |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
26 27 28 29 30 31 32 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** | | | 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | ** type to the other occurs as necessary. ** ** Most of the code in this file is taken up by the sqliteVdbeExec() ** function which does the work of interpreting a VDBE program. ** But other routines are also provided to help in building up ** a program instruction by instruction. ** ** $Id: vdbe.c,v 1.86 2001/10/18 12:34:48 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> /* ** SQL is translated into a sequence of instructions to be ** executed by a virtual machine. Each instruction is an instance |
︙ | ︙ | |||
1657 1658 1659 1660 1661 1662 1663 | */ case OP_Like: { int tos = p->tos; int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; | | > | 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 | */ case OP_Like: { int tos = p->tos; int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; c = sqliteLikeCompare((unsigned char*)zStack[tos], (unsigned char*)zStack[nos]); POPSTACK; POPSTACK; if( pOp->p1 ) c = !c; if( c ) pc = pOp->p2-1; break; } |
︙ | ︙ | |||
1689 1690 1691 1692 1693 1694 1695 | */ case OP_Glob: { int tos = p->tos; int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; | | > | 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 | */ case OP_Glob: { int tos = p->tos; int nos = tos - 1; int c; VERIFY( if( nos<0 ) goto not_enough_stack; ) if( Stringify(p, tos) || Stringify(p, nos) ) goto no_mem; c = sqliteGlobCompare((unsigned char*)zStack[tos], (unsigned char*)zStack[nos]); POPSTACK; POPSTACK; if( pOp->p1 ) c = !c; if( c ) pc = pOp->p2-1; break; } |
︙ | ︙ | |||
3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 | for(i=p->tos-nField+1; i<=p->tos; i++){ zNewKey[j++] = pOp->p3[k++]; memcpy(&zNewKey[j], zStack[i], aStack[i].n-1); j += aStack[i].n-1; zNewKey[j++] = 0; } zNewKey[j] = 0; PopStack(p, nField); VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; zStack[p->tos] = zNewKey; break; | > | 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 | for(i=p->tos-nField+1; i<=p->tos; i++){ zNewKey[j++] = pOp->p3[k++]; memcpy(&zNewKey[j], zStack[i], aStack[i].n-1); j += aStack[i].n-1; zNewKey[j++] = 0; } zNewKey[j] = 0; VERIFY( j<nByte ); PopStack(p, nField); VERIFY( NeedStack(p, p->tos+1); ) p->tos++; aStack[p->tos].n = nByte; aStack[p->tos].flags = STK_Str|STK_Dyn; zStack[p->tos] = zNewKey; break; |
︙ | ︙ |
Changes to test/select1.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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. The # focus of this file is testing the SELECT statement. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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. The # focus of this file is testing the SELECT statement. # # $Id: select1.test,v 1.13 2001/10/18 12:34:48 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Try to select on a non-existant table. # do_test select1-1.1 { |
︙ | ︙ | |||
245 246 247 248 249 250 251 | } {0 {test1.f1 11 test1.f1 33}} do_test select1-6.1.2 { set v [catch {execsql2 {SELECT f1 as 'f1' FROM test1 ORDER BY f2}} msg] lappend v $msg } {0 {f1 11 f1 33}} do_test select1-6.1.3 { set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg] | < > > > > > > > > > | 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 | } {0 {test1.f1 11 test1.f1 33}} do_test select1-6.1.2 { set v [catch {execsql2 {SELECT f1 as 'f1' FROM test1 ORDER BY f2}} msg] lappend v $msg } {0 {f1 11 f1 33}} do_test select1-6.1.3 { set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg] lappend v $msg } {0 {test1.f1 11 test1.f2 22}} do_test select1-6.1.4 { set v [catch {execsql2 {SELECT DISTINCT * FROM test1 WHERE f1==11}} msg] execsql {PRAGMA full_column_names=off} lappend v $msg } {0 {test1.f1 11 test1.f2 22}} do_test select1-6.1.5 { set v [catch {execsql2 {SELECT * FROM test1 WHERE f1==11}} msg] lappend v $msg } {0 {f1 11 f2 22}} do_test select1-6.1.6 { set v [catch {execsql2 {SELECT DISTINCT * FROM test1 WHERE f1==11}} msg] lappend v $msg } {0 {f1 11 f2 22}} do_test select1-6.2 { set v [catch {execsql2 {SELECT f1 as xyzzy FROM test1 ORDER BY f2}} msg] lappend v $msg } {0 {xyzzy 11 xyzzy 33}} do_test select1-6.3 { set v [catch {execsql2 {SELECT f1 as "xyzzy" FROM test1 ORDER BY f2}} msg] |
︙ | ︙ |
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 Oct 14 (2.0.5)} { <li>Added the COUNT_CHANGES pragma.</li> <li>Changes to the FULL_COLUMN_NAMES pragma to help out the ODBC driver.</li> <li>Bug fix: "SELECT count(*)" was returning NULL for empty tables. Now it returns 0.</li> } | > > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | } proc chng {date desc} { puts "<DT><B>$date</B></DT>" puts "<DD><P><UL>$desc</UL></P></DD>" } chng {2001 Oct ?? (2.0.6)} { <li>Support for UTF-8 and ISO8859 characters in column and table names.</li> <li>Bug fix: Compute correct table names with the FULL_COLUMN_NAMES pragma is turned on.</li> } chng {2001 Oct 14 (2.0.5)} { <li>Added the COUNT_CHANGES pragma.</li> <li>Changes to the FULL_COLUMN_NAMES pragma to help out the ODBC driver.</li> <li>Bug fix: "SELECT count(*)" was returning NULL for empty tables. Now it returns 0.</li> } |
︙ | ︙ |