SQLite

Check-in [28ebeadd6a]
Login

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

Overview
Comment:Add the columns=N parameter to the CSV extension.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 28ebeadd6a4c9ff2ce9fc86a0f0fe2f6cf94d3ac
User & Date: drh 2016-05-31 18:44:33.835
Context
2016-06-01
05:02
Fix compilation issues with the VFS stat extension. (check-in: f6e956525b user: mistachkin tags: trunk)
2016-05-31
21:18
An experimental branch with code that allows virtual tables to be declared as WITHOUT ROWID tables. This might be useful for virtual tables that model external data sources that do not have a convenient way of computing a unique rowid. The current check-in almost works, but there are still serious issues. (check-in: 49638f180e user: drh tags: without-rowid-vtab)
18:44
Add the columns=N parameter to the CSV extension. (check-in: 28ebeadd6a user: drh tags: trunk)
18:08
Add the testflags parameter to the csv extension. (check-in: b93fb2fe0d user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/misc/csv.c.
311
312
313
314
315
316
317
318
319
320

321
322
323
324


325
326
327
328
329
330
331
332
333
334
335
336
337
338
339

340

341
342
343
344
345
346
347
  return -1;
}


/*
** Parameters:
**    filename=FILENAME          Required
**    schema=SCHEMA              Optional
**    header=YES|NO              First row of CSV defines the names of
**                               columns if "yes".  Default "no".

**    testflags=N                Bitmask of test flags.  Optional
**
** If header=no and not columns are listed, then the columns are named
** "c0", "c1", "c2", and so forth.


*/
static int csvtabConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  CsvTable *pNew = 0;
  int bHeader = -1;
  int rc = SQLITE_OK;
  int i;
  char *zFilename = 0;
  char *zSchema = 0;
  int tstFlags = 0;

  CsvReader sRdr;


  memset(&sRdr, 0, sizeof(sRdr));
  for(i=3; i<argc; i++){
    const char *z = argv[i];
    const char *zValue;
    if( (zValue = csv_parameter("filename",8,z))!=0 ){
      if( zFilename ){







|


>


|
|
>
>








|
|
|
|
|
|
|
>
|
>







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
  return -1;
}


/*
** Parameters:
**    filename=FILENAME          Required
**    schema=SCHEMA              Alternative CSV schema.
**    header=YES|NO              First row of CSV defines the names of
**                               columns if "yes".  Default "no".
**    columns=N                  Assum the CSV file contains N columns.
**    testflags=N                Bitmask of test flags.  Optional
**
** If schema= is omitted, then the columns are named "c0", "c1", "c2",
** and so forth.  If columns=N is omitted, then the file is opened and
** the number of columns in the first row is counted to determine the
** column count.  If header=YES, then the first row is skipped.
*/
static int csvtabConnect(
  sqlite3 *db,
  void *pAux,
  int argc, const char *const*argv,
  sqlite3_vtab **ppVtab,
  char **pzErr
){
  CsvTable *pNew = 0;        /* The CsvTable object to construct */
  int bHeader = -1;          /* header= flags.  -1 means not seen yet */
  int rc = SQLITE_OK;        /* Result code from this routine */
  int i;                     /* Loop counter */
  char *zFilename = 0;       /* Value of the filename= parameter */
  char *zSchema = 0;         /* Value of the schema= parameter */
  int tstFlags = 0;          /* Value of the testflags= parameter */
  int nCol = -99;            /* Value of the columns= parameter */
  CsvReader sRdr;            /* A CSV file reader used to store an error
                             ** message and/or to count the number of columns */

  memset(&sRdr, 0, sizeof(sRdr));
  for(i=3; i<argc; i++){
    const char *z = argv[i];
    const char *zValue;
    if( (zValue = csv_parameter("filename",8,z))!=0 ){
      if( zFilename ){
378
379
380
381
382
383
384











385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400



401
402
403
404
405

406
407
408
409
410
411
412
        csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue);
        goto csvtab_connect_error;
      }
    }else
    if( (zValue = csv_parameter("testflags",9,z))!=0 ){
      tstFlags = (unsigned int)atoi(zValue);
    }else











    {
      csv_errmsg(&sRdr, "unrecognized parameter '%s'", z);
      goto csvtab_connect_error;
    }
  }
  if( zFilename==0 ){
    csv_errmsg(&sRdr, "missing 'filename' parameter");
    goto csvtab_connect_error;
  }
  if( csv_reader_open(&sRdr, zFilename) ){
    goto csvtab_connect_error;
  }
  pNew = sqlite3_malloc( sizeof(*pNew) );
  *ppVtab = (sqlite3_vtab*)pNew;
  if( pNew==0 ) goto csvtab_connect_oom;
  memset(pNew, 0, sizeof(*pNew));



  do{
    const char *z = csv_read_one_field(&sRdr);
    if( z==0 ) goto csvtab_connect_oom;
    pNew->nCol++;
  }while( sRdr.cTerm==',' );

  pNew->zFilename = zFilename;
  pNew->tstFlags = tstFlags;
  zFilename = 0;
  pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0;
  csv_reader_reset(&sRdr);
  if( zSchema==0 ){
    char *zSep = "";







>
>
>
>
>
>
>
>
>
>
>









|






>
>
>
|
|
|
|
|
>







383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
        csv_errmsg(&sRdr, "unrecognized argument to 'header': %s", zValue);
        goto csvtab_connect_error;
      }
    }else
    if( (zValue = csv_parameter("testflags",9,z))!=0 ){
      tstFlags = (unsigned int)atoi(zValue);
    }else
    if( (zValue = csv_parameter("columns",7,z))!=0 ){
      if( nCol>0 ){
        csv_errmsg(&sRdr, "more than one 'columns' parameter");
        goto csvtab_connect_error;
      }
      nCol = atoi(zValue);
      if( nCol<=0 ){
        csv_errmsg(&sRdr, "must have at least one column");
        goto csvtab_connect_error;
      }
    }else
    {
      csv_errmsg(&sRdr, "unrecognized parameter '%s'", z);
      goto csvtab_connect_error;
    }
  }
  if( zFilename==0 ){
    csv_errmsg(&sRdr, "missing 'filename' parameter");
    goto csvtab_connect_error;
  }
  if( nCol<=0 && csv_reader_open(&sRdr, zFilename) ){
    goto csvtab_connect_error;
  }
  pNew = sqlite3_malloc( sizeof(*pNew) );
  *ppVtab = (sqlite3_vtab*)pNew;
  if( pNew==0 ) goto csvtab_connect_oom;
  memset(pNew, 0, sizeof(*pNew));
  if( nCol>0 ){
    pNew->nCol = nCol;
  }else{
    do{
      const char *z = csv_read_one_field(&sRdr);
      if( z==0 ) goto csvtab_connect_oom;
      pNew->nCol++;
    }while( sRdr.cTerm==',' );
  }
  pNew->zFilename = zFilename;
  pNew->tstFlags = tstFlags;
  zFilename = 0;
  pNew->iStart = bHeader==1 ? ftell(sRdr.in) : 0;
  csv_reader_reset(&sRdr);
  if( zSchema==0 ){
    char *zSep = "";
589
590
591
592
593
594
595

596
597
598
599




600

601

602



603
604


605
606
607
608
609
610
611
*/
static int csvtabBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  CsvTable *pTab = (CsvTable*)tab;
  int i;

  pIdxInfo->estimatedCost = 1000000;
  if( (pTab->tstFlags & CSVTEST_FIDX)==0 ){
    return SQLITE_OK;
  }




  for(i=0; i<pIdxInfo->nConstraint; i++){

    if( pIdxInfo->aConstraint[i].usable==0 ) continue;

    if( pIdxInfo->aConstraint[i].op==SQLITE_INDEX_CONSTRAINT_EQ ){



      pIdxInfo->estimatedCost = 10;
      break;


    }
  }
  return SQLITE_OK;
}


