1724b1896Sdrh /* 2724b1896Sdrh ** 2016-05-28 3724b1896Sdrh ** 4724b1896Sdrh ** The author disclaims copyright to this source code. In place of 5724b1896Sdrh ** a legal notice, here is a blessing: 6724b1896Sdrh ** 7724b1896Sdrh ** May you do good and not evil. 8724b1896Sdrh ** May you find forgiveness for yourself and forgive others. 9724b1896Sdrh ** May you share freely, never taking more than you give. 10724b1896Sdrh ** 11724b1896Sdrh ****************************************************************************** 12724b1896Sdrh ** 13724b1896Sdrh ** This file contains the implementation of an SQLite virtual table for 14724b1896Sdrh ** reading CSV files. 15724b1896Sdrh ** 16724b1896Sdrh ** Usage: 17724b1896Sdrh ** 18724b1896Sdrh ** .load ./csv 19724b1896Sdrh ** CREATE VIRTUAL TABLE temp.csv USING csv(filename=FILENAME); 20724b1896Sdrh ** SELECT * FROM csv; 21724b1896Sdrh ** 22724b1896Sdrh ** The columns are named "c1", "c2", "c3", ... by default. But the 23724b1896Sdrh ** application can define its own CREATE TABLE statement as an additional 24724b1896Sdrh ** parameter. For example: 25724b1896Sdrh ** 26724b1896Sdrh ** CREATE VIRTUAL TABLE temp.csv2 USING csv( 27724b1896Sdrh ** filename = "../http.log", 28724b1896Sdrh ** schema = "CREATE TABLE x(date,ipaddr,url,referrer,userAgent)" 29724b1896Sdrh ** ); 30ac9c3d2cSdrh ** 31ac9c3d2cSdrh ** Instead of specifying a file, the text of the CSV can be loaded using 32ac9c3d2cSdrh ** the data= parameter. 33ac9c3d2cSdrh ** 34ac9c3d2cSdrh ** If the columns=N parameter is supplied, then the CSV file is assumed to have 35ac9c3d2cSdrh ** N columns. If the columns parameter is omitted, the CSV file is opened 36ac9c3d2cSdrh ** as soon as the virtual table is constructed and the first row of the CSV 37ac9c3d2cSdrh ** is read in order to count the tables. 38ac9c3d2cSdrh ** 39ac9c3d2cSdrh ** Some extra debugging features (used for testing virtual tables) are available 40ac9c3d2cSdrh ** if this module is compiled with -DSQLITE_TEST. 41724b1896Sdrh */ 42724b1896Sdrh #include <sqlite3ext.h> 43724b1896Sdrh SQLITE_EXTENSION_INIT1 44724b1896Sdrh #include <string.h> 45724b1896Sdrh #include <stdlib.h> 46724b1896Sdrh #include <assert.h> 47724b1896Sdrh #include <stdarg.h> 48724b1896Sdrh #include <ctype.h> 49724b1896Sdrh #include <stdio.h> 50724b1896Sdrh 51eb5a549eSdrh #ifndef SQLITE_OMIT_VIRTUALTABLE 52eb5a549eSdrh 53724b1896Sdrh /* 54724b1896Sdrh ** A macro to hint to the compiler that a function should not be 55724b1896Sdrh ** inlined. 56724b1896Sdrh */ 57724b1896Sdrh #if defined(__GNUC__) 58724b1896Sdrh # define CSV_NOINLINE __attribute__((noinline)) 59724b1896Sdrh #elif defined(_MSC_VER) && _MSC_VER>=1310 60724b1896Sdrh # define CSV_NOINLINE __declspec(noinline) 61724b1896Sdrh #else 62724b1896Sdrh # define CSV_NOINLINE 63724b1896Sdrh #endif 64724b1896Sdrh 65724b1896Sdrh 66724b1896Sdrh /* Max size of the error message in a CsvReader */ 67724b1896Sdrh #define CSV_MXERR 200 68724b1896Sdrh 69adcba64dSdrh /* Size of the CsvReader input buffer */ 70adcba64dSdrh #define CSV_INBUFSZ 1024 71adcba64dSdrh 72724b1896Sdrh /* A context object used when read a CSV file. */ 73724b1896Sdrh typedef struct CsvReader CsvReader; 74724b1896Sdrh struct CsvReader { 75724b1896Sdrh FILE *in; /* Read the CSV text from this input stream */ 76724b1896Sdrh char *z; /* Accumulated text for a field */ 77724b1896Sdrh int n; /* Number of bytes in z */ 78724b1896Sdrh int nAlloc; /* Space allocated for z[] */ 79724b1896Sdrh int nLine; /* Current line number */ 80d5fbde80Sdrh int bNotFirst; /* True if prior text has been seen */ 812acd24d9Sdrh int cTerm; /* Character that terminated the most recent field */ 82adcba64dSdrh size_t iIn; /* Next unread character in the input buffer */ 83adcba64dSdrh size_t nIn; /* Number of characters in the input buffer */ 84adcba64dSdrh char *zIn; /* The input buffer */ 85724b1896Sdrh char zErr[CSV_MXERR]; /* Error message */ 86724b1896Sdrh }; 87724b1896Sdrh 88724b1896Sdrh /* Initialize a CsvReader object */ 89724b1896Sdrh static void csv_reader_init(CsvReader *p){ 90adcba64dSdrh p->in = 0; 91adcba64dSdrh p->z = 0; 92adcba64dSdrh p->n = 0; 93adcba64dSdrh p->nAlloc = 0; 94adcba64dSdrh p->nLine = 0; 95d5fbde80Sdrh p->bNotFirst = 0; 96adcba64dSdrh p->nIn = 0; 97adcba64dSdrh p->zIn = 0; 98adcba64dSdrh p->zErr[0] = 0; 99724b1896Sdrh } 100724b1896Sdrh 101724b1896Sdrh /* Close and reset a CsvReader object */ 102724b1896Sdrh static void csv_reader_reset(CsvReader *p){ 103adcba64dSdrh if( p->in ){ 104adcba64dSdrh fclose(p->in); 105adcba64dSdrh sqlite3_free(p->zIn); 106adcba64dSdrh } 107724b1896Sdrh sqlite3_free(p->z); 108724b1896Sdrh csv_reader_init(p); 109724b1896Sdrh } 110724b1896Sdrh 111724b1896Sdrh /* Report an error on a CsvReader */ 112724b1896Sdrh static void csv_errmsg(CsvReader *p, const char *zFormat, ...){ 113724b1896Sdrh va_list ap; 114724b1896Sdrh va_start(ap, zFormat); 115724b1896Sdrh sqlite3_vsnprintf(CSV_MXERR, p->zErr, zFormat, ap); 116724b1896Sdrh va_end(ap); 117724b1896Sdrh } 118724b1896Sdrh 119724b1896Sdrh /* Open the file associated with a CsvReader 120724b1896Sdrh ** Return the number of errors. 121724b1896Sdrh */ 122adcba64dSdrh static int csv_reader_open( 123adcba64dSdrh CsvReader *p, /* The reader to open */ 124adcba64dSdrh const char *zFilename, /* Read from this filename */ 125adcba64dSdrh const char *zData /* ... or use this data */ 126adcba64dSdrh ){ 127adcba64dSdrh if( zFilename ){ 128adcba64dSdrh p->zIn = sqlite3_malloc( CSV_INBUFSZ ); 129adcba64dSdrh if( p->zIn==0 ){ 130adcba64dSdrh csv_errmsg(p, "out of memory"); 131adcba64dSdrh return 1; 132adcba64dSdrh } 133724b1896Sdrh p->in = fopen(zFilename, "rb"); 134724b1896Sdrh if( p->in==0 ){ 1354d3e6140Sdrh sqlite3_free(p->zIn); 136adcba64dSdrh csv_reader_reset(p); 137724b1896Sdrh csv_errmsg(p, "cannot open '%s' for reading", zFilename); 138724b1896Sdrh return 1; 139724b1896Sdrh } 140adcba64dSdrh }else{ 141adcba64dSdrh assert( p->in==0 ); 142adcba64dSdrh p->zIn = (char*)zData; 143adcba64dSdrh p->nIn = strlen(zData); 144adcba64dSdrh } 145724b1896Sdrh return 0; 146724b1896Sdrh } 147724b1896Sdrh 148adcba64dSdrh /* The input buffer has overflowed. Refill the input buffer, then 149adcba64dSdrh ** return the next character 150adcba64dSdrh */ 151adcba64dSdrh static CSV_NOINLINE int csv_getc_refill(CsvReader *p){ 152adcba64dSdrh size_t got; 153adcba64dSdrh 154adcba64dSdrh assert( p->iIn>=p->nIn ); /* Only called on an empty input buffer */ 155adcba64dSdrh assert( p->in!=0 ); /* Only called if reading froma file */ 156adcba64dSdrh 157adcba64dSdrh got = fread(p->zIn, 1, CSV_INBUFSZ, p->in); 158adcba64dSdrh if( got==0 ) return EOF; 159adcba64dSdrh p->nIn = got; 160adcba64dSdrh p->iIn = 1; 161adcba64dSdrh return p->zIn[0]; 162adcba64dSdrh } 163adcba64dSdrh 164adcba64dSdrh /* Return the next character of input. Return EOF at end of input. */ 165adcba64dSdrh static int csv_getc(CsvReader *p){ 166adcba64dSdrh if( p->iIn >= p->nIn ){ 167adcba64dSdrh if( p->in!=0 ) return csv_getc_refill(p); 168adcba64dSdrh return EOF; 169adcba64dSdrh } 1702acd24d9Sdrh return ((unsigned char*)p->zIn)[p->iIn++]; 171adcba64dSdrh } 172adcba64dSdrh 173724b1896Sdrh /* Increase the size of p->z and append character c to the end. 174724b1896Sdrh ** Return 0 on success and non-zero if there is an OOM error */ 175724b1896Sdrh static CSV_NOINLINE int csv_resize_and_append(CsvReader *p, char c){ 176724b1896Sdrh char *zNew; 177724b1896Sdrh int nNew = p->nAlloc*2 + 100; 178724b1896Sdrh zNew = sqlite3_realloc64(p->z, nNew); 179724b1896Sdrh if( zNew ){ 180724b1896Sdrh p->z = zNew; 181724b1896Sdrh p->nAlloc = nNew; 182724b1896Sdrh p->z[p->n++] = c; 183724b1896Sdrh return 0; 184724b1896Sdrh }else{ 185724b1896Sdrh csv_errmsg(p, "out of memory"); 186724b1896Sdrh return 1; 187724b1896Sdrh } 188724b1896Sdrh } 189724b1896Sdrh 190724b1896Sdrh /* Append a single character to the CsvReader.z[] array. 191724b1896Sdrh ** Return 0 on success and non-zero if there is an OOM error */ 192724b1896Sdrh static int csv_append(CsvReader *p, char c){ 193724b1896Sdrh if( p->n>=p->nAlloc-1 ) return csv_resize_and_append(p, c); 194724b1896Sdrh p->z[p->n++] = c; 195724b1896Sdrh return 0; 196724b1896Sdrh } 197724b1896Sdrh 198724b1896Sdrh /* Read a single field of CSV text. Compatible with rfc4180 and extended 199724b1896Sdrh ** with the option of having a separator other than ",". 200724b1896Sdrh ** 201724b1896Sdrh ** + Input comes from p->in. 202724b1896Sdrh ** + Store results in p->z of length p->n. Space to hold p->z comes 203724b1896Sdrh ** from sqlite3_malloc64(). 204724b1896Sdrh ** + Keep track of the line number in p->nLine. 205724b1896Sdrh ** + Store the character that terminates the field in p->cTerm. Store 206724b1896Sdrh ** EOF on end-of-file. 207724b1896Sdrh ** 208*e893e2e4Sdrh ** Return 0 at EOF or on OOM. On EOF, the p->cTerm character will have 209*e893e2e4Sdrh ** been set to EOF. 210724b1896Sdrh */ 211724b1896Sdrh static char *csv_read_one_field(CsvReader *p){ 212724b1896Sdrh int c; 213724b1896Sdrh p->n = 0; 214adcba64dSdrh c = csv_getc(p); 215724b1896Sdrh if( c==EOF ){ 216724b1896Sdrh p->cTerm = EOF; 217*e893e2e4Sdrh return 0; 218724b1896Sdrh } 219724b1896Sdrh if( c=='"' ){ 220724b1896Sdrh int pc, ppc; 221724b1896Sdrh int startLine = p->nLine; 222724b1896Sdrh pc = ppc = 0; 223724b1896Sdrh while( 1 ){ 224adcba64dSdrh c = csv_getc(p); 225ac9c3d2cSdrh if( c<='"' || pc=='"' ){ 226724b1896Sdrh if( c=='\n' ) p->nLine++; 227ac9c3d2cSdrh if( c=='"' ){ 228ac9c3d2cSdrh if( pc=='"' ){ 229724b1896Sdrh pc = 0; 230724b1896Sdrh continue; 231724b1896Sdrh } 232724b1896Sdrh } 233ac9c3d2cSdrh if( (c==',' && pc=='"') 234ac9c3d2cSdrh || (c=='\n' && pc=='"') 235ac9c3d2cSdrh || (c=='\n' && pc=='\r' && ppc=='"') 236ac9c3d2cSdrh || (c==EOF && pc=='"') 237724b1896Sdrh ){ 238ac9c3d2cSdrh do{ p->n--; }while( p->z[p->n]!='"' ); 23980f2b33aSmistachkin p->cTerm = (char)c; 240724b1896Sdrh break; 241724b1896Sdrh } 242ac9c3d2cSdrh if( pc=='"' && c!='\r' ){ 243ac9c3d2cSdrh csv_errmsg(p, "line %d: unescaped %c character", p->nLine, '"'); 244724b1896Sdrh break; 245724b1896Sdrh } 246724b1896Sdrh if( c==EOF ){ 247724b1896Sdrh csv_errmsg(p, "line %d: unterminated %c-quoted field\n", 248ac9c3d2cSdrh startLine, '"'); 24980f2b33aSmistachkin p->cTerm = (char)c; 250724b1896Sdrh break; 251724b1896Sdrh } 252ac9c3d2cSdrh } 253724b1896Sdrh if( csv_append(p, (char)c) ) return 0; 254724b1896Sdrh ppc = pc; 255724b1896Sdrh pc = c; 256724b1896Sdrh } 257724b1896Sdrh }else{ 258d5fbde80Sdrh /* If this is the first field being parsed and it begins with the 259d5fbde80Sdrh ** UTF-8 BOM (0xEF BB BF) then skip the BOM */ 260d5fbde80Sdrh if( (c&0xff)==0xef && p->bNotFirst==0 ){ 2612fb960b5Sdrh csv_append(p, (char)c); 262d5fbde80Sdrh c = csv_getc(p); 263d5fbde80Sdrh if( (c&0xff)==0xbb ){ 2642fb960b5Sdrh csv_append(p, (char)c); 265d5fbde80Sdrh c = csv_getc(p); 266d5fbde80Sdrh if( (c&0xff)==0xbf ){ 267d5fbde80Sdrh p->bNotFirst = 1; 268d5fbde80Sdrh p->n = 0; 269d5fbde80Sdrh return csv_read_one_field(p); 270d5fbde80Sdrh } 271d5fbde80Sdrh } 272d5fbde80Sdrh } 273ac9c3d2cSdrh while( c>',' || (c!=EOF && c!=',' && c!='\n') ){ 274724b1896Sdrh if( csv_append(p, (char)c) ) return 0; 275adcba64dSdrh c = csv_getc(p); 276724b1896Sdrh } 277724b1896Sdrh if( c=='\n' ){ 278724b1896Sdrh p->nLine++; 279724b1896Sdrh if( p->n>0 && p->z[p->n-1]=='\r' ) p->n--; 280724b1896Sdrh } 28180f2b33aSmistachkin p->cTerm = (char)c; 282724b1896Sdrh } 283724b1896Sdrh if( p->z ) p->z[p->n] = 0; 284d5fbde80Sdrh p->bNotFirst = 1; 285724b1896Sdrh return p->z; 286724b1896Sdrh } 287724b1896Sdrh 288724b1896Sdrh 289724b1896Sdrh /* Forward references to the various virtual table methods implemented 290724b1896Sdrh ** in this file. */ 291724b1896Sdrh static int csvtabCreate(sqlite3*, void*, int, const char*const*, 292724b1896Sdrh sqlite3_vtab**,char**); 293724b1896Sdrh static int csvtabConnect(sqlite3*, void*, int, const char*const*, 294724b1896Sdrh sqlite3_vtab**,char**); 295724b1896Sdrh static int csvtabBestIndex(sqlite3_vtab*,sqlite3_index_info*); 296724b1896Sdrh static int csvtabDisconnect(sqlite3_vtab*); 297724b1896Sdrh static int csvtabOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); 298724b1896Sdrh static int csvtabClose(sqlite3_vtab_cursor*); 299724b1896Sdrh static int csvtabFilter(sqlite3_vtab_cursor*, int idxNum, const char *idxStr, 300724b1896Sdrh int argc, sqlite3_value **argv); 301724b1896Sdrh static int csvtabNext(sqlite3_vtab_cursor*); 302724b1896Sdrh static int csvtabEof(sqlite3_vtab_cursor*); 303724b1896Sdrh static int csvtabColumn(sqlite3_vtab_cursor*,sqlite3_context*,int); 304724b1896Sdrh static int csvtabRowid(sqlite3_vtab_cursor*,sqlite3_int64*); 305724b1896Sdrh 306724b1896Sdrh /* An instance of the CSV virtual table */ 307724b1896Sdrh typedef struct CsvTable { 308724b1896Sdrh sqlite3_vtab base; /* Base class. Must be first */ 309724b1896Sdrh char *zFilename; /* Name of the CSV file */ 310adcba64dSdrh char *zData; /* Raw CSV data in lieu of zFilename */ 311724b1896Sdrh long iStart; /* Offset to start of data in zFilename */ 312724b1896Sdrh int nCol; /* Number of columns in the CSV file */ 313abfd272bSdrh unsigned int tstFlags; /* Bit values used for testing */ 314724b1896Sdrh } CsvTable; 315724b1896Sdrh 316abfd272bSdrh /* Allowed values for tstFlags */ 317abfd272bSdrh #define CSVTEST_FIDX 0x0001 /* Pretend that constrained searchs cost less*/ 318abfd272bSdrh 319724b1896Sdrh /* A cursor for the CSV virtual table */ 320724b1896Sdrh typedef struct CsvCursor { 321724b1896Sdrh sqlite3_vtab_cursor base; /* Base class. Must be first */ 322724b1896Sdrh CsvReader rdr; /* The CsvReader object */ 323724b1896Sdrh char **azVal; /* Value of the current row */ 324ac9c3d2cSdrh int *aLen; /* Length of each entry */ 325724b1896Sdrh sqlite3_int64 iRowid; /* The current rowid. Negative for EOF */ 326724b1896Sdrh } CsvCursor; 327724b1896Sdrh 328724b1896Sdrh /* Transfer error message text from a reader into a CsvTable */ 329724b1896Sdrh static void csv_xfer_error(CsvTable *pTab, CsvReader *pRdr){ 330724b1896Sdrh sqlite3_free(pTab->base.zErrMsg); 331724b1896Sdrh pTab->base.zErrMsg = sqlite3_mprintf("%s", pRdr->zErr); 332724b1896Sdrh } 333724b1896Sdrh 334724b1896Sdrh /* 335724b1896Sdrh ** This method is the destructor fo a CsvTable object. 336724b1896Sdrh */ 337724b1896Sdrh static int csvtabDisconnect(sqlite3_vtab *pVtab){ 338724b1896Sdrh CsvTable *p = (CsvTable*)pVtab; 339724b1896Sdrh sqlite3_free(p->zFilename); 34035db31b2Sdrh sqlite3_free(p->zData); 341724b1896Sdrh sqlite3_free(p); 342724b1896Sdrh return SQLITE_OK; 343724b1896Sdrh } 344724b1896Sdrh 345724b1896Sdrh /* Skip leading whitespace. Return a pointer to the first non-whitespace 346724b1896Sdrh ** character, or to the zero terminator if the string has only whitespace */ 347724b1896Sdrh static const char *csv_skip_whitespace(const char *z){ 348724b1896Sdrh while( isspace((unsigned char)z[0]) ) z++; 349724b1896Sdrh return z; 350724b1896Sdrh } 351724b1896Sdrh 352724b1896Sdrh /* Remove trailing whitespace from the end of string z[] */ 353724b1896Sdrh static void csv_trim_whitespace(char *z){ 354724b1896Sdrh size_t n = strlen(z); 355724b1896Sdrh while( n>0 && isspace((unsigned char)z[n]) ) n--; 356724b1896Sdrh z[n] = 0; 357724b1896Sdrh } 358724b1896Sdrh 359724b1896Sdrh /* Dequote the string */ 360724b1896Sdrh static void csv_dequote(char *z){ 36180f2b33aSmistachkin int j; 362724b1896Sdrh char cQuote = z[0]; 36380f2b33aSmistachkin size_t i, n; 364724b1896Sdrh 365724b1896Sdrh if( cQuote!='\'' && cQuote!='"' ) return; 366724b1896Sdrh n = strlen(z); 367724b1896Sdrh if( n<2 || z[n-1]!=z[0] ) return; 368724b1896Sdrh for(i=1, j=0; i<n-1; i++){ 369724b1896Sdrh if( z[i]==cQuote && z[i+1]==cQuote ) i++; 370724b1896Sdrh z[j++] = z[i]; 371724b1896Sdrh } 372724b1896Sdrh z[j] = 0; 373724b1896Sdrh } 374724b1896Sdrh 375724b1896Sdrh /* Check to see if the string is of the form: "TAG = VALUE" with optional 376724b1896Sdrh ** whitespace before and around tokens. If it is, return a pointer to the 377724b1896Sdrh ** first character of VALUE. If it is not, return NULL. 378724b1896Sdrh */ 379724b1896Sdrh static const char *csv_parameter(const char *zTag, int nTag, const char *z){ 380724b1896Sdrh z = csv_skip_whitespace(z); 381724b1896Sdrh if( strncmp(zTag, z, nTag)!=0 ) return 0; 382724b1896Sdrh z = csv_skip_whitespace(z+nTag); 383724b1896Sdrh if( z[0]!='=' ) return 0; 384724b1896Sdrh return csv_skip_whitespace(z+1); 385724b1896Sdrh } 386724b1896Sdrh 387adcba64dSdrh /* Decode a parameter that requires a dequoted string. 388adcba64dSdrh ** 389adcba64dSdrh ** Return 1 if the parameter is seen, or 0 if not. 1 is returned 390adcba64dSdrh ** even if there is an error. If an error occurs, then an error message 391adcba64dSdrh ** is left in p->zErr. If there are no errors, p->zErr[0]==0. 392adcba64dSdrh */ 393adcba64dSdrh static int csv_string_parameter( 394adcba64dSdrh CsvReader *p, /* Leave the error message here, if there is one */ 395adcba64dSdrh const char *zParam, /* Parameter we are checking for */ 396adcba64dSdrh const char *zArg, /* Raw text of the virtual table argment */ 397adcba64dSdrh char **pzVal /* Write the dequoted string value here */ 398adcba64dSdrh ){ 399adcba64dSdrh const char *zValue; 40011499f0aSdrh zValue = csv_parameter(zParam,(int)strlen(zParam),zArg); 401adcba64dSdrh if( zValue==0 ) return 0; 402adcba64dSdrh p->zErr[0] = 0; 403adcba64dSdrh if( *pzVal ){ 404adcba64dSdrh csv_errmsg(p, "more than one '%s' parameter", zParam); 405adcba64dSdrh return 1; 406adcba64dSdrh } 407adcba64dSdrh *pzVal = sqlite3_mprintf("%s", zValue); 408adcba64dSdrh if( *pzVal==0 ){ 409adcba64dSdrh csv_errmsg(p, "out of memory"); 410adcba64dSdrh return 1; 411adcba64dSdrh } 412adcba64dSdrh csv_trim_whitespace(*pzVal); 413adcba64dSdrh csv_dequote(*pzVal); 414adcba64dSdrh return 1; 415adcba64dSdrh } 416adcba64dSdrh 417adcba64dSdrh 418724b1896Sdrh /* Return 0 if the argument is false and 1 if it is true. Return -1 if 419724b1896Sdrh ** we cannot really tell. 420724b1896Sdrh */ 421724b1896Sdrh static int csv_boolean(const char *z){ 422724b1896Sdrh if( sqlite3_stricmp("yes",z)==0 423724b1896Sdrh || sqlite3_stricmp("on",z)==0 424724b1896Sdrh || sqlite3_stricmp("true",z)==0 42558282f68Smistachkin || (z[0]=='1' && z[1]==0) 426724b1896Sdrh ){ 427724b1896Sdrh return 1; 428724b1896Sdrh } 429724b1896Sdrh if( sqlite3_stricmp("no",z)==0 430724b1896Sdrh || sqlite3_stricmp("off",z)==0 431724b1896Sdrh || sqlite3_stricmp("false",z)==0 432724b1896Sdrh || (z[0]=='0' && z[1]==0) 433724b1896Sdrh ){ 434724b1896Sdrh return 0; 435724b1896Sdrh } 436724b1896Sdrh return -1; 437724b1896Sdrh } 438724b1896Sdrh 439724b1896Sdrh 440724b1896Sdrh /* 441724b1896Sdrh ** Parameters: 442adcba64dSdrh ** filename=FILENAME Name of file containing CSV content 443adcba64dSdrh ** data=TEXT Direct CSV content. 4441fc1a0f2Sdrh ** schema=SCHEMA Alternative CSV schema. 445724b1896Sdrh ** header=YES|NO First row of CSV defines the names of 446724b1896Sdrh ** columns if "yes". Default "no". 447adcba64dSdrh ** columns=N Assume the CSV file contains N columns. 448ac9c3d2cSdrh ** 449ac9c3d2cSdrh ** Only available if compiled with SQLITE_TEST: 450ac9c3d2cSdrh ** 451abfd272bSdrh ** testflags=N Bitmask of test flags. Optional 452724b1896Sdrh ** 4531fc1a0f2Sdrh ** If schema= is omitted, then the columns are named "c0", "c1", "c2", 4541fc1a0f2Sdrh ** and so forth. If columns=N is omitted, then the file is opened and 4551fc1a0f2Sdrh ** the number of columns in the first row is counted to determine the 4561fc1a0f2Sdrh ** column count. If header=YES, then the first row is skipped. 457724b1896Sdrh */ 458724b1896Sdrh static int csvtabConnect( 459724b1896Sdrh sqlite3 *db, 460724b1896Sdrh void *pAux, 461724b1896Sdrh int argc, const char *const*argv, 462724b1896Sdrh sqlite3_vtab **ppVtab, 463724b1896Sdrh char **pzErr 464724b1896Sdrh ){ 4651fc1a0f2Sdrh CsvTable *pNew = 0; /* The CsvTable object to construct */ 4661fc1a0f2Sdrh int bHeader = -1; /* header= flags. -1 means not seen yet */ 4671fc1a0f2Sdrh int rc = SQLITE_OK; /* Result code from this routine */ 468adcba64dSdrh int i, j; /* Loop counters */ 469ac9c3d2cSdrh #ifdef SQLITE_TEST 470adcba64dSdrh int tstFlags = 0; /* Value for testflags=N parameter */ 471ac9c3d2cSdrh #endif 4721fc1a0f2Sdrh int nCol = -99; /* Value of the columns= parameter */ 4731fc1a0f2Sdrh CsvReader sRdr; /* A CSV file reader used to store an error 4741fc1a0f2Sdrh ** message and/or to count the number of columns */ 475adcba64dSdrh static const char *azParam[] = { 476adcba64dSdrh "filename", "data", "schema", 477adcba64dSdrh }; 478adcba64dSdrh char *azPValue[3]; /* Parameter values */ 479adcba64dSdrh # define CSV_FILENAME (azPValue[0]) 480adcba64dSdrh # define CSV_DATA (azPValue[1]) 481adcba64dSdrh # define CSV_SCHEMA (azPValue[2]) 482724b1896Sdrh 483adcba64dSdrh 484adcba64dSdrh assert( sizeof(azPValue)==sizeof(azParam) ); 485724b1896Sdrh memset(&sRdr, 0, sizeof(sRdr)); 486adcba64dSdrh memset(azPValue, 0, sizeof(azPValue)); 487724b1896Sdrh for(i=3; i<argc; i++){ 488724b1896Sdrh const char *z = argv[i]; 489724b1896Sdrh const char *zValue; 490adcba64dSdrh for(j=0; j<sizeof(azParam)/sizeof(azParam[0]); j++){ 491adcba64dSdrh if( csv_string_parameter(&sRdr, azParam[j], z, &azPValue[j]) ) break; 492724b1896Sdrh } 493adcba64dSdrh if( j<sizeof(azParam)/sizeof(azParam[0]) ){ 494adcba64dSdrh if( sRdr.zErr[0] ) goto csvtab_connect_error; 495724b1896Sdrh }else 496724b1896Sdrh if( (zValue = csv_parameter("header",6,z))!=0 ){ 497724b1896Sdrh int x; 498724b1896Sdrh if( bHeader>=0 ){ 499724b1896Sdrh csv_errmsg(&sRdr, "more than one 'header' parameter"); 500724b1896Sdrh goto csvtab_connect_error; 501724b1896Sdrh } 502724b1896Sdrh x = csv_boolean(zValue); 503724b1896Sdrh if( x==1 ){ 504724b1896Sdrh bHeader = 1; 505724b1896Sdrh }else if( x==0 ){ 506724b1896Sdrh bHeader = 0; 507724b1896Sdrh }else{ 508724b1896Sdrh csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue); 509724b1896Sdrh goto csvtab_connect_error; 510724b1896Sdrh } 511724b1896Sdrh }else 512ac9c3d2cSdrh #ifdef SQLITE_TEST 513abfd272bSdrh if( (zValue = csv_parameter("testflags",9,z))!=0 ){ 514abfd272bSdrh tstFlags = (unsigned int)atoi(zValue); 515abfd272bSdrh }else 516ac9c3d2cSdrh #endif 5171fc1a0f2Sdrh if( (zValue = csv_parameter("columns",7,z))!=0 ){ 5181fc1a0f2Sdrh if( nCol>0 ){ 5191fc1a0f2Sdrh csv_errmsg(&sRdr, "more than one 'columns' parameter"); 5201fc1a0f2Sdrh goto csvtab_connect_error; 5211fc1a0f2Sdrh } 5221fc1a0f2Sdrh nCol = atoi(zValue); 5231fc1a0f2Sdrh if( nCol<=0 ){ 5241fc1a0f2Sdrh csv_errmsg(&sRdr, "must have at least one column"); 5251fc1a0f2Sdrh goto csvtab_connect_error; 5261fc1a0f2Sdrh } 5271fc1a0f2Sdrh }else 528724b1896Sdrh { 529724b1896Sdrh csv_errmsg(&sRdr, "unrecognized parameter '%s'", z); 530724b1896Sdrh goto csvtab_connect_error; 531724b1896Sdrh } 532724b1896Sdrh } 533adcba64dSdrh if( (CSV_FILENAME==0)==(CSV_DATA==0) ){ 534adcba64dSdrh csv_errmsg(&sRdr, "must either filename= or data= but not both"); 535724b1896Sdrh goto csvtab_connect_error; 536724b1896Sdrh } 537adcba64dSdrh if( nCol<=0 && csv_reader_open(&sRdr, CSV_FILENAME, CSV_DATA) ){ 538724b1896Sdrh goto csvtab_connect_error; 539724b1896Sdrh } 540724b1896Sdrh pNew = sqlite3_malloc( sizeof(*pNew) ); 541724b1896Sdrh *ppVtab = (sqlite3_vtab*)pNew; 542724b1896Sdrh if( pNew==0 ) goto csvtab_connect_oom; 543724b1896Sdrh memset(pNew, 0, sizeof(*pNew)); 5441fc1a0f2Sdrh if( nCol>0 ){ 5451fc1a0f2Sdrh pNew->nCol = nCol; 5461fc1a0f2Sdrh }else{ 547724b1896Sdrh do{ 548*e893e2e4Sdrh csv_read_one_field(&sRdr); 549724b1896Sdrh pNew->nCol++; 550724b1896Sdrh }while( sRdr.cTerm==',' ); 5511fc1a0f2Sdrh } 552adcba64dSdrh pNew->zFilename = CSV_FILENAME; CSV_FILENAME = 0; 553adcba64dSdrh pNew->zData = CSV_DATA; CSV_DATA = 0; 554ac9c3d2cSdrh #ifdef SQLITE_TEST 555abfd272bSdrh pNew->tstFlags = tstFlags; 556ac9c3d2cSdrh #endif 557724b1896Sdrh pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0; 558724b1896Sdrh csv_reader_reset(&sRdr); 559adcba64dSdrh if( CSV_SCHEMA==0 ){ 560724b1896Sdrh char *zSep = ""; 561adcba64dSdrh CSV_SCHEMA = sqlite3_mprintf("CREATE TABLE x("); 562adcba64dSdrh if( CSV_SCHEMA==0 ) goto csvtab_connect_oom; 563724b1896Sdrh for(i=0; i<pNew->nCol; i++){ 564adcba64dSdrh CSV_SCHEMA = sqlite3_mprintf("%z%sc%d TEXT",CSV_SCHEMA, zSep, i); 565724b1896Sdrh zSep = ","; 566724b1896Sdrh } 567adcba64dSdrh CSV_SCHEMA = sqlite3_mprintf("%z);", CSV_SCHEMA); 568724b1896Sdrh } 569adcba64dSdrh rc = sqlite3_declare_vtab(db, CSV_SCHEMA); 570724b1896Sdrh if( rc ) goto csvtab_connect_error; 571adcba64dSdrh for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ 572adcba64dSdrh sqlite3_free(azPValue[i]); 573adcba64dSdrh } 574724b1896Sdrh return SQLITE_OK; 575724b1896Sdrh 576724b1896Sdrh csvtab_connect_oom: 577724b1896Sdrh rc = SQLITE_NOMEM; 578724b1896Sdrh csv_errmsg(&sRdr, "out of memory"); 579724b1896Sdrh 580724b1896Sdrh csvtab_connect_error: 581724b1896Sdrh if( pNew ) csvtabDisconnect(&pNew->base); 582adcba64dSdrh for(i=0; i<sizeof(azPValue)/sizeof(azPValue[0]); i++){ 583adcba64dSdrh sqlite3_free(azPValue[i]); 584adcba64dSdrh } 585724b1896Sdrh if( sRdr.zErr[0] ){ 586724b1896Sdrh sqlite3_free(*pzErr); 587724b1896Sdrh *pzErr = sqlite3_mprintf("%s", sRdr.zErr); 588724b1896Sdrh } 589724b1896Sdrh csv_reader_reset(&sRdr); 590abfd272bSdrh if( rc==SQLITE_OK ) rc = SQLITE_ERROR; 591724b1896Sdrh return rc; 592724b1896Sdrh } 593724b1896Sdrh 594724b1896Sdrh /* 595724b1896Sdrh ** Reset the current row content held by a CsvCursor. 596724b1896Sdrh */ 597724b1896Sdrh static void csvtabCursorRowReset(CsvCursor *pCur){ 598724b1896Sdrh CsvTable *pTab = (CsvTable*)pCur->base.pVtab; 599724b1896Sdrh int i; 600724b1896Sdrh for(i=0; i<pTab->nCol; i++){ 601724b1896Sdrh sqlite3_free(pCur->azVal[i]); 602724b1896Sdrh pCur->azVal[i] = 0; 603ac9c3d2cSdrh pCur->aLen[i] = 0; 604724b1896Sdrh } 605724b1896Sdrh } 606724b1896Sdrh 607724b1896Sdrh /* 608724b1896Sdrh ** The xConnect and xCreate methods do the same thing, but they must be 609724b1896Sdrh ** different so that the virtual table is not an eponymous virtual table. 610724b1896Sdrh */ 611724b1896Sdrh static int csvtabCreate( 612724b1896Sdrh sqlite3 *db, 613724b1896Sdrh void *pAux, 614724b1896Sdrh int argc, const char *const*argv, 615724b1896Sdrh sqlite3_vtab **ppVtab, 616724b1896Sdrh char **pzErr 617724b1896Sdrh ){ 618724b1896Sdrh return csvtabConnect(db, pAux, argc, argv, ppVtab, pzErr); 619724b1896Sdrh } 620724b1896Sdrh 621724b1896Sdrh /* 622724b1896Sdrh ** Destructor for a CsvCursor. 623724b1896Sdrh */ 624724b1896Sdrh static int csvtabClose(sqlite3_vtab_cursor *cur){ 625724b1896Sdrh CsvCursor *pCur = (CsvCursor*)cur; 626724b1896Sdrh csvtabCursorRowReset(pCur); 627724b1896Sdrh csv_reader_reset(&pCur->rdr); 628724b1896Sdrh sqlite3_free(cur); 629724b1896Sdrh return SQLITE_OK; 630724b1896Sdrh } 631724b1896Sdrh 632724b1896Sdrh /* 633724b1896Sdrh ** Constructor for a new CsvTable cursor object. 634724b1896Sdrh */ 635724b1896Sdrh static int csvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ 636724b1896Sdrh CsvTable *pTab = (CsvTable*)p; 637724b1896Sdrh CsvCursor *pCur; 638ac9c3d2cSdrh size_t nByte; 639ac9c3d2cSdrh nByte = sizeof(*pCur) + (sizeof(char*)+sizeof(int))*pTab->nCol; 64011499f0aSdrh pCur = sqlite3_malloc64( nByte ); 641724b1896Sdrh if( pCur==0 ) return SQLITE_NOMEM; 642ac9c3d2cSdrh memset(pCur, 0, nByte); 643724b1896Sdrh pCur->azVal = (char**)&pCur[1]; 644ac9c3d2cSdrh pCur->aLen = (int*)&pCur->azVal[pTab->nCol]; 645724b1896Sdrh *ppCursor = &pCur->base; 646adcba64dSdrh if( csv_reader_open(&pCur->rdr, pTab->zFilename, pTab->zData) ){ 647724b1896Sdrh csv_xfer_error(pTab, &pCur->rdr); 648724b1896Sdrh return SQLITE_ERROR; 649724b1896Sdrh } 650724b1896Sdrh return SQLITE_OK; 651724b1896Sdrh } 652724b1896Sdrh 653724b1896Sdrh 654724b1896Sdrh /* 655724b1896Sdrh ** Advance a CsvCursor to its next row of input. 656724b1896Sdrh ** Set the EOF marker if we reach the end of input. 657724b1896Sdrh */ 658724b1896Sdrh static int csvtabNext(sqlite3_vtab_cursor *cur){ 659724b1896Sdrh CsvCursor *pCur = (CsvCursor*)cur; 660724b1896Sdrh CsvTable *pTab = (CsvTable*)cur->pVtab; 661724b1896Sdrh int i = 0; 662724b1896Sdrh char *z; 663724b1896Sdrh do{ 664724b1896Sdrh z = csv_read_one_field(&pCur->rdr); 665724b1896Sdrh if( z==0 ){ 666724b1896Sdrh break; 667724b1896Sdrh } 668ac9c3d2cSdrh if( i<pTab->nCol ){ 669ac9c3d2cSdrh if( pCur->aLen[i] < pCur->rdr.n+1 ){ 67011499f0aSdrh char *zNew = sqlite3_realloc64(pCur->azVal[i], pCur->rdr.n+1); 671ac9c3d2cSdrh if( zNew==0 ){ 672724b1896Sdrh csv_errmsg(&pCur->rdr, "out of memory"); 673724b1896Sdrh csv_xfer_error(pTab, &pCur->rdr); 674724b1896Sdrh break; 675724b1896Sdrh } 676ac9c3d2cSdrh pCur->azVal[i] = zNew; 677ac9c3d2cSdrh pCur->aLen[i] = pCur->rdr.n+1; 678724b1896Sdrh } 679ac9c3d2cSdrh memcpy(pCur->azVal[i], z, pCur->rdr.n+1); 680ac9c3d2cSdrh i++; 681ac9c3d2cSdrh } 682ac9c3d2cSdrh }while( pCur->rdr.cTerm==',' ); 6834f573529Sdrh if( z==0 || (pCur->rdr.cTerm==EOF && i<pTab->nCol) ){ 6844f573529Sdrh pCur->iRowid = -1; 6854f573529Sdrh }else{ 6864f573529Sdrh pCur->iRowid++; 687ac9c3d2cSdrh while( i<pTab->nCol ){ 688ac9c3d2cSdrh sqlite3_free(pCur->azVal[i]); 689ac9c3d2cSdrh pCur->azVal[i] = 0; 690ac9c3d2cSdrh pCur->aLen[i] = 0; 691ac9c3d2cSdrh i++; 692ac9c3d2cSdrh } 693724b1896Sdrh } 694724b1896Sdrh return SQLITE_OK; 695724b1896Sdrh } 696724b1896Sdrh 697724b1896Sdrh /* 698724b1896Sdrh ** Return values of columns for the row at which the CsvCursor 699724b1896Sdrh ** is currently pointing. 700724b1896Sdrh */ 701724b1896Sdrh static int csvtabColumn( 702724b1896Sdrh sqlite3_vtab_cursor *cur, /* The cursor */ 703724b1896Sdrh sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ 704724b1896Sdrh int i /* Which column to return */ 705724b1896Sdrh ){ 706724b1896Sdrh CsvCursor *pCur = (CsvCursor*)cur; 707724b1896Sdrh CsvTable *pTab = (CsvTable*)cur->pVtab; 708724b1896Sdrh if( i>=0 && i<pTab->nCol && pCur->azVal[i]!=0 ){ 709724b1896Sdrh sqlite3_result_text(ctx, pCur->azVal[i], -1, SQLITE_STATIC); 710724b1896Sdrh } 711724b1896Sdrh return SQLITE_OK; 712724b1896Sdrh } 713724b1896Sdrh 714724b1896Sdrh /* 715724b1896Sdrh ** Return the rowid for the current row. 716724b1896Sdrh */ 717724b1896Sdrh static int csvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ 718724b1896Sdrh CsvCursor *pCur = (CsvCursor*)cur; 719724b1896Sdrh *pRowid = pCur->iRowid; 720724b1896Sdrh return SQLITE_OK; 721724b1896Sdrh } 722724b1896Sdrh 723724b1896Sdrh /* 724724b1896Sdrh ** Return TRUE if the cursor has been moved off of the last 725724b1896Sdrh ** row of output. 726724b1896Sdrh */ 727724b1896Sdrh static int csvtabEof(sqlite3_vtab_cursor *cur){ 728724b1896Sdrh CsvCursor *pCur = (CsvCursor*)cur; 729724b1896Sdrh return pCur->iRowid<0; 730724b1896Sdrh } 731724b1896Sdrh 732724b1896Sdrh /* 733724b1896Sdrh ** Only a full table scan is supported. So xFilter simply rewinds to 734724b1896Sdrh ** the beginning. 735724b1896Sdrh */ 736724b1896Sdrh static int csvtabFilter( 737724b1896Sdrh sqlite3_vtab_cursor *pVtabCursor, 738724b1896Sdrh int idxNum, const char *idxStr, 739724b1896Sdrh int argc, sqlite3_value **argv 740724b1896Sdrh ){ 741724b1896Sdrh CsvCursor *pCur = (CsvCursor*)pVtabCursor; 742724b1896Sdrh CsvTable *pTab = (CsvTable*)pVtabCursor->pVtab; 743724b1896Sdrh pCur->iRowid = 0; 744adcba64dSdrh if( pCur->rdr.in==0 ){ 745adcba64dSdrh assert( pCur->rdr.zIn==pTab->zData ); 74680f2b33aSmistachkin assert( pTab->iStart>=0 ); 74780f2b33aSmistachkin assert( (size_t)pTab->iStart<=pCur->rdr.nIn ); 748adcba64dSdrh pCur->rdr.iIn = pTab->iStart; 749adcba64dSdrh }else{ 750724b1896Sdrh fseek(pCur->rdr.in, pTab->iStart, SEEK_SET); 751adcba64dSdrh pCur->rdr.iIn = 0; 752adcba64dSdrh pCur->rdr.nIn = 0; 753adcba64dSdrh } 754724b1896Sdrh return csvtabNext(pVtabCursor); 755724b1896Sdrh } 756724b1896Sdrh 757724b1896Sdrh /* 758adcba64dSdrh ** Only a forward full table scan is supported. xBestIndex is mostly 759abfd272bSdrh ** a no-op. If CSVTEST_FIDX is set, then the presence of equality 760abfd272bSdrh ** constraints lowers the estimated cost, which is fiction, but is useful 761abfd272bSdrh ** for testing certain kinds of virtual table behavior. 762724b1896Sdrh */ 763724b1896Sdrh static int csvtabBestIndex( 764724b1896Sdrh sqlite3_vtab *tab, 765724b1896Sdrh sqlite3_index_info *pIdxInfo 766724b1896Sdrh ){ 767abfd272bSdrh pIdxInfo->estimatedCost = 1000000; 768ac9c3d2cSdrh #ifdef SQLITE_TEST 769ac9c3d2cSdrh if( (((CsvTable*)tab)->tstFlags & CSVTEST_FIDX)!=0 ){ 770ac9c3d2cSdrh /* The usual (and sensible) case is to always do a full table scan. 771ac9c3d2cSdrh ** The code in this branch only runs when testflags=1. This code 7721fc1a0f2Sdrh ** generates an artifical and unrealistic plan which is useful 773adcba64dSdrh ** for testing virtual table logic but is not helpful to real applications. 774adcba64dSdrh ** 775adcba64dSdrh ** Any ==, LIKE, or GLOB constraint is marked as usable by the virtual 776adcba64dSdrh ** table (even though it is not) and the cost of running the virtual table 777adcba64dSdrh ** is reduced from 1 million to just 10. The constraints are *not* marked 778adcba64dSdrh ** as omittable, however, so the query planner should still generate a 779adcba64dSdrh ** plan that gives a correct answer, even if they plan is not optimal. 780adcba64dSdrh */ 781ac9c3d2cSdrh int i; 782ac9c3d2cSdrh int nConst = 0; 783abfd272bSdrh for(i=0; i<pIdxInfo->nConstraint; i++){ 7841fc1a0f2Sdrh unsigned char op; 785abfd272bSdrh if( pIdxInfo->aConstraint[i].usable==0 ) continue; 7861fc1a0f2Sdrh op = pIdxInfo->aConstraint[i].op; 7871fc1a0f2Sdrh if( op==SQLITE_INDEX_CONSTRAINT_EQ 7881fc1a0f2Sdrh || op==SQLITE_INDEX_CONSTRAINT_LIKE 7891fc1a0f2Sdrh || op==SQLITE_INDEX_CONSTRAINT_GLOB 7901fc1a0f2Sdrh ){ 791abfd272bSdrh pIdxInfo->estimatedCost = 10; 7921fc1a0f2Sdrh pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1; 7931fc1a0f2Sdrh nConst++; 794abfd272bSdrh } 795abfd272bSdrh } 796ac9c3d2cSdrh } 797ac9c3d2cSdrh #endif 798724b1896Sdrh return SQLITE_OK; 799724b1896Sdrh } 800724b1896Sdrh 801724b1896Sdrh 802724b1896Sdrh static sqlite3_module CsvModule = { 803724b1896Sdrh 0, /* iVersion */ 804724b1896Sdrh csvtabCreate, /* xCreate */ 805724b1896Sdrh csvtabConnect, /* xConnect */ 806724b1896Sdrh csvtabBestIndex, /* xBestIndex */ 807724b1896Sdrh csvtabDisconnect, /* xDisconnect */ 808724b1896Sdrh csvtabDisconnect, /* xDestroy */ 809724b1896Sdrh csvtabOpen, /* xOpen - open a cursor */ 810724b1896Sdrh csvtabClose, /* xClose - close a cursor */ 811724b1896Sdrh csvtabFilter, /* xFilter - configure scan constraints */ 812724b1896Sdrh csvtabNext, /* xNext - advance a cursor */ 813724b1896Sdrh csvtabEof, /* xEof - check for end of scan */ 814724b1896Sdrh csvtabColumn, /* xColumn - read data */ 815724b1896Sdrh csvtabRowid, /* xRowid - read data */ 816724b1896Sdrh 0, /* xUpdate */ 817724b1896Sdrh 0, /* xBegin */ 818724b1896Sdrh 0, /* xSync */ 819724b1896Sdrh 0, /* xCommit */ 820724b1896Sdrh 0, /* xRollback */ 821724b1896Sdrh 0, /* xFindMethod */ 822724b1896Sdrh 0, /* xRename */ 823724b1896Sdrh }; 824724b1896Sdrh 825ac9c3d2cSdrh #ifdef SQLITE_TEST 826ac9c3d2cSdrh /* 827ac9c3d2cSdrh ** For virtual table testing, make a version of the CSV virtual table 828ac9c3d2cSdrh ** available that has an xUpdate function. But the xUpdate always returns 829ac9c3d2cSdrh ** SQLITE_READONLY since the CSV file is not really writable. 830ac9c3d2cSdrh */ 831ac9c3d2cSdrh static int csvtabUpdate(sqlite3_vtab *p,int n,sqlite3_value**v,sqlite3_int64*x){ 832ac9c3d2cSdrh return SQLITE_READONLY; 833ac9c3d2cSdrh } 834ac9c3d2cSdrh static sqlite3_module CsvModuleFauxWrite = { 835ac9c3d2cSdrh 0, /* iVersion */ 836ac9c3d2cSdrh csvtabCreate, /* xCreate */ 837ac9c3d2cSdrh csvtabConnect, /* xConnect */ 838ac9c3d2cSdrh csvtabBestIndex, /* xBestIndex */ 839ac9c3d2cSdrh csvtabDisconnect, /* xDisconnect */ 840ac9c3d2cSdrh csvtabDisconnect, /* xDestroy */ 841ac9c3d2cSdrh csvtabOpen, /* xOpen - open a cursor */ 842ac9c3d2cSdrh csvtabClose, /* xClose - close a cursor */ 843ac9c3d2cSdrh csvtabFilter, /* xFilter - configure scan constraints */ 844ac9c3d2cSdrh csvtabNext, /* xNext - advance a cursor */ 845ac9c3d2cSdrh csvtabEof, /* xEof - check for end of scan */ 846ac9c3d2cSdrh csvtabColumn, /* xColumn - read data */ 847ac9c3d2cSdrh csvtabRowid, /* xRowid - read data */ 848ac9c3d2cSdrh csvtabUpdate, /* xUpdate */ 849ac9c3d2cSdrh 0, /* xBegin */ 850ac9c3d2cSdrh 0, /* xSync */ 851ac9c3d2cSdrh 0, /* xCommit */ 852ac9c3d2cSdrh 0, /* xRollback */ 853ac9c3d2cSdrh 0, /* xFindMethod */ 854ac9c3d2cSdrh 0, /* xRename */ 855ac9c3d2cSdrh }; 856ac9c3d2cSdrh #endif /* SQLITE_TEST */ 857ac9c3d2cSdrh 858eb5a549eSdrh #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) */ 859ac9c3d2cSdrh 860ac9c3d2cSdrh 861724b1896Sdrh #ifdef _WIN32 862724b1896Sdrh __declspec(dllexport) 863724b1896Sdrh #endif 864724b1896Sdrh /* 865724b1896Sdrh ** This routine is called when the extension is loaded. The new 866724b1896Sdrh ** CSV virtual table module is registered with the calling database 867724b1896Sdrh ** connection. 868724b1896Sdrh */ 869724b1896Sdrh int sqlite3_csv_init( 870724b1896Sdrh sqlite3 *db, 871724b1896Sdrh char **pzErrMsg, 872724b1896Sdrh const sqlite3_api_routines *pApi 873724b1896Sdrh ){ 874eb5a549eSdrh #ifndef SQLITE_OMIT_VIRTUALTABLE 875ac9c3d2cSdrh int rc; 876724b1896Sdrh SQLITE_EXTENSION_INIT2(pApi); 877ac9c3d2cSdrh rc = sqlite3_create_module(db, "csv", &CsvModule, 0); 878ac9c3d2cSdrh #ifdef SQLITE_TEST 879ac9c3d2cSdrh if( rc==SQLITE_OK ){ 880ac9c3d2cSdrh rc = sqlite3_create_module(db, "csv_wr", &CsvModuleFauxWrite, 0); 881ac9c3d2cSdrh } 882ac9c3d2cSdrh #endif 883ac9c3d2cSdrh return rc; 884eb5a549eSdrh #else 885eb5a549eSdrh return SQLITE_OK; 886eb5a549eSdrh #endif 887724b1896Sdrh } 888