SQLite

Check-in [d7551df8c3]
Login

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

Overview
Comment:Add a couple of tests for UTF-16 databases. (CVS 1438)
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: d7551df8c32c4981d94eb57cd2a999592e91f50f
User & Date: danielk1977 2004-05-22 10:33:03.000
Original User & Date: danielk1977 2004-05-22 10:33:04.000
Context
2004-05-22
10:33
Add a couple of tests for UTF-16 databases. (CVS 1439) (check-in: 891be63a92 user: danielk1977 tags: trunk)
10:33
Add a couple of tests for UTF-16 databases. (CVS 1438) (check-in: d7551df8c3 user: danielk1977 tags: trunk)
09:21
Use the new form of the sqlite3_open() API everywhere. (CVS 1437) (check-in: b449217318 user: danielk1977 tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/sqlite.h.in.
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 header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.69 2004/05/22 09:21:21 danielk1977 Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.







|







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 header file defines the interface that the SQLite library
** presents to client programs.
**
** @(#) $Id: sqlite.h.in,v 1.70 2004/05/22 10:33:04 danielk1977 Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** Make sure we can call this stuff from C++.
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302












1303
1304
1305
1306
1307
1308
1309
** SQLITE3_BLOB      A pointer to the blob of data.
*/
const void *sqlite3_column_data16(sqlite3_stmt*,int);

/*
** The first parameter is a compiled SQL statement for which the most
** recent call to sqlite3_step() has returned SQLITE_ROW. This routine
** retrieves the length of the data in bytse returned by the
** sqlite3_column_data() routine for the same second parameter value.
**
** If sqlite3_column_data() returns a UTF-8 string, then the length
** returned by this function includes the nul terminator character at the
** end of the UTF-8 string.
*/
int sqlite3_column_bytes(sqlite3_stmt*,int);













/*
** The first parameter is a compiled SQL statement for which the most
** recent call to sqlite3_step() has returned SQLITE_ROW. This routine
** retrieves the value of the Nth column of the current row, where
** N is the second function parameter as an integer.
**
** SQLITE3_NULL      0







|








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







1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
** SQLITE3_BLOB      A pointer to the blob of data.
*/
const void *sqlite3_column_data16(sqlite3_stmt*,int);

/*
** The first parameter is a compiled SQL statement for which the most
** recent call to sqlite3_step() has returned SQLITE_ROW. This routine
** retrieves the length of the data in bytes returned by the
** sqlite3_column_data() routine for the same second parameter value.
**
** If sqlite3_column_data() returns a UTF-8 string, then the length
** returned by this function includes the nul terminator character at the
** end of the UTF-8 string.
*/
int sqlite3_column_bytes(sqlite3_stmt*,int);

/*
** The first parameter is a compiled SQL statement for which the most
** recent call to sqlite3_step() has returned SQLITE_ROW. This routine
** retrieves the length of the data in bytes returned by the
** sqlite3_column_data() routine for the same second parameter value.
**
** If sqlite3_column_data() returns a UTF-16 string, then the length
** returned by this function includes the nul terminator character (two
** bytes) at the end of the UTF-16 string.
*/
int sqlite3_column_bytes16(sqlite3_stmt *, int);

/*
** The first parameter is a compiled SQL statement for which the most
** recent call to sqlite3_step() has returned SQLITE_ROW. This routine
** retrieves the value of the Nth column of the current row, where
** N is the second function parameter as an integer.
**
** SQLITE3_NULL      0
Changes to src/test1.c.
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.46 2004/05/22 09:21:21 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>








|







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
**    May you share freely, never taking more than you give.
**
*************************************************************************
** Code for testing the printf() interface to SQLite.  This code
** is not included in the SQLite library.  It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.47 2004/05/22 10:33:04 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
#include "os.h"
#include <stdlib.h>
#include <string.h>

1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427






















1428













































1429
1430
1431
1432
1433
1434
1435
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int rc;

  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " STMT", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  rc = sqlite3_step_new(pStmt);























  if( rc!=SQLITE_OK ) return TCL_ERROR;













































  return TCL_OK;
}

/*
** This is a collating function named "REVERSE" which sorts text
** in reverse order.
*/







|








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







1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int rc;

  if( objc!=2 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " STMT", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  rc = sqlite3_step_new(pStmt);

  if( rc!=SQLITE_DONE && rc!=SQLITE_ROW ) return TCL_ERROR;
  return TCL_OK;
}

/*
** Usage: sqlite3_column_data STMT column
**
** Advance the statement to the next row.
*/
static int test_column_data(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int col;
  Tcl_Obj *pRet;

  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " STMT column", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;

  if( SQLITE3_BLOB==sqlite3_column_type(pStmt, col) ){
    int len = sqlite3_column_bytes(pStmt, col);
    pRet = Tcl_NewByteArrayObj(sqlite3_column_data(pStmt, col), len);
  }else{
    pRet = Tcl_NewStringObj(sqlite3_column_data(pStmt, col), -1);
  }
  Tcl_SetObjResult(interp, pRet);

  return TCL_OK;
}

/*
** Usage: sqlite3_column_data16 STMT column
**
** Advance the statement to the next row.
*/
static int test_column_data16(
  void * clientData,
  Tcl_Interp *interp,
  int objc,
  Tcl_Obj *CONST objv[]
){
  sqlite3_stmt *pStmt;
  int col;
  Tcl_Obj *pRet;
  int len;

  if( objc!=3 ){
    Tcl_AppendResult(interp, "wrong # args: should be \"", 
       Tcl_GetString(objv[0]), " STMT column", 0);
    return TCL_ERROR;
  }

  if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
  if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;

  len = sqlite3_column_bytes16(pStmt, col);
  pRet = Tcl_NewByteArrayObj(sqlite3_column_data16(pStmt, col), len);
  Tcl_SetObjResult(interp, pRet);

  return TCL_OK;
}

/*
** This is a collating function named "REVERSE" which sorts text
** in reverse order.
*/
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531


1532
1533
1534
1535
1536
1537
1538
     { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
     { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
     { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
     { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
     { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
     { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
     { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
     { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize     },
     { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset        },
     { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step_new      },


     { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }







|
|

>
>







1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
     { "sqlite3_errcode",               (Tcl_ObjCmdProc*)test_errcode       },
     { "sqlite3_errmsg",                (Tcl_ObjCmdProc*)test_errmsg        },
     { "sqlite3_errmsg16",              (Tcl_ObjCmdProc*)test_errmsg16      },
     { "sqlite3_prepare",               (Tcl_ObjCmdProc*)test_prepare       },
     { "sqlite3_prepare16",             (Tcl_ObjCmdProc*)test_prepare16     },
     { "sqlite3_open",                  (Tcl_ObjCmdProc*)test_open          },
     { "sqlite3_open16",                (Tcl_ObjCmdProc*)test_open16        },
     { "sqlite3_finalize",              (Tcl_ObjCmdProc*)test_finalize      },
     { "sqlite3_reset",                 (Tcl_ObjCmdProc*)test_reset         },
     { "sqlite3_step",                  (Tcl_ObjCmdProc*)test_step_new      },
     { "sqlite3_column_data",           (Tcl_ObjCmdProc*)test_column_data   },
     { "sqlite3_column_data16",         (Tcl_ObjCmdProc*)test_column_data16   },
     { "add_reverse_collating_func",    (Tcl_ObjCmdProc*)reverse_collfunc   },
  };
  int i;

  for(i=0; i<sizeof(aCmd)/sizeof(aCmd[0]); i++){
    Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0);
  }
Changes to src/vdbe.c.
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.317 2004/05/22 07:27:46 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*







|







39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
**
** Various scripts scan this source file in order to generate HTML
** documentation, headers files, or other derived files.  The formatting
** of the code in this file is, therefore, important.  See other comments
** in this file for details.  If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.318 2004/05/22 10:33:04 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
#include <ctype.h>
#include "vdbeInt.h"

/*
65
66
67
68
69
70
71

72
73
74
75
76
77
78
** of the db.flags field is set in order to simulate and interrupt.
**
** This facility is used for testing purposes only.  It does not function
** in an ordinary build.
*/
int sqlite3_interrupt_count = 0;


/*
** NulTermify
** Stringify
** Integerify
** Realify
** SetEncoding
** Release







>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
** of the db.flags field is set in order to simulate and interrupt.
**
** This facility is used for testing purposes only.  It does not function
** in an ordinary build.
*/
int sqlite3_interrupt_count = 0;

#if 0
/*
** NulTermify
** Stringify
** Integerify
** Realify
** SetEncoding
** Release
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
** MemRecord. An Mem cell used to store a MemRecord works as follows:
**
** Mem.z points at a MemRecord struct
*/
static int Recordify(Mem *pMem){
  return 0;
}

#define NulTermify(P) if(((P)->flags & MEM_Str)==0){hardStringify(P);} \
                      else if(((P)->flags & MEM_Term)==0){hardNulTermify(P);}
static int hardNulTermify(Mem *pStack){
  int flags = pStack->flags;

  assert( !(flags&MEM_Term) && (flags&MEM_Str) );
  assert( flags&(MEM_Utf8|MEM_Utf16le|MEM_Utf16be) );

  if( flags&MEM_Utf8 ){
    /* If the string is already dynamically allocated, use sqliteRealloc()
    ** to allocate extra space for the terminator.
    */
    if( flags&MEM_Dyn ){
      pStack->z = sqliteRealloc(pStack->z, pStack->n+1);
      if( !pStack->z ){
        return 1;
      }
    }

    if( flags&(MEM_Static|MEM_Ephem|MEM_Short) ){
      if( pStack->n+1<NBFS ){
        if( flags&MEM_Short ){
          memcpy(pStack->zShort, pStack->z, pStack->n);
          pStack->flags = MEM_Short|MEM_Str|MEM_Utf8|MEM_Term;
        }
      }else{
        char *z = sqliteMalloc(pStack->n+1);
        if( !z ){
          return 1;
        }
        memcpy(z, pStack->z, pStack->n);
        pStack->z = z;
        pStack->flags = MEM_Dyn|MEM_Str|MEM_Utf8|MEM_Term;
      }
    }

    pStack->z[pStack->n] = '\0';
    pStack->n++;
  }else{
    assert(0);
  }

  return 0;
}

/*
** Convert the given stack entity into a string if it isn't one
** already.
*/
#define Stringify(P) if(!((P)->flags&(MEM_Str|MEM_Blob))){hardStringify(P);}
static int hardStringify(Mem *pStack){







|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







91
92
93
94
95
96
97
98












































99
100
101
102
103
104
105
** MemRecord. An Mem cell used to store a MemRecord works as follows:
**
** Mem.z points at a MemRecord struct
*/
static int Recordify(Mem *pMem){
  return 0;
}
#endif













































/*
** Convert the given stack entity into a string if it isn't one
** already.
*/
#define Stringify(P) if(!((P)->flags&(MEM_Str|MEM_Blob))){hardStringify(P);}
static int hardStringify(Mem *pStack){
528
529
530
531
532
533
534
535
536
537
538

539
540
541
542
543
544
545
546
547
























548















549
550
551
552
553
554
555
    SetEncoding(pVal, MEM_Utf8|MEM_Term);
  }

  return pVal->z;
}

/*
** Return the number of bytes of data that will be returned by the
** equivalent sqlite3_column_data() call.
*/
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){

  Vdbe *pVm = (Vdbe *)pStmt;
  int vals;

  vals = sqlite3_value_count(pStmt);
  if( i>=vals || i<0 ){
    sqlite3Error(pVm->db, SQLITE_RANGE, 0);
    return 0;
  }

























  if( sqlite3_column_data(pStmt, i) ){















    return pVm->pTos[(1-vals)+i].n;
  }
  return 0;
}

/*
** Return the value of the 'i'th column of the current row of the currently







|
|

|
>

|







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

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







485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
    SetEncoding(pVal, MEM_Utf8|MEM_Term);
  }

  return pVal->z;
}

/*
** Return the value of the 'i'th column of the current row of the currently
** executing statement pStmt.
*/
const void *sqlite3_column_data16(sqlite3_stmt *pStmt, int i){
  int vals;
  Vdbe *pVm = (Vdbe *)pStmt;
  Mem *pVal;

  vals = sqlite3_value_count(pStmt);
  if( i>=vals || i<0 ){
    sqlite3Error(pVm->db, SQLITE_RANGE, 0);
    return 0;
  }

  pVal = &pVm->pTos[(1-vals)+i];
  if( pVal->flags&MEM_Null ){
    return 0;
  }

  if( !(pVal->flags&MEM_Blob) ){
    Stringify(pVal);
    if( SQLITE3_BIGENDIAN ){
      SetEncoding(pVal, MEM_Utf16be|MEM_Term);
    }else{
      SetEncoding(pVal, MEM_Utf16le|MEM_Term);
    }
  }

  return pVal->z;
}

/*
** Return the number of bytes of data that will be returned by the
** equivalent sqlite3_column_data() call.
*/
int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){
  Vdbe *pVm = (Vdbe *)pStmt;

  if( sqlite3_column_data(pStmt, i) ){
    int vals = sqlite3_value_count(pStmt);
    return pVm->pTos[(1-vals)+i].n;
  }
  return 0;
}

/*
** Return the number of bytes of data that will be returned by the
** equivalent sqlite3_column_data16() call.
*/
int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){
  Vdbe *pVm = (Vdbe *)pStmt;

  if( sqlite3_column_data16(pStmt, i) ){
    int vals = sqlite3_value_count(pStmt);
    return pVm->pTos[(1-vals)+i].n;
  }
  return 0;
}

/*
** Return the value of the 'i'th column of the current row of the currently
Added test/enc2.test.


































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
40
41
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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# 2002 May 24
#
# 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 SQLite routines used for converting between the
# various suported unicode encodings (UTF-8, UTF-16, UTF-16le and
# UTF-16be).
#
# $Id: enc2.test,v 1.1 2004/05/22 10:33:04 danielk1977 Exp $

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

db close

# Return the UTF-8 representation of the supplied UTF-16 string $str. 
proc utf8 {str} {
  # If $str ends in two 0x00 0x00 bytes, knock these off before
  # converting to UTF-8 using TCL.
  binary scan $str \c* vals
  if {[lindex $vals end]==0 && [lindex $vals end-1]==0} {
    set str [binary format \c* [lrange $vals 0 end-2]]
  }

  set r [encoding convertfrom unicode $str]
  return $r
}

#
# This proc contains all the tests in this file. It is run
# three times. Each time the file 'test.db' contains a database
# with the following contents:
set dbcontents {
  CREATE TABLE t1(a PRIMARY KEY, b, c);
  INSERT INTO t1 VALUES('one', 'I', 1);
}
# This proc tests that we can open and manipulate the test.db 
# database, and that it is possible to retreive values in
# various text encodings.
#
proc run_test_script {t} {

# Open the database and pull out a (the) row.
do_test $t.1 {
  set DB [sqlite db test.db]
  execsql {SELECT * FROM t1}
} {one I 1}

# Insert some data
do_test $t.2 {
  execsql {INSERT INTO t1 VALUES('two', 'II', 2);}
  execsql {SELECT * FROM t1}
} {one I 1 two II 2}

# Insert some data using the COPY command.
do_test $t.3 {
  set f [open data.txt w]
  puts $f "three\tIII\t3"
  puts $f "four\tIV\t4"
  puts $f "five\tV\t5"
  close $f
  execsql {COPY t1 FROM 'data.txt'}
  execsql {SELECT * FROM t1}
} {one I 1 two II 2 three III 3 four IV 4 five V 5}

# Use the index
do_test $t.4 {
  execsql {
    SELECT * FROM t1 WHERE a = 'one';
  }
} {one I 1}
do_test $t.5 {
  execsql {
    SELECT * FROM t1 WHERE a = 'four';
  }
} {four IV 4}
do_test $t.6 {
  execsql {
    SELECT * FROM t1 WHERE a IN ('one', 'two');
  }
} {one I 1 two II 2}

# Now check that we can retrieve data in both UTF-16 and UTF-8
do_test $t.7 {
  set STMT [sqlite3_prepare $DB "SELECT a FROM t1 WHERE c>3;" -1 TAIL]
  sqlite3_step $STMT
  sqlite3_column_data $STMT 0
} {four}

do_test $t.8 {
  sqlite3_step $STMT
  utf8 [sqlite3_column_data16 $STMT 0]
} {five}

do_test $t.9 {
  sqlite3_finalize $STMT
} {}

do_test $t.99 {
  db close
} {}

}

# The three unicode encodings understood by SQLite.
set encodings [list -utf8 -utf16be -utf16le]

set i 1
foreach enc $encodings {
  file delete -force test.db
  sqlite db test.db $enc
  execsql $dbcontents
  db close
  run_test_script enc2-$i
  incr i
}

finish_test