static sqlite3_module CsvModule = {







>




>
>
>
>

>

>
|
>
>
>

<
>
>







609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633

634
635
636
637
638
639
640
641
642
*/
static int csvtabBestIndex(
  sqlite3_vtab *tab,
  sqlite3_index_info *pIdxInfo
){
  CsvTable *pTab = (CsvTable*)tab;
  int i;
  int nConst = 0;
  pIdxInfo->estimatedCost = 1000000;
  if( (pTab->tstFlags & CSVTEST_FIDX)==0 ){
    return SQLITE_OK;
  }
  /* The usual (an sensible) case is to take the "return SQLITE_OK" above.
  ** The code below only runs when testflags=1.  The following code
  ** generates an artifical and unrealistic plan which is useful
  ** for testing virtual table logic but is useless for real applications. */
  for(i=0; i<pIdxInfo->nConstraint; i++){
    unsigned char op;
    if( pIdxInfo->aConstraint[i].usable==0 ) continue;
    op = pIdxInfo->aConstraint[i].op;
    if( op==SQLITE_INDEX_CONSTRAINT_EQ 
     || op==SQLITE_INDEX_CONSTRAINT_LIKE
     || op==SQLITE_INDEX_CONSTRAINT_GLOB
    ){
      pIdxInfo->estimatedCost = 10;

      pIdxInfo->aConstraintUsage[nConst].argvIndex = nConst+1;
      nConst++;
    }
  }
  return SQLITE_OK;
}


static sqlite3_module CsvModule = {