Compare commits

...

3 Commits

Author SHA1 Message Date
shaneh e2db2b1978 Update maxRow size after shrinking the row buffer (CSV).
FossilOrigin-Name: d474195a997b9d94bea8976738c942662f7c4751
2009-11-05 04:14:30 +00:00
shaneh 7e57ba9016 Removed line limit on rows.
FossilOrigin-Name: ec08b15f77741efd38dadd6aff492ccbb841471e
2009-11-05 04:01:04 +00:00
shaneh 520bcc1170 Initial implementation of a virtual table for CSV files.
FossilOrigin-Name: 90e63b7d845bacc9a1a1db13c1e9a406e5306faa
2009-11-05 02:34:42 +00:00
10 changed files with 998 additions and 19 deletions
+670
View File
@@ -0,0 +1,670 @@
/*
** 2009 March 26
**
** 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 contains code for implementations of the CSV
** algorithms packaged as an SQLite virtual table module.
*/
#if defined(_WIN32) || defined(WIN32)
/* This needs to come before any includes for MSVC compiler */
#define _CRT_SECURE_NO_WARNINGS
#endif
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_CSV)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef SQLITE_CORE
#include "sqlite3ext.h"
SQLITE_EXTENSION_INIT1
#else
#include "sqlite3.h"
#endif
#define UNUSED_PARAMETER(x) (void)(x)
/*
** The CSV virtual-table types.
*/
typedef struct CSV CSV;
typedef struct CSVCursor CSVCursor;
/*
** An CSV virtual-table object.
*/
struct CSV {
sqlite3_vtab base; /* Must be first */
sqlite3 *db; /* Host database connection */
char *zDb; /* Name of database containing CSV table */
char *zName; /* Name of CSV table */
char *zFile; /* Name of CSV file */
int nBusy; /* Current number of users of this structure */
FILE *f; /* File pointer for source CSV file */
long offsetFirstRow; /* ftell position of first row */
int eof; /* True when at end of file */
int maxRow; /* Size of zRow buffer */
char *zRow; /* Buffer for current CSV row */
char cDelim; /* Character to use for delimiting columns */
int nCol; /* Number of columns in current row */
int maxCol; /* Size of aCols array */
char **aCols; /* Array of parsed columns */
};
/*
** An CSV cursor object.
*/
struct CSVCursor {
sqlite3_vtab_cursor base; /* Must be first */
long csvpos; /* ftell position of current zRow */
};
/*
** Forward declarations.
*/
static int csvNext( sqlite3_vtab_cursor* pVtabCursor );
static int csvInit(
sqlite3 *db, /* Database connection */
void *pAux, /* Unused */
int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */
sqlite3_vtab **ppVtab, /* OUT: New virtual table */
char **pzErr, /* OUT: Error message, if any */
int isCreate /* True for xCreate, false for xConnect */
);
static void csvReference( CSV *pCSV );
static int csvRelease( CSV *pCSV );
/*
** Abstract out file io routines for porting
*/
static FILE *csv_open( CSV *pCSV ){
return fopen( pCSV->zFile, "rb" );
}
static void csv_close( CSV *pCSV ){
if( pCSV->f ) fclose( pCSV->f );
}
static int csv_seek( CSV *pCSV, long pos ){
return fseek( pCSV->f, pos, SEEK_SET );
}
static long csv_tell( CSV *pCSV ){
return ftell( pCSV->f );
}
/*
** This routine reads a line of text from FILE in, stores
** the text in memory obtained from malloc() and returns a pointer
** to the text. NULL is returned at end of file, or if malloc()
** fails.
**
** The interface is like "readline" but no command-line editing
** is done.
**
** This code was modified from existing code in shell.c of the sqlite3 CLI.
*/
static char *csv_getline( CSV *pCSV ){
int n = 0;
int bEol = 0;
int bShrink = 0;
/* allocate initial row buffer */
if( pCSV->maxRow < 1 ){
pCSV->zRow = sqlite3_malloc( 100 );
if( pCSV->zRow ){
pCSV->maxRow = 100;
}
}
if( !pCSV->zRow ) return 0;
/* read until eol */
while( !bEol ){
/* grow row buffer as needed */
if( n+100>pCSV->maxRow ){
int newSize = pCSV->maxRow*2 + 100;
char *p = sqlite3_realloc(pCSV->zRow, newSize);
if( !p ) return 0;
pCSV->maxRow = newSize;
pCSV->zRow = p;
bShrink = -1;
}
if( fgets(&pCSV->zRow[n], pCSV->maxRow-n, pCSV->f)==0 ){
if( n==0 ){
break;
}
pCSV->zRow[n] = '\0';
bEol = -1;
break;
}
/* look for line delimiter */
while( pCSV->zRow[n] ){ n++; }
if( (n>0) && ((pCSV->zRow[n-1]=='\n') || (pCSV->zRow[n-1]=='\r')) ){
pCSV->zRow[n-1] = '\n'; /* uniform line ending */
pCSV->zRow[n] = '\0';
bEol = -1;
}
}
if( bShrink ){
pCSV->zRow = realloc( pCSV->zRow, n+1 );
pCSV->maxRow = n+1;
}
return bEol ? pCSV->zRow : 0;
}
/*
** CSV virtual table module xCreate method.
*/
static int csvCreate(
sqlite3* db,
void *pAux,
int argc,
const char *const *argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
return csvInit( db, pAux, argc, argv, ppVtab, pzErr, 1 );
}
/*
** CSV virtual table module xConnect method.
*/
static int csvConnect(
sqlite3 *db,
void *pAux,
int argc, const char *const*argv,
sqlite3_vtab **ppVtab,
char **pzErr
){
return csvInit(db, pAux, argc, argv, ppVtab, pzErr, 0);
}
/*
** CSV virtual table module xBestIndex method.
*/
static int csvBestIndex( sqlite3_vtab *pVtab, sqlite3_index_info* info )
{
UNUSED_PARAMETER(pVtab);
UNUSED_PARAMETER(info);
/* TBD */
return SQLITE_OK;
}
/*
** CSV virtual table module xDisconnect method.
*/
static int csvDisconnect( sqlite3_vtab *pVtab ){
return csvRelease( (CSV *)pVtab );
}
/*
** CSV virtual table module xDestroy method.
*/
static int csvDestroy( sqlite3_vtab *pVtab ){
return csvDisconnect( pVtab );
}
/*
** CSV virtual table module xOpen method.
*/
static int csvOpen( sqlite3_vtab *pVtab, sqlite3_vtab_cursor **ppVtabCursor ){
int rc = SQLITE_NOMEM;
CSVCursor *pCsr;
/* create a new cursor object */
pCsr = (CSVCursor *)sqlite3_malloc(sizeof(CSVCursor));
if( pCsr ){
memset(pCsr, 0, sizeof(CSVCursor));
pCsr->base.pVtab = pVtab;
rc = SQLITE_OK;
}
*ppVtabCursor = (sqlite3_vtab_cursor *)pCsr;
return rc;
}
/*
** CSV virtual table module xClose method.
*/
static int csvClose( sqlite3_vtab_cursor *pVtabCursor ){
CSVCursor *pCsr = (CSVCursor *)pVtabCursor;
sqlite3_free(pCsr);
return SQLITE_OK;
}
/*
** CSV virtual table module xFilter method.
*/
static int csvFilter(
sqlite3_vtab_cursor *pVtabCursor,
int idxNum, const char *idxStr,
int argc, sqlite3_value **argv
){
CSV *pCSV = (CSV *)pVtabCursor->pVtab;
int rc;
UNUSED_PARAMETER(idxNum);
UNUSED_PARAMETER(idxStr);
UNUSED_PARAMETER(argc);
UNUSED_PARAMETER(argv);
csvReference( pCSV );
/* seek back to start of first zRow */
pCSV->eof = 0;
csv_seek( pCSV, pCSV->offsetFirstRow );
/* read and parse next line */
rc = csvNext( pVtabCursor );
csvRelease( pCSV );
return rc;
}
/*
** CSV virtual table module xNext method.
*/
static int csvNext( sqlite3_vtab_cursor* pVtabCursor ){
CSV *pCSV = (CSV *)pVtabCursor->pVtab;
CSVCursor *pCsr = (CSVCursor *)pVtabCursor;
int nCol = 0;
char *s;
char zDelims[3] = ",\n";
char cDelim; /* char that delimited current col */
if( pCSV->eof ){
return SQLITE_ERROR;
}
/* update the cursor */
pCsr->csvpos = csv_tell( pCSV );
/* read the next row of data */
s = csv_getline( pCSV );
if( !s ){
/* and error or eof occured */
pCSV->eof = -1;
return SQLITE_OK;
}
/* allocate initial space for the column pointers */
if( pCSV->maxCol < 1 ){
/* take a guess */
int maxCol = (int)(strlen(pCSV->zRow) / 5 + 1);
pCSV->aCols = (char **)sqlite3_malloc( sizeof(char*) * maxCol );
if( pCSV->aCols ){
pCSV->maxCol = maxCol;
}
}
if( !pCSV->aCols ) return SQLITE_NOMEM;
/* add custom delim character */
zDelims[0] = pCSV->cDelim;
/* parse the zRow into individual columns */
do{
/* if it begins with a quote, assume it's a quoted col */
if( *s=='\"' ){
s++; /* skip quote */
pCSV->aCols[nCol] = s; /* save pointer for this col */
/* TBD: handle escaped quotes "" */
/* find closing quote */
s = strchr(s, '\"');
if( !s ){
/* no closing quote */
pCSV->eof = -1;
return SQLITE_ERROR;
}
*s = '\0'; /* null terminate this col */
/* fall through and look for following ",\n" */
s++;
}else{
pCSV->aCols[nCol] = s; /* save pointer for this col */
}
s = strpbrk(s, zDelims);
if( !s ){
/* no col delimiter */
pCSV->eof = -1;
return SQLITE_ERROR;
}
cDelim = *s;
/* null terminate the column by overwriting the delimiter */
*s = '\0';
nCol++;
/* if end of zRow, stop parsing cols */
if( cDelim == '\n' ) break;
/* move to start of next col */
s++; /* skip delimiter */
if(nCol >= pCSV->maxCol ){
/* we need to grow our col pointer array */
char **p = (char **)sqlite3_realloc( pCSV->aCols, sizeof(char*) * (nCol+5) );
if( !p ){
/* out of memory */
return SQLITE_ERROR;
}
pCSV->maxCol = nCol + 5;
pCSV->aCols = p;
}
}while( *s );
pCSV->nCol = nCol;
return SQLITE_OK;
}
/*
** CSV virtual table module xEof method.
**
** Return non-zero if the cursor does not currently point to a valid
** record (i.e if the scan has finished), or zero otherwise.
*/
static int csvEof( sqlite3_vtab_cursor *pVtabCursor )
{
CSV *pCSV = (CSV *)pVtabCursor->pVtab;
return pCSV->eof;
}
/*
** CSV virtual table module xColumn method.
*/
static int csvColumn(sqlite3_vtab_cursor *pVtabCursor, sqlite3_context *ctx, int i){
CSV *pCSV = (CSV *)pVtabCursor->pVtab;
if( i<0 || i>=pCSV->nCol ){
sqlite3_result_null( ctx );
}else{
char *col = pCSV->aCols[i];
if( !col ){
sqlite3_result_null( ctx );
}else{
sqlite3_result_text( ctx, col, -1, SQLITE_TRANSIENT );
}
}
return SQLITE_OK;
}
/*
** CSV virtual table module xRowid method.
** We probably should store a hidden table
** mapping rowid's to csvpos.
*/
static int csvRowid( sqlite3_vtab_cursor* pVtabCursor, sqlite3_int64 *pRowid ){
CSVCursor *pCsr = (CSVCursor *)pVtabCursor;
*pRowid = pCsr->csvpos;
return SQLITE_OK;
}
static sqlite3_module csvModule = {
0, /* iVersion */
csvCreate, /* xCreate - create a table */
csvConnect, /* xConnect - connect to an existing table */
csvBestIndex, /* xBestIndex - Determine search strategy */
csvDisconnect, /* xDisconnect - Disconnect from a table */
csvDestroy, /* xDestroy - Drop a table */
csvOpen, /* xOpen - open a cursor */
csvClose, /* xClose - close a cursor */
csvFilter, /* xFilter - configure scan constraints */
csvNext, /* xNext - advance a cursor */
csvEof, /* xEof */
csvColumn, /* xColumn - read data */
csvRowid, /* xRowid - read data */
0, /* xUpdate - write data */
0, /* xBegin - begin transaction */
0, /* xSync - sync transaction */
0, /* xCommit - commit transaction */
0, /* xRollback - rollback transaction */
0, /* xFindFunction - function overloading */
0 /* xRename - rename the table */
};
/*
** Increment the CSV reference count.
*/
static void csvReference( CSV *pCSV ){
pCSV->nBusy++;
}
/*
** Decrement the CSV reference count. When the reference count reaches
** zero the structure is deleted.
*/
static int csvRelease( CSV *pCSV ){
pCSV->nBusy--;
if( pCSV->nBusy<1 ){
/* finalize any prepared statements here */
csv_close( pCSV );
if( pCSV->zRow ) sqlite3_free( pCSV->zRow );
if( pCSV->aCols ) sqlite3_free( pCSV->aCols );
sqlite3_free( pCSV );
}
return 0;
}
/*
** This function is the implementation of both the xConnect and xCreate
** methods of the CSV virtual table.
**
** argv[0] -> module name
** argv[1] -> database name
** argv[2] -> table name
** argv[3] -> csv file name
** argv[4] -> custom delimiter
** argv[5] -> optional: use header row for column names
*/
static int csvInit(
sqlite3 *db, /* Database connection */
void *pAux, /* Unused */
int argc, const char *const*argv, /* Parameters to CREATE TABLE statement */
sqlite3_vtab **ppVtab, /* OUT: New virtual table */
char **pzErr, /* OUT: Error message, if any */
int isCreate /* True for xCreate, false for xConnect */
){
int rc = SQLITE_OK;
int i;
CSV *pCSV;
char *zSql;
char cDelim = ','; /* Default col delimiter */
int bUseHeaderRow = 0; /* Default to not use zRow headers */
size_t nDb; /* Length of string argv[1] */
size_t nName; /* Length of string argv[2] */
size_t nFile; /* Length of string argv[3] */
CSVCursor csvCsr; /* Used for calling csvNext */
const char *aErrMsg[] = {
0, /* 0 */
"No CSV file specified", /* 1 */
"Error opening CSV file: '%s'", /* 2 */
"No columns found", /* 3 */
"No column name found", /* 4 */
"Out of memory", /* 5 */
};
UNUSED_PARAMETER(pAux);
UNUSED_PARAMETER(isCreate);
if( argc < 4 ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[1]);
return SQLITE_ERROR;
}
/* allocate space for the virtual table object */
nDb = strlen(argv[1]);
nName = strlen(argv[2]);
nFile = strlen(argv[3]);
pCSV = (CSV *)sqlite3_malloc( (int)(sizeof(CSV)+nDb+nName+nFile+3) );
if( !pCSV ){
/* out of memory */
*pzErr = sqlite3_mprintf("%s", aErrMsg[5]);
return SQLITE_NOMEM;
}
/* intialize virtual table object */
memset(pCSV, 0, sizeof(CSV)+nDb+nName+nFile+3);
pCSV->nBusy = 1;
pCSV->base.pModule = &csvModule;
pCSV->cDelim = cDelim;
pCSV->zDb = (char *)&pCSV[1];
pCSV->zName = &pCSV->zDb[nDb+1];
pCSV->zFile = &pCSV->zName[nName+1];
memcpy(pCSV->zDb, argv[1], nDb);
memcpy(pCSV->zName, argv[2], nName);
/* pull out name of csv file (remove quotes) */
if( argv[3][0] == '\'' ){
memcpy( pCSV->zFile, argv[3]+1, nFile-2 );
pCSV->zFile[nFile-2] = '\0';
}else{
memcpy( pCSV->zFile, argv[3], nFile );
}
/* if a custom delimiter specified, pull it out */
if( argc > 4 ){
if( argv[4][0] == '\'' ){
pCSV->cDelim = argv[4][1];
}else{
pCSV->cDelim = argv[4][0];
}
}
/* should the header zRow be used */
if( argc > 5 ){
if( !strcmp(argv[5], "USE_HEADER_ROW") ){
bUseHeaderRow = -1;
}
}
/* open the source csv file */
pCSV->f = csv_open( pCSV );
if( !pCSV->f ){
*pzErr = sqlite3_mprintf(aErrMsg[2], pCSV->zFile);
csvRelease( pCSV );
return SQLITE_ERROR;
}
/* Read first zRow to obtain column names/number */
csvCsr.base.pVtab = (sqlite3_vtab *)pCSV;
rc = csvNext( (sqlite3_vtab_cursor *)&csvCsr );
if( (SQLITE_OK!=rc) || (pCSV->nCol<=0) ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[3]);
csvRelease( pCSV );
return SQLITE_ERROR;
}
if( bUseHeaderRow ){
pCSV->offsetFirstRow = csv_tell( pCSV );
}
/* Create the underlying relational database schema. If
** that is successful, call sqlite3_declare_vtab() to configure
** the csv table schema.
*/
zSql = sqlite3_mprintf("CREATE TABLE x(");
for(i=0; zSql && i<pCSV->nCol; i++){
const char *zTail = (i+1<pCSV->nCol) ? ", " : ");";
char *zTmp = zSql;
if( bUseHeaderRow ){
const char *zCol = pCSV->aCols[i];
if( !zCol ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[4]);
sqlite3_free(zSql);
csvRelease( pCSV );
return SQLITE_ERROR;
}
zSql = sqlite3_mprintf("%s%s%s", zTmp, zCol, zTail);
}else{
zSql = sqlite3_mprintf("%scol%d%s", zTmp, i+1, zTail);
}
sqlite3_free(zTmp);
}
if( !zSql ){
*pzErr = sqlite3_mprintf("%s", aErrMsg[5]);
csvRelease( pCSV );
return SQLITE_NOMEM;
}
rc = sqlite3_declare_vtab( db, zSql );
sqlite3_free(zSql);
if( SQLITE_OK != rc ){
*pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db));
csvRelease( pCSV );
return SQLITE_ERROR;
}
*ppVtab = (sqlite3_vtab *)pCSV;
*pzErr = NULL;
return SQLITE_OK;
}
/*
** Register the CSV module with database handle db. This creates the
** virtual table module "csv".
*/
int sqlite3CsvInit(sqlite3 *db){
int rc = SQLITE_OK;
if( rc==SQLITE_OK ){
void *c = (void *)NULL;
rc = sqlite3_create_module_v2(db, "csv", &csvModule, c, 0);
}
return rc;
}
#if !SQLITE_CORE
/*
** Support auto-extension loading.
*/
int sqlite3_extension_init(
sqlite3 *db,
char **pzErrMsg,
const sqlite3_api_routines *pApi
){
SQLITE_EXTENSION_INIT2(pApi)
return sqlite3CsvInit(db);
}
#endif
#endif
+28
View File
@@ -0,0 +1,28 @@
/*
** 2009 March 26
**
** 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 header file is used by programs that want to link against the
** CSV Virtual Table extention.
**
** All it does is declare the sqlite3CsvInit() interface.
*/
#include "sqlite3.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int sqlite3CsvInit(sqlite3 *db);
#ifdef __cplusplus
} /* extern "C" */
#endif /* __cplusplus */
+253
View File
@@ -0,0 +1,253 @@
# 2009 Nov 11
#
# 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.
#
#***********************************************************************
#
# The focus of this file is testing the csv extension.
#
# $Id: csv1.test,v 1.7 2009/07/17 16:54:48 shaneh Exp $
#
if {![info exists testdir]} {
set testdir [file join [file dirname $argv0] .. .. test]
}
source $testdir/tester.tcl
# Test plan:
#
# csv-1.*: Creating/destroying csv tables.
# csv-2.*: Linear scans of csv data.
# csv-3.*: Test renaming an csv table.
# csv-4.*: CREATE errors
#
ifcapable !csv {
finish_test
return
}
# This file is delimited by ',' and has quoted fields.
set test1csv [file join [file dirname [info script]] test1.csv]
# This file is delimited by '|' and has quoted fields.
set test2csv [file join [file dirname [info script]] test2.csv]
# This file is delimited by '|'. It does NOT have quoted fields.
set test3csv [file join [file dirname [info script]] test3.csv]
#----------------------------------------------------------------------------
# Test cases csv-1.* test CREATE and DROP table statements.
#
# Test creating and dropping an csv table with a header row.
#
do_test csv-1.1.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test1csv', ',', USE_HEADER_ROW) "
} {}
do_test csv-1.1.2 {
execsql { SELECT name FROM sqlite_master ORDER BY name }
} {t1}
do_test csv-1.1.3 {
execsql {
DROP TABLE t1;
SELECT name FROM sqlite_master ORDER BY name;
}
} {}
# Test creating and dropping an csv table without a header row.
#
do_test csv-1.2.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test1csv', ',') "
} {}
do_test csv-1.2.2 {
execsql { SELECT name FROM sqlite_master ORDER BY name }
} {t1}
do_test csv-1.2.3 {
execsql {
DROP TABLE t1;
SELECT name FROM sqlite_master ORDER BY name;
}
} {}
# Test creating and dropping an csv table without a header row
# and with the default delimiter ','.
#
do_test csv-1.3.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test1csv') "
} {}
do_test csv-1.3.2 {
execsql { SELECT name FROM sqlite_master ORDER BY name }
} {t1}
do_test csv-1.3.3 {
execsql {
DROP TABLE t1;
SELECT name FROM sqlite_master ORDER BY name;
}
} {}
# Test creating and dropping an csv table without a header row
# and with the custom delimiter '|'.
#
do_test csv-1.4.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test2csv', '|') "
} {}
do_test csv-1.4.2 {
execsql { SELECT name FROM sqlite_master ORDER BY name }
} {t1}
do_test csv-1.4.3 {
execsql {
DROP TABLE t1;
SELECT name FROM sqlite_master ORDER BY name;
}
} {}
#----------------------------------------------------------------------------
# Test cases csv-2.* test linear scans of csv table data.
#
do_test csv-2.1.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test1csv', ',', USE_HEADER_ROW) "
} {}
do_test csv-2.1.2 {
execsql {
SELECT * FROM t1;
}
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-2.1.3 {
execsql {
SELECT * FROM t1 WHERE colA='a';
}
} {a b c a b c a b {c .. z} a b c,d}
do_test csv-2.2.1 {
execsql " CREATE VIRTUAL TABLE t2 USING csv('$test1csv', ',') "
} {}
do_test csv-2.2.2 {
execsql {
SELECT * FROM t2;
}
} {colA colB colC 1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-2.2.3 {
execsql {
SELECT * FROM t2 WHERE col1='a';
}
} {a b c a b c a b {c .. z} a b c,d}
# Test scanning with the custom delimiter '|'.
#
do_test csv-2.3.1 {
execsql " CREATE VIRTUAL TABLE t3 USING csv('$test2csv', '|') "
} {}
do_test csv-2.3.2 {
execsql {
SELECT * FROM t3;
}
} {colA colB colC 1 2 3 a b c a b c a b {c .. z} a b c|d}
do_test csv-2.3.3 {
execsql {
SELECT * FROM t3 WHERE col1='a';
}
} {a b c a b c a b {c .. z} a b c|d}
# Test scanning with the custom delimiter ';'. The test file
# uses | for a delimiter, so everything should be treated as
# a single column.
#
do_test csv-2.4.1 {
execsql " CREATE VIRTUAL TABLE t4 USING csv('$test3csv', ';') "
} {}
do_test csv-2.4.2 {
execsql {
SELECT * FROM t4;
}
} {colA|colB|colC 1|2|3 a|b|c {a|b|c .. z} a|b|c|d}
do_test csv-2.4.3 {
execsql {
SELECT * FROM t4 WHERE col1 LIKE 'a%';
}
} {a|b|c {a|b|c .. z} a|b|c|d}
# Test rowid column.
#
do_test csv-2.5.1 {
execsql {
SELECT rowid FROM t1;
}
} {21 27 33 41 58}
do_test csv-2.5.2 {
execsql {
SELECT rowid FROM t1 WHERE colA='a';
}
} {27 33 41 58}
# Clean-up.
#
do_test csv-2.6.1 {
execsql {
DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE t4;
}
} {}
#----------------------------------------------------------------------------
# Test cases csv-3.* test rename operations.
#
do_test csv-3.1.1 {
execsql " CREATE VIRTUAL TABLE t1 USING csv('$test1csv', ',', USE_HEADER_ROW) "
execsql " CREATE VIRTUAL TABLE t2 USING csv('$test1csv', ',', USE_HEADER_ROW) "
} {}
do_test csv-3.1.2 {
catchsql { ALTER TABLE t2 RENAME TO t1 }
} {1 {there is already another table or index with this name: t1}}
do_test csv-3.1.3 {
execsql {
DROP TABLE t1;
ALTER TABLE t2 RENAME TO t1
}
} {}
do_test csv-3.1.4 {
execsql { ALTER TABLE t1 RENAME TO t5 }
execsql { SELECT * FROM t5 }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-3.1.5 {
db close
sqlite3 db test.db
execsql { SELECT * FROM t5 }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-3.1.6 {
execsql { ALTER TABLE t5 RENAME TO 'raisara "one"'''}
execsql { SELECT * FROM "raisara ""one""'" }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-3.1.7 {
execsql { SELECT * FROM 'raisara "one"''' }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-3.1.8 {
execsql { ALTER TABLE "raisara ""one""'" RENAME TO "abc 123" }
execsql { SELECT * FROM "abc 123" }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
do_test csv-3.1.9 {
db close
sqlite3 db test.db
execsql { SELECT * FROM "abc 123" }
} {1 2 3 a b c a b c a b {c .. z} a b c,d}
#----------------------------------------------------------------------------
# Test cases csv-4.* test CREATE errors
#
# Test creating and dropping an csv table with a header row.
#
do_test csv-4.1.1 {
catchsql " CREATE VIRTUAL TABLE t1 USING csv() "
} {1 {No CSV file specified}}
do_test csv-4.1.2 {
catchsql " CREATE VIRTUAL TABLE t1 USING csv('foo') "
} {1 {Error opening CSV file: 'foo'}}
do_test csv-4.1.3 {
catchsql " CREATE VIRTUAL TABLE t1 USING csv(foo foo) "
} {1 {Error opening CSV file: 'foo foo'}}
+6
View File
@@ -0,0 +1,6 @@
"colA","colB","colC"
1,2,3
a,b,c
a,"b",c
"a","b","c .. z"
"a","b","c,d"
1 colA colB colC
2 1 2 3
3 a b c
4 a b c
5 a b c .. z
6 a b c,d
+6
View File
@@ -0,0 +1,6 @@
"colA"|"colB"|"colC"
1|2|3
a|b|c
a|"b"|c
"a"|"b"|"c .. z"
"a"|"b"|"c|d"
1 colA colB colC
2 1 2 3
3 a b c
4 a b c
5 a b c .. z
6 a b c|d
+5
View File
@@ -0,0 +1,5 @@
colA|colB|colC
1|2|3
a|b|c
a|b|c .. z
a|b|c|d
1 colA|colB|colC
2 1|2|3
3 a|b|c
4 a|b|c .. z
5 a|b|c|d
+14 -18
View File
@@ -1,8 +1,5 @@
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
C Remove\s"const"\sfrom\sparameter\sof\ssqlite3BtreeFactory()\sto\savoid\sa\scompiler\nwarning.
D 2009-11-04T13:30:02
C Update\smaxRow\ssize\safter\sshrinking\sthe\srow\sbuffer\s(CSV).
D 2009-11-05T04:14:30
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in a77dfde96ad86aafd3f71651a4333a104debe86a
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
@@ -30,6 +27,12 @@ F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
F ext/async/README.txt 0c541f418b14b415212264cbaaf51c924ec62e5b
F ext/async/sqlite3async.c 3d5396cd69851f5633ef29c7491ca9249eac903a
F ext/async/sqlite3async.h a21e1252deb14a2c211f0e165c4b9122a8f1f344
F ext/csv/csv.c c2b193b98394970c6e5fc8b2a9dd3d80114c5703
F ext/csv/csv.h 9d200dd0511a41f22561d3100cd3cc924818c04a
F ext/csv/csv1.test 822780d05036796c3f2ff4432b5451fe47ae3355
F ext/csv/test1.csv 888555e2a197fecaf9d0b90133551ebb8cbac8ce
F ext/csv/test2.csv 04c9f79ff9edd3f9fa4a332524d7b651b968bf8b
F ext/csv/test3.csv 4d0a88e552374c2d3f57bec1c4fe3b0fbd37a362
F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e
F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b
F ext/fts1/ft_hash.h 1a35e654a235c2c662d3ca0dfc3138ad60b8b7d5
@@ -130,7 +133,7 @@ F src/journal.c e00df0c0da8413ab6e1bb7d7cab5665d4a9000d0
F src/legacy.c 303b4ffcf1ae652fcf5ef635846c563c254564f6
F src/lempar.c 7f026423f4d71d989e719a743f98a1cbd4e6d99e
F src/loadext.c 0e88a335665db0b2fb4cece3e49dcb65d832635a
F src/main.c aae32d5af35b88faff0664e0f937ee7133d77c8d
F src/main.c 3f99627e8e3014eb38d95ca7e00e56a2dd95f687
F src/malloc.c 685561d2f1602042e349aea5d7a88c3f10a63454
F src/mem0.c f2f84062d1f35814d6535c9f9e33de3bfb3b132c
F src/mem1.c e6d5c23941288df8191b8a98c28e3f57771e2270
@@ -185,7 +188,7 @@ F src/test_async.c 731d23f953ece5bf40ce87810cfb7607218953c5
F src/test_autoext.c f53b0cdf7bf5f08100009572a5d65cdb540bd0ad
F src/test_backup.c 1384a18985a5a2d275c2662e48473bf1542ebd08
F src/test_btree.c 5adbba9b138988a3cf4d3b5424dbc7c85651da02
F src/test_config.c 4ac1e6257dcf926a71b7934410b71c5c326e68f2
F src/test_config.c cc5c8cfdb2ce128ff61c8546db51c0169b45dd50
F src/test_devsym.c 9f4bc2551e267ce7aeda195f3897d0f30c5228f4
F src/test_func.c c6e9d7cfbd7bb0bd7c392a10d76adab4b48e813b
F src/test_hexio.c 2f1122aa3f012fa0142ee3c36ce5c902a70cd12f
@@ -764,14 +767,7 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
P 24a4d520d540d92b611abc4eb57dc6da9be4eac6
R a2178242a921307d19fbc8b7d2eec4f0
U drh
Z a8d4aa9309aed4b69860cd88128a4708
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
iD8DBQFK8YHdoxKgR168RlERAs0DAJ447A8mNmnCD0zy/gACLgqIHsmF8QCfYMHu
do95dSeuDXCMLnSZQtGGeQE=
=FnZg
-----END PGP SIGNATURE-----
P ec08b15f77741efd38dadd6aff492ccbb841471e
R bbd4a60a692322be9ab3321f8859c300
U shaneh
Z 68d17772bddd2ba999f9cce39f7958ee
+1 -1
View File
@@ -1 +1 @@
eb7a544fe49d1626bacecfe53ddc03fe082e3243
d474195a997b9d94bea8976738c942662f7c4751
+9
View File
@@ -25,6 +25,9 @@
#ifdef SQLITE_ENABLE_ICU
# include "sqliteicu.h"
#endif
#ifdef SQLITE_ENABLE_CSV
# include "csv.h"
#endif
/*
** The version of the library
@@ -1715,6 +1718,12 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_CSV
if( !db->mallocFailed && rc==SQLITE_OK){
rc = sqlite3CsvInit(db);
}
#endif
sqlite3Error(db, rc, 0);
/* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking
+6
View File
@@ -384,6 +384,12 @@ Tcl_SetVar2(interp, "sqlite_options", "long_double",
Tcl_SetVar2(interp, "sqlite_options", "rtree", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_CSV
Tcl_SetVar2(interp, "sqlite_options", "csv", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "csv", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_SCHEMA_PRAGMAS
Tcl_SetVar2(interp, "sqlite_options", "schema_pragmas", "0", TCL_GLOBAL_ONLY);
#else