[205] | 1 | /*
|
---|
| 2 | ** 2003 April 6
|
---|
| 3 | **
|
---|
| 4 | ** The author disclaims copyright to this source code. In place of
|
---|
| 5 | ** a legal notice, here is a blessing:
|
---|
| 6 | **
|
---|
| 7 | ** May you do good and not evil.
|
---|
| 8 | ** May you find forgiveness for yourself and forgive others.
|
---|
| 9 | ** May you share freely, never taking more than you give.
|
---|
| 10 | **
|
---|
| 11 | *************************************************************************
|
---|
| 12 | ** This file contains code used to implement the COPY command.
|
---|
| 13 | **
|
---|
| 14 | ** $Id: copy.c,v 1.9 2004/02/25 13:47:31 drh Exp $
|
---|
| 15 | */
|
---|
| 16 | #include "sqliteInt.h"
|
---|
| 17 |
|
---|
| 18 | /*
|
---|
| 19 | ** The COPY command is for compatibility with PostgreSQL and specificially
|
---|
| 20 | ** for the ability to read the output of pg_dump. The format is as
|
---|
| 21 | ** follows:
|
---|
| 22 | **
|
---|
| 23 | ** COPY table FROM file [USING DELIMITERS string]
|
---|
| 24 | **
|
---|
| 25 | ** "table" is an existing table name. We will read lines of code from
|
---|
| 26 | ** file to fill this table with data. File might be "stdin". The optional
|
---|
| 27 | ** delimiter string identifies the field separators. The default is a tab.
|
---|
| 28 | */
|
---|
| 29 | void sqliteCopy(
|
---|
| 30 | Parse *pParse, /* The parser context */
|
---|
| 31 | SrcList *pTableName, /* The name of the table into which we will insert */
|
---|
| 32 | Token *pFilename, /* The file from which to obtain information */
|
---|
| 33 | Token *pDelimiter, /* Use this as the field delimiter */
|
---|
| 34 | int onError /* What to do if a constraint fails */
|
---|
| 35 | ){
|
---|
| 36 | Table *pTab;
|
---|
| 37 | int i;
|
---|
| 38 | Vdbe *v;
|
---|
| 39 | int addr, end;
|
---|
| 40 | char *zFile = 0;
|
---|
| 41 | const char *zDb;
|
---|
| 42 | sqlite *db = pParse->db;
|
---|
| 43 |
|
---|
| 44 |
|
---|
| 45 | if( sqlite_malloc_failed ) goto copy_cleanup;
|
---|
| 46 | assert( pTableName->nSrc==1 );
|
---|
| 47 | pTab = sqliteSrcListLookup(pParse, pTableName);
|
---|
| 48 | if( pTab==0 || sqliteIsReadOnly(pParse, pTab, 0) ) goto copy_cleanup;
|
---|
| 49 | zFile = sqliteStrNDup(pFilename->z, pFilename->n);
|
---|
| 50 | sqliteDequote(zFile);
|
---|
| 51 | assert( pTab->iDb<db->nDb );
|
---|
| 52 | zDb = db->aDb[pTab->iDb].zName;
|
---|
| 53 | if( sqliteAuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb)
|
---|
| 54 | || sqliteAuthCheck(pParse, SQLITE_COPY, pTab->zName, zFile, zDb) ){
|
---|
| 55 | goto copy_cleanup;
|
---|
| 56 | }
|
---|
| 57 | v = sqliteGetVdbe(pParse);
|
---|
| 58 | if( v ){
|
---|
| 59 | sqliteBeginWriteOperation(pParse, 1, pTab->iDb);
|
---|
| 60 | addr = sqliteVdbeOp3(v, OP_FileOpen, 0, 0, pFilename->z, pFilename->n);
|
---|
| 61 | sqliteVdbeDequoteP3(v, addr);
|
---|
| 62 | sqliteOpenTableAndIndices(pParse, pTab, 0);
|
---|
| 63 | if( db->flags & SQLITE_CountRows ){
|
---|
| 64 | sqliteVdbeAddOp(v, OP_Integer, 0, 0); /* Initialize the row count */
|
---|
| 65 | }
|
---|
| 66 | end = sqliteVdbeMakeLabel(v);
|
---|
| 67 | addr = sqliteVdbeAddOp(v, OP_FileRead, pTab->nCol, end);
|
---|
| 68 | if( pDelimiter ){
|
---|
| 69 | sqliteVdbeChangeP3(v, addr, pDelimiter->z, pDelimiter->n);
|
---|
| 70 | sqliteVdbeDequoteP3(v, addr);
|
---|
| 71 | }else{
|
---|
| 72 | sqliteVdbeChangeP3(v, addr, "\t", 1);
|
---|
| 73 | }
|
---|
| 74 | if( pTab->iPKey>=0 ){
|
---|
| 75 | sqliteVdbeAddOp(v, OP_FileColumn, pTab->iPKey, 0);
|
---|
| 76 | sqliteVdbeAddOp(v, OP_MustBeInt, 0, 0);
|
---|
| 77 | }else{
|
---|
| 78 | sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
|
---|
| 79 | }
|
---|
| 80 | for(i=0; i<pTab->nCol; i++){
|
---|
| 81 | if( i==pTab->iPKey ){
|
---|
| 82 | /* The integer primary key column is filled with NULL since its
|
---|
| 83 | ** value is always pulled from the record number */
|
---|
| 84 | sqliteVdbeAddOp(v, OP_String, 0, 0);
|
---|
| 85 | }else{
|
---|
| 86 | sqliteVdbeAddOp(v, OP_FileColumn, i, 0);
|
---|
| 87 | }
|
---|
| 88 | }
|
---|
| 89 | sqliteGenerateConstraintChecks(pParse, pTab, 0, 0, pTab->iPKey>=0,
|
---|
| 90 | 0, onError, addr);
|
---|
| 91 | sqliteCompleteInsertion(pParse, pTab, 0, 0, 0, 0, -1);
|
---|
| 92 | if( (db->flags & SQLITE_CountRows)!=0 ){
|
---|
| 93 | sqliteVdbeAddOp(v, OP_AddImm, 1, 0); /* Increment row count */
|
---|
| 94 | }
|
---|
| 95 | sqliteVdbeAddOp(v, OP_Goto, 0, addr);
|
---|
| 96 | sqliteVdbeResolveLabel(v, end);
|
---|
| 97 | sqliteVdbeAddOp(v, OP_Noop, 0, 0);
|
---|
| 98 | sqliteEndWriteOperation(pParse);
|
---|
| 99 | if( db->flags & SQLITE_CountRows ){
|
---|
| 100 | sqliteVdbeAddOp(v, OP_ColumnName, 0, 1);
|
---|
| 101 | sqliteVdbeChangeP3(v, -1, "rows inserted", P3_STATIC);
|
---|
| 102 | sqliteVdbeAddOp(v, OP_Callback, 1, 0);
|
---|
| 103 | }
|
---|
| 104 | }
|
---|
| 105 |
|
---|
| 106 | copy_cleanup:
|
---|
| 107 | sqliteSrcListDelete(pTableName);
|
---|
| 108 | sqliteFree(zFile);
|
---|
| 109 | return;
|
---|
| 110 | }
|
---|