| | @@ -92,14 +92,14 @@ |
| 92 | 92 | # include <signal.h> |
| 93 | 93 | # if !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 94 | 94 | # include <pwd.h> |
| 95 | 95 | # endif |
| 96 | 96 | #endif |
| 97 | | -#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW_H) |
| 97 | +#if (!defined(_WIN32) && !defined(WIN32)) || defined(__MINGW32__) |
| 98 | 98 | # include <unistd.h> |
| 99 | 99 | # include <dirent.h> |
| 100 | | -# if defined(__MINGW_H) |
| 100 | +# if defined(__MINGW32__) |
| 101 | 101 | # define DIRENT dirent |
| 102 | 102 | # ifndef S_ISLNK |
| 103 | 103 | # define S_ISLNK(mode) (0) |
| 104 | 104 | # endif |
| 105 | 105 | # endif |
| | @@ -368,10 +368,15 @@ |
| 368 | 368 | /* |
| 369 | 369 | ** Used to prevent warnings about unused parameters |
| 370 | 370 | */ |
| 371 | 371 | #define UNUSED_PARAMETER(x) (void)(x) |
| 372 | 372 | |
| 373 | +/* |
| 374 | +** Number of elements in an array |
| 375 | +*/ |
| 376 | +#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) |
| 377 | + |
| 373 | 378 | /* |
| 374 | 379 | ** If the following flag is set, then command execution stops |
| 375 | 380 | ** at an error if we are not interactive. |
| 376 | 381 | */ |
| 377 | 382 | static int bail_on_error = 0; |
| | @@ -640,10 +645,69 @@ |
| 640 | 645 | if( zResult && *zResult ) shell_add_history(zResult); |
| 641 | 646 | #endif |
| 642 | 647 | } |
| 643 | 648 | return zResult; |
| 644 | 649 | } |
| 650 | + |
| 651 | + |
| 652 | +/* |
| 653 | +** Return the value of a hexadecimal digit. Return -1 if the input |
| 654 | +** is not a hex digit. |
| 655 | +*/ |
| 656 | +static int hexDigitValue(char c){ |
| 657 | + if( c>='0' && c<='9' ) return c - '0'; |
| 658 | + if( c>='a' && c<='f' ) return c - 'a' + 10; |
| 659 | + if( c>='A' && c<='F' ) return c - 'A' + 10; |
| 660 | + return -1; |
| 661 | +} |
| 662 | + |
| 663 | +/* |
| 664 | +** Interpret zArg as an integer value, possibly with suffixes. |
| 665 | +*/ |
| 666 | +static sqlite3_int64 integerValue(const char *zArg){ |
| 667 | + sqlite3_int64 v = 0; |
| 668 | + static const struct { char *zSuffix; int iMult; } aMult[] = { |
| 669 | + { "KiB", 1024 }, |
| 670 | + { "MiB", 1024*1024 }, |
| 671 | + { "GiB", 1024*1024*1024 }, |
| 672 | + { "KB", 1000 }, |
| 673 | + { "MB", 1000000 }, |
| 674 | + { "GB", 1000000000 }, |
| 675 | + { "K", 1000 }, |
| 676 | + { "M", 1000000 }, |
| 677 | + { "G", 1000000000 }, |
| 678 | + }; |
| 679 | + int i; |
| 680 | + int isNeg = 0; |
| 681 | + if( zArg[0]=='-' ){ |
| 682 | + isNeg = 1; |
| 683 | + zArg++; |
| 684 | + }else if( zArg[0]=='+' ){ |
| 685 | + zArg++; |
| 686 | + } |
| 687 | + if( zArg[0]=='0' && zArg[1]=='x' ){ |
| 688 | + int x; |
| 689 | + zArg += 2; |
| 690 | + while( (x = hexDigitValue(zArg[0]))>=0 ){ |
| 691 | + v = (v<<4) + x; |
| 692 | + zArg++; |
| 693 | + } |
| 694 | + }else{ |
| 695 | + while( IsDigit(zArg[0]) ){ |
| 696 | + v = v*10 + zArg[0] - '0'; |
| 697 | + zArg++; |
| 698 | + } |
| 699 | + } |
| 700 | + for(i=0; i<ArraySize(aMult); i++){ |
| 701 | + if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ |
| 702 | + v *= aMult[i].iMult; |
| 703 | + break; |
| 704 | + } |
| 705 | + } |
| 706 | + return isNeg? -v : v; |
| 707 | +} |
| 708 | + |
| 645 | 709 | /* |
| 646 | 710 | ** A variable length string to which one can append text. |
| 647 | 711 | */ |
| 648 | 712 | typedef struct ShellText ShellText; |
| 649 | 713 | struct ShellText { |
| | @@ -818,12 +882,13 @@ |
| 818 | 882 | sqlite3_value **apVal |
| 819 | 883 | ){ |
| 820 | 884 | const char *zName = (const char*)sqlite3_value_text(apVal[0]); |
| 821 | 885 | char *zFake = shellFakeSchema(sqlite3_context_db_handle(pCtx), 0, zName); |
| 822 | 886 | if( zFake ){ |
| 823 | | - sqlite3_result_text(pCtx, sqlite3_mprintf("/* %z */", zFake), |
| 887 | + sqlite3_result_text(pCtx, sqlite3_mprintf("/* %s */", zFake), |
| 824 | 888 | -1, sqlite3_free); |
| 889 | + free(zFake); |
| 825 | 890 | } |
| 826 | 891 | } |
| 827 | 892 | |
| 828 | 893 | /* |
| 829 | 894 | ** SQL function: shell_add_schema(S,X) |
| | @@ -879,14 +944,15 @@ |
| 879 | 944 | if( zName |
| 880 | 945 | && aPrefix[i][0]=='V' |
| 881 | 946 | && (zFake = shellFakeSchema(db, zSchema, zName))!=0 |
| 882 | 947 | ){ |
| 883 | 948 | if( z==0 ){ |
| 884 | | - z = sqlite3_mprintf("%s\n/* %z */", zIn, zFake); |
| 949 | + z = sqlite3_mprintf("%s\n/* %s */", zIn, zFake); |
| 885 | 950 | }else{ |
| 886 | | - z = sqlite3_mprintf("%z\n/* %z */", z, zFake); |
| 951 | + z = sqlite3_mprintf("%z\n/* %s */", z, zFake); |
| 887 | 952 | } |
| 953 | + free(zFake); |
| 888 | 954 | } |
| 889 | 955 | if( z ){ |
| 890 | 956 | sqlite3_result_text(pCtx, z, -1, sqlite3_free); |
| 891 | 957 | return; |
| 892 | 958 | } |
| | @@ -2068,14 +2134,15 @@ |
| 2068 | 2134 | # include "windows.h" |
| 2069 | 2135 | # include <io.h> |
| 2070 | 2136 | # include <direct.h> |
| 2071 | 2137 | /* # include "test_windirent.h" */ |
| 2072 | 2138 | # define dirent DIRENT |
| 2073 | | -# define timespec TIMESPEC |
| 2074 | | -# define stat _stat |
| 2139 | +# ifndef stat |
| 2140 | +# define stat _stat |
| 2141 | +# endif |
| 2075 | 2142 | # define mkdir(path,mode) _mkdir(path) |
| 2076 | | -# define lstat(path,buf) _stat(path,buf) |
| 2143 | +# define lstat(path,buf) stat(path,buf) |
| 2077 | 2144 | #endif |
| 2078 | 2145 | #include <time.h> |
| 2079 | 2146 | #include <errno.h> |
| 2080 | 2147 | |
| 2081 | 2148 | |
| | @@ -2331,10 +2398,44 @@ |
| 2331 | 2398 | }else{ |
| 2332 | 2399 | ctxErrorMsg(context, "failed to write file: %s", zFile); |
| 2333 | 2400 | } |
| 2334 | 2401 | } |
| 2335 | 2402 | } |
| 2403 | + |
| 2404 | +/* |
| 2405 | +** SQL function: lsmode(MODE) |
| 2406 | +** |
| 2407 | +** Given a numberic st_mode from stat(), convert it into a human-readable |
| 2408 | +** text string in the style of "ls -l". |
| 2409 | +*/ |
| 2410 | +static void lsModeFunc( |
| 2411 | + sqlite3_context *context, |
| 2412 | + int argc, |
| 2413 | + sqlite3_value **argv |
| 2414 | +){ |
| 2415 | + int i; |
| 2416 | + int iMode = sqlite3_value_int(argv[0]); |
| 2417 | + char z[16]; |
| 2418 | + if( S_ISLNK(iMode) ){ |
| 2419 | + z[0] = 'l'; |
| 2420 | + }else if( S_ISREG(iMode) ){ |
| 2421 | + z[0] = '-'; |
| 2422 | + }else if( S_ISDIR(iMode) ){ |
| 2423 | + z[0] = 'd'; |
| 2424 | + }else{ |
| 2425 | + z[0] = '?'; |
| 2426 | + } |
| 2427 | + for(i=0; i<3; i++){ |
| 2428 | + int m = (iMode >> ((2-i)*3)); |
| 2429 | + char *a = &z[1 + i*3]; |
| 2430 | + a[0] = (m & 0x4) ? 'r' : '-'; |
| 2431 | + a[1] = (m & 0x2) ? 'w' : '-'; |
| 2432 | + a[2] = (m & 0x1) ? 'x' : '-'; |
| 2433 | + } |
| 2434 | + z[10] = '\0'; |
| 2435 | + sqlite3_result_text(context, z, -1, SQLITE_TRANSIENT); |
| 2436 | +} |
| 2336 | 2437 | |
| 2337 | 2438 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 2338 | 2439 | |
| 2339 | 2440 | /* |
| 2340 | 2441 | ** Cursor type for recursively iterating through a directory structure. |
| | @@ -2743,10 +2844,14 @@ |
| 2743 | 2844 | readfileFunc, 0, 0); |
| 2744 | 2845 | if( rc==SQLITE_OK ){ |
| 2745 | 2846 | rc = sqlite3_create_function(db, "writefile", -1, SQLITE_UTF8, 0, |
| 2746 | 2847 | writefileFunc, 0, 0); |
| 2747 | 2848 | } |
| 2849 | + if( rc==SQLITE_OK ){ |
| 2850 | + rc = sqlite3_create_function(db, "lsmode", 1, SQLITE_UTF8, 0, |
| 2851 | + lsModeFunc, 0, 0); |
| 2852 | + } |
| 2748 | 2853 | if( rc==SQLITE_OK ){ |
| 2749 | 2854 | rc = fsdirRegister(db); |
| 2750 | 2855 | } |
| 2751 | 2856 | return rc; |
| 2752 | 2857 | } |
| | @@ -3885,21 +3990,22 @@ |
| 3885 | 3990 | typedef unsigned short u16; |
| 3886 | 3991 | typedef unsigned long u32; |
| 3887 | 3992 | #define MIN(a,b) ((a)<(b) ? (a) : (b)) |
| 3888 | 3993 | #endif |
| 3889 | 3994 | |
| 3890 | | -#define ZIPFILE_SCHEMA "CREATE TABLE y(" \ |
| 3891 | | - "name, /* Name of file in zip archive */" \ |
| 3892 | | - "mode, /* POSIX mode for file */" \ |
| 3893 | | - "mtime, /* Last modification time in seconds since epoch */" \ |
| 3894 | | - "sz, /* Size of object */" \ |
| 3895 | | - "data, /* Data stored in zip file (possibly compressed) */" \ |
| 3896 | | - "method, /* Compression method (integer) */" \ |
| 3897 | | - "f HIDDEN /* Name of zip file */" \ |
| 3995 | +#define ZIPFILE_SCHEMA "CREATE TABLE y(" \ |
| 3996 | + "name, /* 0: Name of file in zip archive */" \ |
| 3997 | + "mode, /* 1: POSIX mode for file */" \ |
| 3998 | + "mtime, /* 2: Last modification time in seconds since epoch */" \ |
| 3999 | + "sz, /* 3: Size of object */" \ |
| 4000 | + "rawdata, /* 4: Raw data */" \ |
| 4001 | + "data, /* 5: Uncompressed data */" \ |
| 4002 | + "method, /* 6: Compression method (integer) */" \ |
| 4003 | + "file HIDDEN /* Name of zip file */" \ |
| 3898 | 4004 | ");" |
| 3899 | 4005 | |
| 3900 | | -#define ZIPFILE_F_COLUMN_IDX 6 /* Index of column "f" in the above */ |
| 4006 | +#define ZIPFILE_F_COLUMN_IDX 7 /* Index of column "f" in the above */ |
| 3901 | 4007 | #define ZIPFILE_BUFFER_SIZE (64*1024) |
| 3902 | 4008 | |
| 3903 | 4009 | |
| 3904 | 4010 | /* |
| 3905 | 4011 | ** Magic numbers used to read and write zip files. |
| | @@ -4513,10 +4619,84 @@ |
| 4513 | 4619 | pCds->mDate = (u16)( |
| 4514 | 4620 | (res.tm_mday-1) + |
| 4515 | 4621 | ((res.tm_mon+1) << 5) + |
| 4516 | 4622 | ((res.tm_year-80) << 9)); |
| 4517 | 4623 | } |
| 4624 | + |
| 4625 | +static void zipfileInflate( |
| 4626 | + sqlite3_context *pCtx, /* Store error here, if any */ |
| 4627 | + const u8 *aIn, /* Compressed data */ |
| 4628 | + int nIn, /* Size of buffer aIn[] in bytes */ |
| 4629 | + int nOut /* Expected output size */ |
| 4630 | +){ |
| 4631 | + u8 *aRes = sqlite3_malloc(nOut); |
| 4632 | + if( aRes==0 ){ |
| 4633 | + sqlite3_result_error_nomem(pCtx); |
| 4634 | + }else{ |
| 4635 | + int err; |
| 4636 | + z_stream str; |
| 4637 | + memset(&str, 0, sizeof(str)); |
| 4638 | + |
| 4639 | + str.next_in = (Byte*)aIn; |
| 4640 | + str.avail_in = nIn; |
| 4641 | + str.next_out = (Byte*)aRes; |
| 4642 | + str.avail_out = nOut; |
| 4643 | + |
| 4644 | + err = inflateInit2(&str, -15); |
| 4645 | + if( err!=Z_OK ){ |
| 4646 | + zipfileCtxErrorMsg(pCtx, "inflateInit2() failed (%d)", err); |
| 4647 | + }else{ |
| 4648 | + err = inflate(&str, Z_NO_FLUSH); |
| 4649 | + if( err!=Z_STREAM_END ){ |
| 4650 | + zipfileCtxErrorMsg(pCtx, "inflate() failed (%d)", err); |
| 4651 | + }else{ |
| 4652 | + sqlite3_result_blob(pCtx, aRes, nOut, SQLITE_TRANSIENT); |
| 4653 | + } |
| 4654 | + } |
| 4655 | + sqlite3_free(aRes); |
| 4656 | + inflateEnd(&str); |
| 4657 | + } |
| 4658 | +} |
| 4659 | + |
| 4660 | +static int zipfileDeflate( |
| 4661 | + ZipfileTab *pTab, /* Set error message here */ |
| 4662 | + const u8 *aIn, int nIn, /* Input */ |
| 4663 | + u8 **ppOut, int *pnOut /* Output */ |
| 4664 | +){ |
| 4665 | + int nAlloc = (int)compressBound(nIn); |
| 4666 | + u8 *aOut; |
| 4667 | + int rc = SQLITE_OK; |
| 4668 | + |
| 4669 | + aOut = (u8*)sqlite3_malloc(nAlloc); |
| 4670 | + if( aOut==0 ){ |
| 4671 | + rc = SQLITE_NOMEM; |
| 4672 | + }else{ |
| 4673 | + int res; |
| 4674 | + z_stream str; |
| 4675 | + memset(&str, 0, sizeof(str)); |
| 4676 | + str.next_in = (z_const Bytef*)aIn; |
| 4677 | + str.avail_in = nIn; |
| 4678 | + str.next_out = aOut; |
| 4679 | + str.avail_out = nAlloc; |
| 4680 | + |
| 4681 | + deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); |
| 4682 | + res = deflate(&str, Z_FINISH); |
| 4683 | + |
| 4684 | + if( res==Z_STREAM_END ){ |
| 4685 | + *ppOut = aOut; |
| 4686 | + *pnOut = (int)str.total_out; |
| 4687 | + }else{ |
| 4688 | + sqlite3_free(aOut); |
| 4689 | + pTab->base.zErrMsg = sqlite3_mprintf("zipfile: deflate() error"); |
| 4690 | + rc = SQLITE_ERROR; |
| 4691 | + } |
| 4692 | + deflateEnd(&str); |
| 4693 | + } |
| 4694 | + |
| 4695 | + return rc; |
| 4696 | +} |
| 4697 | + |
| 4518 | 4698 | |
| 4519 | 4699 | /* |
| 4520 | 4700 | ** Return values of columns for the row at which the series_cursor |
| 4521 | 4701 | ** is currently pointing. |
| 4522 | 4702 | */ |
| | @@ -4546,30 +4726,37 @@ |
| 4546 | 4726 | } |
| 4547 | 4727 | case 3: { /* sz */ |
| 4548 | 4728 | sqlite3_result_int64(ctx, pCsr->cds.szUncompressed); |
| 4549 | 4729 | break; |
| 4550 | 4730 | } |
| 4551 | | - case 4: { /* data */ |
| 4552 | | - int sz = pCsr->cds.szCompressed; |
| 4553 | | - if( sz>0 ){ |
| 4554 | | - u8 *aBuf = sqlite3_malloc(sz); |
| 4555 | | - if( aBuf==0 ){ |
| 4556 | | - rc = SQLITE_NOMEM; |
| 4557 | | - }else{ |
| 4558 | | - FILE *pFile = zipfileGetFd(pCsr); |
| 4559 | | - rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff, |
| 4560 | | - &pCsr->base.pVtab->zErrMsg |
| 4561 | | - ); |
| 4562 | | - } |
| 4563 | | - if( rc==SQLITE_OK ){ |
| 4564 | | - sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); |
| 4565 | | - sqlite3_free(aBuf); |
| 4731 | + case 4: /* rawdata */ |
| 4732 | + case 5: { /* data */ |
| 4733 | + if( i==4 || pCsr->cds.iCompression==0 || pCsr->cds.iCompression==8 ){ |
| 4734 | + int sz = pCsr->cds.szCompressed; |
| 4735 | + if( sz>0 ){ |
| 4736 | + u8 *aBuf = sqlite3_malloc(sz); |
| 4737 | + if( aBuf==0 ){ |
| 4738 | + rc = SQLITE_NOMEM; |
| 4739 | + }else{ |
| 4740 | + FILE *pFile = zipfileGetFd(pCsr); |
| 4741 | + rc = zipfileReadData(pFile, aBuf, sz, pCsr->iDataOff, |
| 4742 | + &pCsr->base.pVtab->zErrMsg |
| 4743 | + ); |
| 4744 | + } |
| 4745 | + if( rc==SQLITE_OK ){ |
| 4746 | + if( i==5 && pCsr->cds.iCompression ){ |
| 4747 | + zipfileInflate(ctx, aBuf, sz, pCsr->cds.szUncompressed); |
| 4748 | + }else{ |
| 4749 | + sqlite3_result_blob(ctx, aBuf, sz, SQLITE_TRANSIENT); |
| 4750 | + } |
| 4751 | + sqlite3_free(aBuf); |
| 4752 | + } |
| 4566 | 4753 | } |
| 4567 | 4754 | } |
| 4568 | 4755 | break; |
| 4569 | 4756 | } |
| 4570 | | - case 5: /* method */ |
| 4757 | + case 6: /* method */ |
| 4571 | 4758 | sqlite3_result_int(ctx, pCsr->cds.iCompression); |
| 4572 | 4759 | break; |
| 4573 | 4760 | } |
| 4574 | 4761 | |
| 4575 | 4762 | return SQLITE_OK; |
| | @@ -4794,11 +4981,11 @@ |
| 4794 | 4981 | if( pNew==0 ){ |
| 4795 | 4982 | rc = SQLITE_NOMEM; |
| 4796 | 4983 | }else{ |
| 4797 | 4984 | memset(pNew, 0, sizeof(ZipfileEntry)); |
| 4798 | 4985 | pNew->zPath = (char*)&pNew[1]; |
| 4799 | | - memcpy(pNew->zPath, &aBuf[ZIPFILE_CDS_FIXED_SZ], nFile); |
| 4986 | + memcpy(pNew->zPath, &aRec[ZIPFILE_CDS_FIXED_SZ], nFile); |
| 4800 | 4987 | pNew->zPath[nFile] = '\0'; |
| 4801 | 4988 | pNew->aCdsEntry = (u8*)&pNew->zPath[nFile+1]; |
| 4802 | 4989 | pNew->nCdsEntry = ZIPFILE_CDS_FIXED_SZ+nFile+nExtra+nComment; |
| 4803 | 4990 | memcpy(pNew->aCdsEntry, aRec, pNew->nCdsEntry); |
| 4804 | 4991 | zipfileAddEntry(pTab, pNew); |
| | @@ -4913,15 +5100,22 @@ |
| 4913 | 5100 | } |
| 4914 | 5101 | |
| 4915 | 5102 | return rc; |
| 4916 | 5103 | } |
| 4917 | 5104 | |
| 4918 | | -static int zipfileGetMode(ZipfileTab *pTab, sqlite3_value *pVal, int *pMode){ |
| 5105 | +static int zipfileGetMode( |
| 5106 | + ZipfileTab *pTab, |
| 5107 | + sqlite3_value *pVal, |
| 5108 | + u32 defaultMode, /* Value to use if pVal IS NULL */ |
| 5109 | + u32 *pMode |
| 5110 | +){ |
| 4919 | 5111 | const char *z = (const char*)sqlite3_value_text(pVal); |
| 4920 | | - int mode = 0; |
| 4921 | | - if( z==0 || (z[0]>=0 && z[0]<=9) ){ |
| 4922 | | - mode = sqlite3_value_int(pVal); |
| 5112 | + u32 mode = 0; |
| 5113 | + if( z==0 ){ |
| 5114 | + mode = defaultMode; |
| 5115 | + }else if( z[0]>=0 && z[0]<=9 ){ |
| 5116 | + mode = (unsigned int)sqlite3_value_int(pVal); |
| 4923 | 5117 | }else{ |
| 4924 | 5118 | const char zTemplate[11] = "-rwxrwxrwx"; |
| 4925 | 5119 | int i; |
| 4926 | 5120 | if( strlen(z)!=10 ) goto parse_error; |
| 4927 | 5121 | switch( z[0] ){ |
| | @@ -4942,10 +5136,22 @@ |
| 4942 | 5136 | |
| 4943 | 5137 | parse_error: |
| 4944 | 5138 | pTab->base.zErrMsg = sqlite3_mprintf("zipfile: parse error in mode: %s", z); |
| 4945 | 5139 | return SQLITE_ERROR; |
| 4946 | 5140 | } |
| 5141 | + |
| 5142 | +/* |
| 5143 | +** Both (const char*) arguments point to nul-terminated strings. Argument |
| 5144 | +** nB is the value of strlen(zB). This function returns 0 if the strings are |
| 5145 | +** identical, ignoring any trailing '/' character in either path. */ |
| 5146 | +static int zipfileComparePath(const char *zA, const char *zB, int nB){ |
| 5147 | + int nA = (int)strlen(zA); |
| 5148 | + if( zA[nA-1]=='/' ) nA--; |
| 5149 | + if( zB[nB-1]=='/' ) nB--; |
| 5150 | + if( nA==nB && memcmp(zA, zB, nA)==0 ) return 0; |
| 5151 | + return 1; |
| 5152 | +} |
| 4947 | 5153 | |
| 4948 | 5154 | /* |
| 4949 | 5155 | ** xUpdate method. |
| 4950 | 5156 | */ |
| 4951 | 5157 | static int zipfileUpdate( |
| | @@ -4956,79 +5162,138 @@ |
| 4956 | 5162 | ){ |
| 4957 | 5163 | ZipfileTab *pTab = (ZipfileTab*)pVtab; |
| 4958 | 5164 | int rc = SQLITE_OK; /* Return Code */ |
| 4959 | 5165 | ZipfileEntry *pNew = 0; /* New in-memory CDS entry */ |
| 4960 | 5166 | |
| 4961 | | - int mode; /* Mode for new entry */ |
| 4962 | | - i64 mTime; /* Modification time for new entry */ |
| 4963 | | - i64 sz; /* Uncompressed size */ |
| 4964 | | - const char *zPath; /* Path for new entry */ |
| 4965 | | - int nPath; /* strlen(zPath) */ |
| 4966 | | - const u8 *pData; /* Pointer to buffer containing content */ |
| 4967 | | - int nData; /* Size of pData buffer in bytes */ |
| 5167 | + u32 mode = 0; /* Mode for new entry */ |
| 5168 | + i64 mTime = 0; /* Modification time for new entry */ |
| 5169 | + i64 sz = 0; /* Uncompressed size */ |
| 5170 | + const char *zPath = 0; /* Path for new entry */ |
| 5171 | + int nPath = 0; /* strlen(zPath) */ |
| 5172 | + const u8 *pData = 0; /* Pointer to buffer containing content */ |
| 5173 | + int nData = 0; /* Size of pData buffer in bytes */ |
| 4968 | 5174 | int iMethod = 0; /* Compression method for new entry */ |
| 4969 | 5175 | u8 *pFree = 0; /* Free this */ |
| 5176 | + char *zFree = 0; /* Also free this */ |
| 4970 | 5177 | ZipfileCDS cds; /* New Central Directory Structure entry */ |
| 5178 | + |
| 5179 | + int bIsDir = 0; |
| 5180 | + |
| 5181 | + int mNull; |
| 4971 | 5182 | |
| 4972 | 5183 | assert( pTab->zFile ); |
| 4973 | 5184 | assert( pTab->pWriteFd ); |
| 4974 | 5185 | |
| 4975 | 5186 | if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 4976 | | - i64 iDelete = sqlite3_value_int64(apVal[0]); |
| 4977 | | - ZipfileEntry *p; |
| 4978 | | - for(p=pTab->pFirstEntry; p; p=p->pNext){ |
| 4979 | | - if( p->iRowid==iDelete ){ |
| 4980 | | - p->bDeleted = 1; |
| 4981 | | - break; |
| 4982 | | - } |
| 4983 | | - } |
| 4984 | | - if( nVal==1 ) return SQLITE_OK; |
| 4985 | | - } |
| 4986 | | - |
| 4987 | | - zPath = (const char*)sqlite3_value_text(apVal[2]); |
| 4988 | | - nPath = (int)strlen(zPath); |
| 4989 | | - rc = zipfileGetMode(pTab, apVal[3], &mode); |
| 4990 | | - if( rc!=SQLITE_OK ) return rc; |
| 4991 | | - mTime = sqlite3_value_int64(apVal[4]); |
| 4992 | | - sz = sqlite3_value_int(apVal[5]); |
| 4993 | | - pData = sqlite3_value_blob(apVal[6]); |
| 4994 | | - nData = sqlite3_value_bytes(apVal[6]); |
| 4995 | | - |
| 4996 | | - /* If a NULL value is inserted into the 'method' column, do automatic |
| 4997 | | - ** compression. */ |
| 4998 | | - if( nData>0 && sqlite3_value_type(apVal[7])==SQLITE_NULL ){ |
| 4999 | | - pFree = (u8*)sqlite3_malloc(nData); |
| 5000 | | - if( pFree==0 ){ |
| 5001 | | - rc = SQLITE_NOMEM; |
| 5002 | | - }else{ |
| 5003 | | - int res; |
| 5004 | | - z_stream str; |
| 5005 | | - memset(&str, 0, sizeof(str)); |
| 5006 | | - str.next_in = (z_const Bytef*)pData; |
| 5007 | | - str.avail_in = nData; |
| 5008 | | - str.next_out = pFree; |
| 5009 | | - str.avail_out = nData; |
| 5010 | | - deflateInit2(&str, 9, Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY); |
| 5011 | | - res = deflate(&str, Z_FINISH); |
| 5012 | | - if( res==Z_STREAM_END ){ |
| 5013 | | - pData = pFree; |
| 5014 | | - nData = str.total_out; |
| 5015 | | - iMethod = 8; |
| 5016 | | - }else if( res!=Z_OK ){ |
| 5017 | | - pTab->base.zErrMsg = sqlite3_mprintf("zipfile: deflate() error"); |
| 5018 | | - rc = SQLITE_ERROR; |
| 5019 | | - } |
| 5020 | | - deflateEnd(&str); |
| 5021 | | - } |
| 5022 | | - }else{ |
| 5023 | | - iMethod = sqlite3_value_int(apVal[7]); |
| 5187 | + if( nVal>1 ){ |
| 5188 | + return SQLITE_CONSTRAINT; |
| 5189 | + }else{ |
| 5190 | + i64 iDelete = sqlite3_value_int64(apVal[0]); |
| 5191 | + ZipfileEntry *p; |
| 5192 | + for(p=pTab->pFirstEntry; p; p=p->pNext){ |
| 5193 | + if( p->iRowid==iDelete ){ |
| 5194 | + p->bDeleted = 1; |
| 5195 | + break; |
| 5196 | + } |
| 5197 | + } |
| 5198 | + return SQLITE_OK; |
| 5199 | + } |
| 5200 | + } |
| 5201 | + |
| 5202 | + mNull = (sqlite3_value_type(apVal[5])==SQLITE_NULL ? 0x0 : 0x8) /* sz */ |
| 5203 | + + (sqlite3_value_type(apVal[6])==SQLITE_NULL ? 0x0 : 0x4) /* rawdata */ |
| 5204 | + + (sqlite3_value_type(apVal[7])==SQLITE_NULL ? 0x0 : 0x2) /* data */ |
| 5205 | + + (sqlite3_value_type(apVal[8])==SQLITE_NULL ? 0x0 : 0x1); /* method */ |
| 5206 | + if( mNull==0x00 ){ |
| 5207 | + /* All four are NULL - this must be a directory */ |
| 5208 | + bIsDir = 1; |
| 5209 | + } |
| 5210 | + else if( mNull==0x2 || mNull==0x3 ){ |
| 5211 | + /* Value specified for "data", and possibly "method". This must be |
| 5212 | + ** a regular file or a symlink. */ |
| 5213 | + const u8 *aIn = sqlite3_value_blob(apVal[7]); |
| 5214 | + int nIn = sqlite3_value_bytes(apVal[7]); |
| 5215 | + int bAuto = sqlite3_value_type(apVal[8])==SQLITE_NULL; |
| 5216 | + |
| 5217 | + iMethod = sqlite3_value_int(apVal[8]); |
| 5218 | + sz = nIn; |
| 5219 | + if( iMethod!=0 && iMethod!=8 ){ |
| 5220 | + rc = SQLITE_CONSTRAINT; |
| 5221 | + }else if( bAuto || iMethod ){ |
| 5222 | + rc = zipfileDeflate(pTab, aIn, nIn, &pFree, &nData); |
| 5223 | + if( rc==SQLITE_OK ){ |
| 5224 | + if( iMethod || nData<nIn ){ |
| 5225 | + iMethod = 8; |
| 5226 | + pData = pFree; |
| 5227 | + }else{ |
| 5228 | + pData = aIn; |
| 5229 | + nData = nIn; |
| 5230 | + } |
| 5231 | + } |
| 5232 | + } |
| 5233 | + } |
| 5234 | + else if( mNull==0x0D ){ |
| 5235 | + /* Values specified for "sz", "rawdata" and "method". In other words, |
| 5236 | + ** pre-compressed data is being inserted. */ |
| 5237 | + pData = sqlite3_value_blob(apVal[6]); |
| 5238 | + nData = sqlite3_value_bytes(apVal[6]); |
| 5239 | + sz = sqlite3_value_int(apVal[5]); |
| 5240 | + iMethod = sqlite3_value_int(apVal[8]); |
| 5024 | 5241 | if( iMethod<0 || iMethod>65535 ){ |
| 5025 | 5242 | pTab->base.zErrMsg = sqlite3_mprintf( |
| 5026 | 5243 | "zipfile: invalid compression method: %d", iMethod |
| 5027 | 5244 | ); |
| 5028 | 5245 | rc = SQLITE_ERROR; |
| 5029 | 5246 | } |
| 5247 | + } |
| 5248 | + else{ |
| 5249 | + rc = SQLITE_CONSTRAINT; |
| 5250 | + } |
| 5251 | + |
| 5252 | + if( rc==SQLITE_OK ){ |
| 5253 | + rc = zipfileGetMode(pTab, apVal[3], |
| 5254 | + (bIsDir ? (S_IFDIR + 0755) : (S_IFREG + 0644)), &mode |
| 5255 | + ); |
| 5256 | + if( rc==SQLITE_OK && (bIsDir == ((mode & S_IFDIR)==0)) ){ |
| 5257 | + /* The "mode" attribute is a directory, but data has been specified. |
| 5258 | + ** Or vice-versa - no data but "mode" is a file or symlink. */ |
| 5259 | + rc = SQLITE_CONSTRAINT; |
| 5260 | + } |
| 5261 | + } |
| 5262 | + |
| 5263 | + if( rc==SQLITE_OK ){ |
| 5264 | + zPath = (const char*)sqlite3_value_text(apVal[2]); |
| 5265 | + nPath = (int)strlen(zPath); |
| 5266 | + if( sqlite3_value_type(apVal[4])==SQLITE_NULL ){ |
| 5267 | + mTime = (sqlite3_int64)time(0); |
| 5268 | + }else{ |
| 5269 | + mTime = sqlite3_value_int64(apVal[4]); |
| 5270 | + } |
| 5271 | + } |
| 5272 | + |
| 5273 | + if( rc==SQLITE_OK && bIsDir ){ |
| 5274 | + /* For a directory, check that the last character in the path is a |
| 5275 | + ** '/'. This appears to be required for compatibility with info-zip |
| 5276 | + ** (the unzip command on unix). It does not create directories |
| 5277 | + ** otherwise. */ |
| 5278 | + if( zPath[nPath-1]!='/' ){ |
| 5279 | + zFree = sqlite3_mprintf("%s/", zPath); |
| 5280 | + if( zFree==0 ){ rc = SQLITE_NOMEM; } |
| 5281 | + zPath = (const char*)zFree; |
| 5282 | + nPath++; |
| 5283 | + } |
| 5284 | + } |
| 5285 | + |
| 5286 | + /* Check that we're not inserting a duplicate entry */ |
| 5287 | + if( rc==SQLITE_OK ){ |
| 5288 | + ZipfileEntry *p; |
| 5289 | + for(p=pTab->pFirstEntry; p; p=p->pNext){ |
| 5290 | + if( zipfileComparePath(p->zPath, zPath, nPath)==0 ){ |
| 5291 | + rc = SQLITE_CONSTRAINT; |
| 5292 | + break; |
| 5293 | + } |
| 5294 | + } |
| 5030 | 5295 | } |
| 5031 | 5296 | |
| 5032 | 5297 | if( rc==SQLITE_OK ){ |
| 5033 | 5298 | /* Create the new CDS record. */ |
| 5034 | 5299 | memset(&cds, 0, sizeof(cds)); |
| | @@ -5054,10 +5319,11 @@ |
| 5054 | 5319 | if( rc==SQLITE_OK ){ |
| 5055 | 5320 | rc = zipfileAppendEntry(pTab, &cds, zPath, nPath, pData, nData, (u32)mTime); |
| 5056 | 5321 | } |
| 5057 | 5322 | |
| 5058 | 5323 | sqlite3_free(pFree); |
| 5324 | + sqlite3_free(zFree); |
| 5059 | 5325 | return rc; |
| 5060 | 5326 | } |
| 5061 | 5327 | |
| 5062 | 5328 | static int zipfileAppendEOCD(ZipfileTab *pTab, ZipfileEOCD *p){ |
| 5063 | 5329 | u8 *aBuf = pTab->aBuffer; |
| | @@ -5195,74 +5461,22 @@ |
| 5195 | 5461 | } |
| 5196 | 5462 | #else /* SQLITE_OMIT_VIRTUALTABLE */ |
| 5197 | 5463 | # define zipfileRegister(x) SQLITE_OK |
| 5198 | 5464 | #endif |
| 5199 | 5465 | |
| 5200 | | -/* |
| 5201 | | -** zipfile_uncompress(DATA, SZ, METHOD) |
| 5202 | | -*/ |
| 5203 | | -static void zipfileUncompressFunc( |
| 5204 | | - sqlite3_context *context, |
| 5205 | | - int argc, |
| 5206 | | - sqlite3_value **argv |
| 5207 | | -){ |
| 5208 | | - int iMethod; |
| 5209 | | - |
| 5210 | | - iMethod = sqlite3_value_int(argv[2]); |
| 5211 | | - if( iMethod==0 ){ |
| 5212 | | - sqlite3_result_value(context, argv[0]); |
| 5213 | | - }else if( iMethod==8 ){ |
| 5214 | | - Byte *res; |
| 5215 | | - int sz = sqlite3_value_int(argv[1]); |
| 5216 | | - z_stream str; |
| 5217 | | - memset(&str, 0, sizeof(str)); |
| 5218 | | - str.next_in = (Byte*)sqlite3_value_blob(argv[0]); |
| 5219 | | - str.avail_in = sqlite3_value_bytes(argv[0]); |
| 5220 | | - res = str.next_out = (Byte*)sqlite3_malloc(sz); |
| 5221 | | - if( res==0 ){ |
| 5222 | | - sqlite3_result_error_nomem(context); |
| 5223 | | - }else{ |
| 5224 | | - int err; |
| 5225 | | - str.avail_out = sz; |
| 5226 | | - |
| 5227 | | - err = inflateInit2(&str, -15); |
| 5228 | | - if( err!=Z_OK ){ |
| 5229 | | - zipfileCtxErrorMsg(context, "inflateInit2() failed (%d)", err); |
| 5230 | | - }else{ |
| 5231 | | - err = inflate(&str, Z_NO_FLUSH); |
| 5232 | | - if( err!=Z_STREAM_END ){ |
| 5233 | | - zipfileCtxErrorMsg(context, "inflate() failed (%d)", err); |
| 5234 | | - }else{ |
| 5235 | | - sqlite3_result_blob(context, res, sz, SQLITE_TRANSIENT); |
| 5236 | | - } |
| 5237 | | - } |
| 5238 | | - sqlite3_free(res); |
| 5239 | | - inflateEnd(&str); |
| 5240 | | - } |
| 5241 | | - }else{ |
| 5242 | | - zipfileCtxErrorMsg(context, "unrecognized compression method: %d", iMethod); |
| 5243 | | - } |
| 5244 | | -} |
| 5245 | | - |
| 5246 | 5466 | #ifdef _WIN32 |
| 5247 | 5467 | |
| 5248 | 5468 | #endif |
| 5249 | 5469 | int sqlite3_zipfile_init( |
| 5250 | 5470 | sqlite3 *db, |
| 5251 | 5471 | char **pzErrMsg, |
| 5252 | 5472 | const sqlite3_api_routines *pApi |
| 5253 | 5473 | ){ |
| 5254 | | - int rc = SQLITE_OK; |
| 5255 | 5474 | SQLITE_EXTENSION_INIT2(pApi); |
| 5256 | 5475 | (void)pzErrMsg; /* Unused parameter */ |
| 5257 | | - rc = sqlite3_create_function(db, "zipfile_uncompress", 3, |
| 5258 | | - SQLITE_UTF8, 0, zipfileUncompressFunc, 0, 0 |
| 5259 | | - ); |
| 5260 | | - if( rc!=SQLITE_OK ) return rc; |
| 5261 | 5476 | return zipfileRegister(db); |
| 5262 | 5477 | } |
| 5263 | | - |
| 5264 | 5478 | |
| 5265 | 5479 | /************************* End ../ext/misc/zipfile.c ********************/ |
| 5266 | 5480 | /************************* Begin ../ext/misc/sqlar.c ******************/ |
| 5267 | 5481 | /* |
| 5268 | 5482 | ** 2017-12-17 |
| | @@ -5571,10 +5785,12 @@ |
| 5571 | 5785 | ************************************************************************* |
| 5572 | 5786 | */ |
| 5573 | 5787 | #include <assert.h> |
| 5574 | 5788 | #include <string.h> |
| 5575 | 5789 | #include <stdio.h> |
| 5790 | + |
| 5791 | +#ifndef SQLITE_OMIT_VIRTUALTABLE |
| 5576 | 5792 | |
| 5577 | 5793 | /* typedef sqlite3_int64 i64; */ |
| 5578 | 5794 | /* typedef sqlite3_uint64 u64; */ |
| 5579 | 5795 | |
| 5580 | 5796 | typedef struct IdxColumn IdxColumn; |
| | @@ -6052,11 +6268,11 @@ |
| 6052 | 6268 | } |
| 6053 | 6269 | } |
| 6054 | 6270 | } |
| 6055 | 6271 | } |
| 6056 | 6272 | |
| 6057 | | - pIdxInfo->estimatedCost = 1000000.0 / n; |
| 6273 | + pIdxInfo->estimatedCost = 1000000.0 / (n+1); |
| 6058 | 6274 | return rc; |
| 6059 | 6275 | } |
| 6060 | 6276 | |
| 6061 | 6277 | static int expertUpdate( |
| 6062 | 6278 | sqlite3_vtab *pVtab, |
| | @@ -6311,11 +6527,11 @@ |
| 6311 | 6527 | if( zAppend ){ |
| 6312 | 6528 | nAppend = STRLEN(zAppend); |
| 6313 | 6529 | zRet = (char*)sqlite3_malloc(nIn + nAppend + 1); |
| 6314 | 6530 | } |
| 6315 | 6531 | if( zAppend && zRet ){ |
| 6316 | | - memcpy(zRet, zIn, nIn); |
| 6532 | + if( nIn ) memcpy(zRet, zIn, nIn); |
| 6317 | 6533 | memcpy(&zRet[nIn], zAppend, nAppend+1); |
| 6318 | 6534 | }else{ |
| 6319 | 6535 | sqlite3_free(zRet); |
| 6320 | 6536 | zRet = 0; |
| 6321 | 6537 | *pRc = SQLITE_NOMEM; |
| | @@ -6465,11 +6681,11 @@ |
| 6465 | 6681 | if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){ |
| 6466 | 6682 | IdxTable *pTab = pScan->pTab; |
| 6467 | 6683 | char *zCols = 0; |
| 6468 | 6684 | char *zIdx = 0; |
| 6469 | 6685 | IdxConstraint *pCons; |
| 6470 | | - int h = 0; |
| 6686 | + unsigned int h = 0; |
| 6471 | 6687 | const char *zFmt; |
| 6472 | 6688 | |
| 6473 | 6689 | for(pCons=pEq; pCons; pCons=pCons->pLink){ |
| 6474 | 6690 | zCols = idxAppendColDefn(&rc, zCols, pTab, pCons); |
| 6475 | 6691 | } |
| | @@ -7080,10 +7296,11 @@ |
| 7080 | 7296 | zCols = idxAppendText(&rc, zCols, |
| 7081 | 7297 | "%sx.%Q IS rem(%d, x.%Q) COLLATE %s", zComma, zName, nCol, zName, zColl |
| 7082 | 7298 | ); |
| 7083 | 7299 | zOrder = idxAppendText(&rc, zOrder, "%s%d", zComma, ++nCol); |
| 7084 | 7300 | } |
| 7301 | + sqlite3_reset(pIndexXInfo); |
| 7085 | 7302 | if( rc==SQLITE_OK ){ |
| 7086 | 7303 | if( p->iSample==100 ){ |
| 7087 | 7304 | zQuery = sqlite3_mprintf( |
| 7088 | 7305 | "SELECT %s FROM %Q x ORDER BY %s", zCols, zTab, zOrder |
| 7089 | 7306 | ); |
| | @@ -7489,10 +7706,12 @@ |
| 7489 | 7706 | idxHashClear(&p->hIdx); |
| 7490 | 7707 | sqlite3_free(p->zCandidates); |
| 7491 | 7708 | sqlite3_free(p); |
| 7492 | 7709 | } |
| 7493 | 7710 | } |
| 7711 | + |
| 7712 | +#endif /* ifndef SQLITE_OMIT_VIRTUAL_TABLE */ |
| 7494 | 7713 | |
| 7495 | 7714 | /************************* End ../ext/expert/sqlite3expert.c ********************/ |
| 7496 | 7715 | |
| 7497 | 7716 | #if defined(SQLITE_ENABLE_SESSION) |
| 7498 | 7717 | /* |
| | @@ -7535,26 +7754,31 @@ |
| 7535 | 7754 | u8 autoExplain; /* Automatically turn on .explain mode */ |
| 7536 | 7755 | u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ |
| 7537 | 7756 | u8 statsOn; /* True to display memory stats before each finalize */ |
| 7538 | 7757 | u8 scanstatsOn; /* True to display scan stats before each finalize */ |
| 7539 | 7758 | u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ |
| 7759 | + u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ |
| 7540 | 7760 | int outCount; /* Revert to stdout when reaching zero */ |
| 7541 | 7761 | int cnt; /* Number of records displayed so far */ |
| 7542 | 7762 | FILE *out; /* Write results here */ |
| 7543 | 7763 | FILE *traceOut; /* Output for sqlite3_trace() */ |
| 7544 | 7764 | int nErr; /* Number of errors seen */ |
| 7545 | 7765 | int mode; /* An output mode setting */ |
| 7766 | + int modePrior; /* Saved mode */ |
| 7546 | 7767 | int cMode; /* temporary output mode for the current query */ |
| 7547 | 7768 | int normalMode; /* Output mode before ".explain on" */ |
| 7548 | 7769 | int writableSchema; /* True if PRAGMA writable_schema=ON */ |
| 7549 | 7770 | int showHeader; /* True to show column names in List or Column mode */ |
| 7550 | 7771 | int nCheck; /* Number of ".check" commands run */ |
| 7551 | 7772 | unsigned shellFlgs; /* Various flags */ |
| 7552 | 7773 | char *zDestTable; /* Name of destination table when MODE_Insert */ |
| 7774 | + char *zTempFile; /* Temporary file that might need deleting */ |
| 7553 | 7775 | char zTestcase[30]; /* Name of current test case */ |
| 7554 | 7776 | char colSeparator[20]; /* Column separator character for several modes */ |
| 7555 | 7777 | char rowSeparator[20]; /* Row separator character for MODE_Ascii */ |
| 7778 | + char colSepPrior[20]; /* Saved column separator */ |
| 7779 | + char rowSepPrior[20]; /* Saved row separator */ |
| 7556 | 7780 | int colWidth[100]; /* Requested width of each column when in column mode*/ |
| 7557 | 7781 | int actualWidth[100]; /* Actual width of each column */ |
| 7558 | 7782 | char nullValue[20]; /* The text to print when a NULL comes back from |
| 7559 | 7783 | ** the database */ |
| 7560 | 7784 | char outfile[FILENAME_MAX]; /* Filename for *out */ |
| | @@ -7648,24 +7872,175 @@ |
| 7648 | 7872 | #define SEP_Comma "," |
| 7649 | 7873 | #define SEP_CrLf "\r\n" |
| 7650 | 7874 | #define SEP_Unit "\x1F" |
| 7651 | 7875 | #define SEP_Record "\x1E" |
| 7652 | 7876 | |
| 7653 | | -/* |
| 7654 | | -** Number of elements in an array |
| 7655 | | -*/ |
| 7656 | | -#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0])) |
| 7657 | | - |
| 7658 | 7877 | /* |
| 7659 | 7878 | ** A callback for the sqlite3_log() interface. |
| 7660 | 7879 | */ |
| 7661 | 7880 | static void shellLog(void *pArg, int iErrCode, const char *zMsg){ |
| 7662 | 7881 | ShellState *p = (ShellState*)pArg; |
| 7663 | 7882 | if( p->pLog==0 ) return; |
| 7664 | 7883 | utf8_printf(p->pLog, "(%d) %s\n", iErrCode, zMsg); |
| 7665 | 7884 | fflush(p->pLog); |
| 7666 | 7885 | } |
| 7886 | + |
| 7887 | +/* |
| 7888 | +** SQL function: shell_putsnl(X) |
| 7889 | +** |
| 7890 | +** Write the text X to the screen (or whatever output is being directed) |
| 7891 | +** adding a newline at the end, and then return X. |
| 7892 | +*/ |
| 7893 | +static void shellPutsFunc( |
| 7894 | + sqlite3_context *pCtx, |
| 7895 | + int nVal, |
| 7896 | + sqlite3_value **apVal |
| 7897 | +){ |
| 7898 | + ShellState *p = (ShellState*)sqlite3_user_data(pCtx); |
| 7899 | + utf8_printf(p->out, "%s\n", sqlite3_value_text(apVal[0])); |
| 7900 | + sqlite3_result_value(pCtx, apVal[0]); |
| 7901 | +} |
| 7902 | + |
| 7903 | +/* |
| 7904 | +** SQL function: edit(VALUE) |
| 7905 | +** edit(VALUE,EDITOR) |
| 7906 | +** |
| 7907 | +** These steps: |
| 7908 | +** |
| 7909 | +** (1) Write VALUE into a temporary file. |
| 7910 | +** (2) Run program EDITOR on that temporary file. |
| 7911 | +** (3) Read the temporary file back and return its content as the result. |
| 7912 | +** (4) Delete the temporary file |
| 7913 | +** |
| 7914 | +** If the EDITOR argument is omitted, use the value in the VISUAL |
| 7915 | +** environment variable. If still there is no EDITOR, through an error. |
| 7916 | +** |
| 7917 | +** Also throw an error if the EDITOR program returns a non-zero exit code. |
| 7918 | +*/ |
| 7919 | +static void editFunc( |
| 7920 | + sqlite3_context *context, |
| 7921 | + int argc, |
| 7922 | + sqlite3_value **argv |
| 7923 | +){ |
| 7924 | + const char *zEditor; |
| 7925 | + char *zTempFile = 0; |
| 7926 | + sqlite3 *db; |
| 7927 | + char *zCmd = 0; |
| 7928 | + int bBin; |
| 7929 | + int rc; |
| 7930 | + FILE *f = 0; |
| 7931 | + sqlite3_int64 sz; |
| 7932 | + sqlite3_int64 x; |
| 7933 | + unsigned char *p = 0; |
| 7934 | + |
| 7935 | + if( argc==2 ){ |
| 7936 | + zEditor = (const char*)sqlite3_value_text(argv[1]); |
| 7937 | + }else{ |
| 7938 | + zEditor = getenv("VISUAL"); |
| 7939 | + } |
| 7940 | + if( zEditor==0 ){ |
| 7941 | + sqlite3_result_error(context, "no editor for edit()", -1); |
| 7942 | + return; |
| 7943 | + } |
| 7944 | + if( sqlite3_value_type(argv[0])==SQLITE_NULL ){ |
| 7945 | + sqlite3_result_error(context, "NULL input to edit()", -1); |
| 7946 | + return; |
| 7947 | + } |
| 7948 | + db = sqlite3_context_db_handle(context); |
| 7949 | + zTempFile = 0; |
| 7950 | + sqlite3_file_control(db, 0, SQLITE_FCNTL_TEMPFILENAME, &zTempFile); |
| 7951 | + if( zTempFile==0 ){ |
| 7952 | + sqlite3_uint64 r = 0; |
| 7953 | + sqlite3_randomness(sizeof(r), &r); |
| 7954 | + zTempFile = sqlite3_mprintf("temp%llx", r); |
| 7955 | + if( zTempFile==0 ){ |
| 7956 | + sqlite3_result_error_nomem(context); |
| 7957 | + return; |
| 7958 | + } |
| 7959 | + } |
| 7960 | + bBin = sqlite3_value_type(argv[0])==SQLITE_BLOB; |
| 7961 | + f = fopen(zTempFile, bBin ? "wb" : "w"); |
| 7962 | + if( f==0 ){ |
| 7963 | + sqlite3_result_error(context, "edit() cannot open temp file", -1); |
| 7964 | + goto edit_func_end; |
| 7965 | + } |
| 7966 | + sz = sqlite3_value_bytes(argv[0]); |
| 7967 | + if( bBin ){ |
| 7968 | + x = fwrite(sqlite3_value_blob(argv[0]), 1, sz, f); |
| 7969 | + }else{ |
| 7970 | + x = fwrite(sqlite3_value_text(argv[0]), 1, sz, f); |
| 7971 | + } |
| 7972 | + fclose(f); |
| 7973 | + f = 0; |
| 7974 | + if( x!=sz ){ |
| 7975 | + sqlite3_result_error(context, "edit() could not write the whole file", -1); |
| 7976 | + goto edit_func_end; |
| 7977 | + } |
| 7978 | + zCmd = sqlite3_mprintf("%s \"%s\"", zEditor, zTempFile); |
| 7979 | + if( zCmd==0 ){ |
| 7980 | + sqlite3_result_error_nomem(context); |
| 7981 | + goto edit_func_end; |
| 7982 | + } |
| 7983 | + rc = system(zCmd); |
| 7984 | + sqlite3_free(zCmd); |
| 7985 | + if( rc ){ |
| 7986 | + sqlite3_result_error(context, "EDITOR returned non-zero", -1); |
| 7987 | + goto edit_func_end; |
| 7988 | + } |
| 7989 | + f = fopen(zTempFile, bBin ? "rb" : "r"); |
| 7990 | + if( f==0 ){ |
| 7991 | + sqlite3_result_error(context, |
| 7992 | + "edit() cannot reopen temp file after edit", -1); |
| 7993 | + goto edit_func_end; |
| 7994 | + } |
| 7995 | + fseek(f, 0, SEEK_END); |
| 7996 | + sz = ftell(f); |
| 7997 | + rewind(f); |
| 7998 | + p = sqlite3_malloc64( sz+(bBin==0) ); |
| 7999 | + if( p==0 ){ |
| 8000 | + sqlite3_result_error_nomem(context); |
| 8001 | + goto edit_func_end; |
| 8002 | + } |
| 8003 | + if( bBin ){ |
| 8004 | + x = fread(p, 1, sz, f); |
| 8005 | + }else{ |
| 8006 | + x = fread(p, 1, sz, f); |
| 8007 | + p[sz] = 0; |
| 8008 | + } |
| 8009 | + fclose(f); |
| 8010 | + f = 0; |
| 8011 | + if( x!=sz ){ |
| 8012 | + sqlite3_result_error(context, "could not read back the whole file", -1); |
| 8013 | + goto edit_func_end; |
| 8014 | + } |
| 8015 | + if( bBin ){ |
| 8016 | + sqlite3_result_blob(context, p, sz, sqlite3_free); |
| 8017 | + }else{ |
| 8018 | + sqlite3_result_text(context, (const char*)p, sz, sqlite3_free); |
| 8019 | + } |
| 8020 | + p = 0; |
| 8021 | + |
| 8022 | +edit_func_end: |
| 8023 | + if( f ) fclose(f); |
| 8024 | + unlink(zTempFile); |
| 8025 | + sqlite3_free(zTempFile); |
| 8026 | + sqlite3_free(p); |
| 8027 | +} |
| 8028 | + |
| 8029 | +/* |
| 8030 | +** Save or restore the current output mode |
| 8031 | +*/ |
| 8032 | +static void outputModePush(ShellState *p){ |
| 8033 | + p->modePrior = p->mode; |
| 8034 | + memcpy(p->colSepPrior, p->colSeparator, sizeof(p->colSeparator)); |
| 8035 | + memcpy(p->rowSepPrior, p->rowSeparator, sizeof(p->rowSeparator)); |
| 8036 | +} |
| 8037 | +static void outputModePop(ShellState *p){ |
| 8038 | + p->mode = p->modePrior; |
| 8039 | + memcpy(p->colSeparator, p->colSepPrior, sizeof(p->colSeparator)); |
| 8040 | + memcpy(p->rowSeparator, p->rowSepPrior, sizeof(p->rowSeparator)); |
| 8041 | +} |
| 7667 | 8042 | |
| 7668 | 8043 | /* |
| 7669 | 8044 | ** Output the given string as a hex-encoded blob (eg. X'1234' ) |
| 7670 | 8045 | */ |
| 7671 | 8046 | static void output_hex_blob(FILE *out, const void *pBlob, int nBlob){ |
| | @@ -8987,10 +9362,11 @@ |
| 8987 | 9362 | } while( rc == SQLITE_ROW ); |
| 8988 | 9363 | } |
| 8989 | 9364 | } |
| 8990 | 9365 | } |
| 8991 | 9366 | |
| 9367 | +#ifndef SQLITE_OMIT_VIRTUALTABLE |
| 8992 | 9368 | /* |
| 8993 | 9369 | ** This function is called to process SQL if the previous shell command |
| 8994 | 9370 | ** was ".expert". It passes the SQL in the second argument directly to |
| 8995 | 9371 | ** the sqlite3expert object. |
| 8996 | 9372 | ** |
| | @@ -9059,10 +9435,67 @@ |
| 9059 | 9435 | sqlite3_expert_destroy(p); |
| 9060 | 9436 | pState->expert.pExpert = 0; |
| 9061 | 9437 | return rc; |
| 9062 | 9438 | } |
| 9063 | 9439 | |
| 9440 | +/* |
| 9441 | +** Implementation of ".expert" dot command. |
| 9442 | +*/ |
| 9443 | +static int expertDotCommand( |
| 9444 | + ShellState *pState, /* Current shell tool state */ |
| 9445 | + char **azArg, /* Array of arguments passed to dot command */ |
| 9446 | + int nArg /* Number of entries in azArg[] */ |
| 9447 | +){ |
| 9448 | + int rc = SQLITE_OK; |
| 9449 | + char *zErr = 0; |
| 9450 | + int i; |
| 9451 | + int iSample = 0; |
| 9452 | + |
| 9453 | + assert( pState->expert.pExpert==0 ); |
| 9454 | + memset(&pState->expert, 0, sizeof(ExpertInfo)); |
| 9455 | + |
| 9456 | + for(i=1; rc==SQLITE_OK && i<nArg; i++){ |
| 9457 | + char *z = azArg[i]; |
| 9458 | + int n; |
| 9459 | + if( z[0]=='-' && z[1]=='-' ) z++; |
| 9460 | + n = strlen30(z); |
| 9461 | + if( n>=2 && 0==strncmp(z, "-verbose", n) ){ |
| 9462 | + pState->expert.bVerbose = 1; |
| 9463 | + } |
| 9464 | + else if( n>=2 && 0==strncmp(z, "-sample", n) ){ |
| 9465 | + if( i==(nArg-1) ){ |
| 9466 | + raw_printf(stderr, "option requires an argument: %s\n", z); |
| 9467 | + rc = SQLITE_ERROR; |
| 9468 | + }else{ |
| 9469 | + iSample = (int)integerValue(azArg[++i]); |
| 9470 | + if( iSample<0 || iSample>100 ){ |
| 9471 | + raw_printf(stderr, "value out of range: %s\n", azArg[i]); |
| 9472 | + rc = SQLITE_ERROR; |
| 9473 | + } |
| 9474 | + } |
| 9475 | + } |
| 9476 | + else{ |
| 9477 | + raw_printf(stderr, "unknown option: %s\n", z); |
| 9478 | + rc = SQLITE_ERROR; |
| 9479 | + } |
| 9480 | + } |
| 9481 | + |
| 9482 | + if( rc==SQLITE_OK ){ |
| 9483 | + pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); |
| 9484 | + if( pState->expert.pExpert==0 ){ |
| 9485 | + raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr); |
| 9486 | + rc = SQLITE_ERROR; |
| 9487 | + }else{ |
| 9488 | + sqlite3_expert_config( |
| 9489 | + pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample |
| 9490 | + ); |
| 9491 | + } |
| 9492 | + } |
| 9493 | + |
| 9494 | + return rc; |
| 9495 | +} |
| 9496 | +#endif /* ifndef SQLITE_OMIT_VIRTUALTABLE */ |
| 9064 | 9497 | |
| 9065 | 9498 | /* |
| 9066 | 9499 | ** Execute a statement or set of statements. Print |
| 9067 | 9500 | ** any result rows/columns depending on the current mode |
| 9068 | 9501 | ** set via the supplied callback. |
| | @@ -9086,14 +9519,16 @@ |
| 9086 | 9519 | |
| 9087 | 9520 | if( pzErrMsg ){ |
| 9088 | 9521 | *pzErrMsg = NULL; |
| 9089 | 9522 | } |
| 9090 | 9523 | |
| 9524 | +#ifndef SQLITE_OMIT_VIRTUALTABLE |
| 9091 | 9525 | if( pArg->expert.pExpert ){ |
| 9092 | 9526 | rc = expertHandleSQL(pArg, zSql, pzErrMsg); |
| 9093 | 9527 | return expertFinish(pArg, (rc!=SQLITE_OK), pzErrMsg); |
| 9094 | 9528 | } |
| 9529 | +#endif |
| 9095 | 9530 | |
| 9096 | 9531 | while( zSql[0] && (SQLITE_OK == rc) ){ |
| 9097 | 9532 | static const char *zStmtSql; |
| 9098 | 9533 | rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, &zLeftover); |
| 9099 | 9534 | if( SQLITE_OK != rc ){ |
| | @@ -9516,10 +9951,11 @@ |
| 9516 | 9951 | ".dump ?TABLE? ... Dump the database in an SQL text format\n" |
| 9517 | 9952 | " If TABLE specified, only dump tables matching\n" |
| 9518 | 9953 | " LIKE pattern TABLE.\n" |
| 9519 | 9954 | ".echo on|off Turn command echo on or off\n" |
| 9520 | 9955 | ".eqp on|off|full Enable or disable automatic EXPLAIN QUERY PLAN\n" |
| 9956 | + ".excel Display the output of next command in a spreadsheet\n" |
| 9521 | 9957 | ".exit Exit this program\n" |
| 9522 | 9958 | ".expert EXPERIMENTAL. Suggest indexes for specified queries\n" |
| 9523 | 9959 | /* Because explain mode comes on automatically now, the ".explain" mode |
| 9524 | 9960 | ** is removed from the help screen. It is still supported for legacy, however */ |
| 9525 | 9961 | /*".explain ?on|off|auto? Turn EXPLAIN output mode on or off or to automatic\n"*/ |
| | @@ -9553,14 +9989,16 @@ |
| 9553 | 9989 | " list Values delimited by \"|\"\n" |
| 9554 | 9990 | " quote Escape answers as for SQL\n" |
| 9555 | 9991 | " tabs Tab-separated values\n" |
| 9556 | 9992 | " tcl TCL list elements\n" |
| 9557 | 9993 | ".nullvalue STRING Use STRING in place of NULL values\n" |
| 9558 | | - ".once FILENAME Output for the next SQL command only to FILENAME\n" |
| 9994 | + ".once (-e|-x|FILE) Output for the next SQL command only to FILE\n" |
| 9995 | + " or invoke system text editor (-e) or spreadsheet (-x)\n" |
| 9996 | + " on the output.\n" |
| 9559 | 9997 | ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE\n" |
| 9560 | 9998 | " The --new option starts with an empty file\n" |
| 9561 | | - ".output ?FILENAME? Send output to FILENAME or stdout\n" |
| 9999 | + ".output ?FILE? Send output to FILE or stdout\n" |
| 9562 | 10000 | ".print STRING... Print literal STRING\n" |
| 9563 | 10001 | ".prompt MAIN CONTINUE Replace the standard prompts\n" |
| 9564 | 10002 | ".quit Exit this program\n" |
| 9565 | 10003 | ".read FILENAME Execute SQL in FILENAME\n" |
| 9566 | 10004 | ".restore ?DB? FILE Restore content of DB (default \"main\") from FILE\n" |
| | @@ -9775,10 +10213,16 @@ |
| 9775 | 10213 | #endif |
| 9776 | 10214 | sqlite3_create_function(p->db, "shell_add_schema", 3, SQLITE_UTF8, 0, |
| 9777 | 10215 | shellAddSchemaName, 0, 0); |
| 9778 | 10216 | sqlite3_create_function(p->db, "shell_module_schema", 1, SQLITE_UTF8, 0, |
| 9779 | 10217 | shellModuleSchema, 0, 0); |
| 10218 | + sqlite3_create_function(p->db, "shell_putsnl", 1, SQLITE_UTF8, p, |
| 10219 | + shellPutsFunc, 0, 0); |
| 10220 | + sqlite3_create_function(p->db, "edit", 1, SQLITE_UTF8, 0, |
| 10221 | + editFunc, 0, 0); |
| 10222 | + sqlite3_create_function(p->db, "edit", 2, SQLITE_UTF8, 0, |
| 10223 | + editFunc, 0, 0); |
| 9780 | 10224 | if( p->openMode==SHELL_OPEN_ZIPFILE ){ |
| 9781 | 10225 | char *zSql = sqlite3_mprintf( |
| 9782 | 10226 | "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); |
| 9783 | 10227 | sqlite3_exec(p->db, zSql, 0, 0, 0); |
| 9784 | 10228 | sqlite3_free(zSql); |
| | @@ -9908,67 +10352,10 @@ |
| 9908 | 10352 | z[j] = c; |
| 9909 | 10353 | } |
| 9910 | 10354 | if( j<i ) z[j] = 0; |
| 9911 | 10355 | } |
| 9912 | 10356 | |
| 9913 | | -/* |
| 9914 | | -** Return the value of a hexadecimal digit. Return -1 if the input |
| 9915 | | -** is not a hex digit. |
| 9916 | | -*/ |
| 9917 | | -static int hexDigitValue(char c){ |
| 9918 | | - if( c>='0' && c<='9' ) return c - '0'; |
| 9919 | | - if( c>='a' && c<='f' ) return c - 'a' + 10; |
| 9920 | | - if( c>='A' && c<='F' ) return c - 'A' + 10; |
| 9921 | | - return -1; |
| 9922 | | -} |
| 9923 | | - |
| 9924 | | -/* |
| 9925 | | -** Interpret zArg as an integer value, possibly with suffixes. |
| 9926 | | -*/ |
| 9927 | | -static sqlite3_int64 integerValue(const char *zArg){ |
| 9928 | | - sqlite3_int64 v = 0; |
| 9929 | | - static const struct { char *zSuffix; int iMult; } aMult[] = { |
| 9930 | | - { "KiB", 1024 }, |
| 9931 | | - { "MiB", 1024*1024 }, |
| 9932 | | - { "GiB", 1024*1024*1024 }, |
| 9933 | | - { "KB", 1000 }, |
| 9934 | | - { "MB", 1000000 }, |
| 9935 | | - { "GB", 1000000000 }, |
| 9936 | | - { "K", 1000 }, |
| 9937 | | - { "M", 1000000 }, |
| 9938 | | - { "G", 1000000000 }, |
| 9939 | | - }; |
| 9940 | | - int i; |
| 9941 | | - int isNeg = 0; |
| 9942 | | - if( zArg[0]=='-' ){ |
| 9943 | | - isNeg = 1; |
| 9944 | | - zArg++; |
| 9945 | | - }else if( zArg[0]=='+' ){ |
| 9946 | | - zArg++; |
| 9947 | | - } |
| 9948 | | - if( zArg[0]=='0' && zArg[1]=='x' ){ |
| 9949 | | - int x; |
| 9950 | | - zArg += 2; |
| 9951 | | - while( (x = hexDigitValue(zArg[0]))>=0 ){ |
| 9952 | | - v = (v<<4) + x; |
| 9953 | | - zArg++; |
| 9954 | | - } |
| 9955 | | - }else{ |
| 9956 | | - while( IsDigit(zArg[0]) ){ |
| 9957 | | - v = v*10 + zArg[0] - '0'; |
| 9958 | | - zArg++; |
| 9959 | | - } |
| 9960 | | - } |
| 9961 | | - for(i=0; i<ArraySize(aMult); i++){ |
| 9962 | | - if( sqlite3_stricmp(aMult[i].zSuffix, zArg)==0 ){ |
| 9963 | | - v *= aMult[i].iMult; |
| 9964 | | - break; |
| 9965 | | - } |
| 9966 | | - } |
| 9967 | | - return isNeg? -v : v; |
| 9968 | | -} |
| 9969 | | - |
| 9970 | 10357 | /* |
| 9971 | 10358 | ** Interpret zArg as either an integer or a boolean value. Return 1 or 0 |
| 9972 | 10359 | ** for TRUE and FALSE. Return the integer value if appropriate. |
| 9973 | 10360 | */ |
| 9974 | 10361 | static int booleanValue(const char *zArg){ |
| | @@ -10011,20 +10398,20 @@ |
| 10011 | 10398 | /* |
| 10012 | 10399 | ** Try to open an output file. The names "stdout" and "stderr" are |
| 10013 | 10400 | ** recognized and do the right thing. NULL is returned if the output |
| 10014 | 10401 | ** filename is "off". |
| 10015 | 10402 | */ |
| 10016 | | -static FILE *output_file_open(const char *zFile){ |
| 10403 | +static FILE *output_file_open(const char *zFile, int bTextMode){ |
| 10017 | 10404 | FILE *f; |
| 10018 | 10405 | if( strcmp(zFile,"stdout")==0 ){ |
| 10019 | 10406 | f = stdout; |
| 10020 | 10407 | }else if( strcmp(zFile, "stderr")==0 ){ |
| 10021 | 10408 | f = stderr; |
| 10022 | 10409 | }else if( strcmp(zFile, "off")==0 ){ |
| 10023 | 10410 | f = 0; |
| 10024 | 10411 | }else{ |
| 10025 | | - f = fopen(zFile, "wb"); |
| 10412 | + f = fopen(zFile, bTextMode ? "w" : "wb"); |
| 10026 | 10413 | if( f==0 ){ |
| 10027 | 10414 | utf8_printf(stderr, "Error: cannot open \"%s\"\n", zFile); |
| 10028 | 10415 | } |
| 10029 | 10416 | } |
| 10030 | 10417 | return f; |
| | @@ -10433,19 +10820,41 @@ |
| 10433 | 10820 | } |
| 10434 | 10821 | sqlite3_close(newDb); |
| 10435 | 10822 | } |
| 10436 | 10823 | |
| 10437 | 10824 | /* |
| 10438 | | -** Change the output file back to stdout |
| 10825 | +** Change the output file back to stdout. |
| 10826 | +** |
| 10827 | +** If the p->doXdgOpen flag is set, that means the output was being |
| 10828 | +** redirected to a temporary file named by p->zTempFile. In that case, |
| 10829 | +** launch start/open/xdg-open on that temporary file. |
| 10439 | 10830 | */ |
| 10440 | 10831 | static void output_reset(ShellState *p){ |
| 10441 | 10832 | if( p->outfile[0]=='|' ){ |
| 10442 | 10833 | #ifndef SQLITE_OMIT_POPEN |
| 10443 | 10834 | pclose(p->out); |
| 10444 | 10835 | #endif |
| 10445 | 10836 | }else{ |
| 10446 | 10837 | output_file_close(p->out); |
| 10838 | + if( p->doXdgOpen ){ |
| 10839 | + const char *zXdgOpenCmd = |
| 10840 | +#if defined(_WIN32) |
| 10841 | + "start"; |
| 10842 | +#elif defined(__APPLE__) |
| 10843 | + "open"; |
| 10844 | +#else |
| 10845 | + "xdg-open"; |
| 10846 | +#endif |
| 10847 | + char *zCmd; |
| 10848 | + zCmd = sqlite3_mprintf("%s %s", zXdgOpenCmd, p->zTempFile); |
| 10849 | + if( system(zCmd) ){ |
| 10850 | + utf8_printf(stderr, "Failed: [%s]\n", zCmd); |
| 10851 | + } |
| 10852 | + sqlite3_free(zCmd); |
| 10853 | + outputModePop(p); |
| 10854 | + p->doXdgOpen = 0; |
| 10855 | + } |
| 10447 | 10856 | } |
| 10448 | 10857 | p->outfile[0] = 0; |
| 10449 | 10858 | p->out = stdout; |
| 10450 | 10859 | } |
| 10451 | 10860 | |
| | @@ -10699,10 +11108,45 @@ |
| 10699 | 11108 | #else |
| 10700 | 11109 | rc = unlink(zFilename); |
| 10701 | 11110 | #endif |
| 10702 | 11111 | return rc; |
| 10703 | 11112 | } |
| 11113 | + |
| 11114 | +/* |
| 11115 | +** Try to delete the temporary file (if there is one) and free the |
| 11116 | +** memory used to hold the name of the temp file. |
| 11117 | +*/ |
| 11118 | +static void clearTempFile(ShellState *p){ |
| 11119 | + if( p->zTempFile==0 ) return; |
| 11120 | + if( p->doXdgOpen ) return; |
| 11121 | + if( shellDeleteFile(p->zTempFile) ) return; |
| 11122 | + sqlite3_free(p->zTempFile); |
| 11123 | + p->zTempFile = 0; |
| 11124 | +} |
| 11125 | + |
| 11126 | +/* |
| 11127 | +** Create a new temp file name with the given suffix. |
| 11128 | +*/ |
| 11129 | +static void newTempFile(ShellState *p, const char *zSuffix){ |
| 11130 | + clearTempFile(p); |
| 11131 | + sqlite3_free(p->zTempFile); |
| 11132 | + p->zTempFile = 0; |
| 11133 | + if( p->db ){ |
| 11134 | + sqlite3_file_control(p->db, 0, SQLITE_FCNTL_TEMPFILENAME, &p->zTempFile); |
| 11135 | + } |
| 11136 | + if( p->zTempFile==0 ){ |
| 11137 | + sqlite3_uint64 r; |
| 11138 | + sqlite3_randomness(sizeof(r), &r); |
| 11139 | + p->zTempFile = sqlite3_mprintf("temp%llx.%s", r, zSuffix); |
| 11140 | + }else{ |
| 11141 | + p->zTempFile = sqlite3_mprintf("%z.%s", p->zTempFile, zSuffix); |
| 11142 | + } |
| 11143 | + if( p->zTempFile==0 ){ |
| 11144 | + raw_printf(stderr, "out of memory\n"); |
| 11145 | + exit(1); |
| 11146 | + } |
| 11147 | +} |
| 10704 | 11148 | |
| 10705 | 11149 | |
| 10706 | 11150 | /* |
| 10707 | 11151 | ** The implementation of SQL scalar function fkey_collate_clause(), used |
| 10708 | 11152 | ** by the ".lint fkey-indexes" command. This scalar function is always |
| | @@ -11028,17 +11472,22 @@ |
| 11028 | 11472 | /* |
| 11029 | 11473 | ** Structure representing a single ".ar" command. |
| 11030 | 11474 | */ |
| 11031 | 11475 | typedef struct ArCommand ArCommand; |
| 11032 | 11476 | struct ArCommand { |
| 11033 | | - int eCmd; /* An AR_CMD_* value */ |
| 11477 | + u8 eCmd; /* An AR_CMD_* value */ |
| 11478 | + u8 bVerbose; /* True if --verbose */ |
| 11479 | + u8 bZip; /* True if the archive is a ZIP */ |
| 11480 | + u8 bDryRun; /* True if --dry-run */ |
| 11481 | + u8 bAppend; /* True if --append */ |
| 11482 | + int nArg; /* Number of command arguments */ |
| 11483 | + char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ |
| 11034 | 11484 | const char *zFile; /* --file argument, or NULL */ |
| 11035 | 11485 | const char *zDir; /* --directory argument, or NULL */ |
| 11036 | | - int bVerbose; /* True if --verbose */ |
| 11037 | | - int bZip; /* True if --zip */ |
| 11038 | | - int nArg; /* Number of command arguments */ |
| 11039 | 11486 | char **azArg; /* Array of command arguments */ |
| 11487 | + ShellState *p; /* Shell state */ |
| 11488 | + sqlite3 *db; /* Database containing the archive */ |
| 11040 | 11489 | }; |
| 11041 | 11490 | |
| 11042 | 11491 | /* |
| 11043 | 11492 | ** Print a usage message for the .ar command to stderr and return SQLITE_ERROR. |
| 11044 | 11493 | */ |
| | @@ -11060,11 +11509,13 @@ |
| 11060 | 11509 | " -x, --extract Extract files from archive\n" |
| 11061 | 11510 | "\n" |
| 11062 | 11511 | "And zero or more optional options:\n" |
| 11063 | 11512 | " -v, --verbose Print each filename as it is processed\n" |
| 11064 | 11513 | " -f FILE, --file FILE Operate on archive FILE (default is current db)\n" |
| 11514 | +" -a FILE, --append FILE Operate on FILE opened using the apndvfs VFS\n" |
| 11065 | 11515 | " -C DIR, --directory DIR Change to directory DIR to read/extract files\n" |
| 11516 | +" -n, --dryrun Show the SQL that would have occurred\n" |
| 11066 | 11517 | "\n" |
| 11067 | 11518 | "See also: http://sqlite.org/cli.html#sqlar_archive_support\n" |
| 11068 | 11519 | "\n" |
| 11069 | 11520 | ); |
| 11070 | 11521 | return SQLITE_ERROR; |
| | @@ -11095,14 +11546,15 @@ |
| 11095 | 11546 | #define AR_CMD_HELP 5 |
| 11096 | 11547 | |
| 11097 | 11548 | /* |
| 11098 | 11549 | ** Other (non-command) switches. |
| 11099 | 11550 | */ |
| 11100 | | -#define AR_SWITCH_VERBOSE 6 |
| 11101 | | -#define AR_SWITCH_FILE 7 |
| 11102 | | -#define AR_SWITCH_DIRECTORY 8 |
| 11103 | | -#define AR_SWITCH_ZIP 9 |
| 11551 | +#define AR_SWITCH_VERBOSE 6 |
| 11552 | +#define AR_SWITCH_FILE 7 |
| 11553 | +#define AR_SWITCH_DIRECTORY 8 |
| 11554 | +#define AR_SWITCH_APPEND 9 |
| 11555 | +#define AR_SWITCH_DRYRUN 10 |
| 11104 | 11556 | |
| 11105 | 11557 | static int arProcessSwitch(ArCommand *pAr, int eSwitch, const char *zArg){ |
| 11106 | 11558 | switch( eSwitch ){ |
| 11107 | 11559 | case AR_CMD_CREATE: |
| 11108 | 11560 | case AR_CMD_EXTRACT: |
| | @@ -11113,17 +11565,19 @@ |
| 11113 | 11565 | return arErrorMsg("multiple command options"); |
| 11114 | 11566 | } |
| 11115 | 11567 | pAr->eCmd = eSwitch; |
| 11116 | 11568 | break; |
| 11117 | 11569 | |
| 11570 | + case AR_SWITCH_DRYRUN: |
| 11571 | + pAr->bDryRun = 1; |
| 11572 | + break; |
| 11118 | 11573 | case AR_SWITCH_VERBOSE: |
| 11119 | 11574 | pAr->bVerbose = 1; |
| 11120 | 11575 | break; |
| 11121 | | - case AR_SWITCH_ZIP: |
| 11122 | | - pAr->bZip = 1; |
| 11123 | | - break; |
| 11124 | | - |
| 11576 | + case AR_SWITCH_APPEND: |
| 11577 | + pAr->bAppend = 1; |
| 11578 | + /* Fall thru into --file */ |
| 11125 | 11579 | case AR_SWITCH_FILE: |
| 11126 | 11580 | pAr->zFile = zArg; |
| 11127 | 11581 | break; |
| 11128 | 11582 | case AR_SWITCH_DIRECTORY: |
| 11129 | 11583 | pAr->zDir = zArg; |
| | @@ -11143,24 +11597,25 @@ |
| 11143 | 11597 | char **azArg, /* Array of arguments passed to dot command */ |
| 11144 | 11598 | int nArg, /* Number of entries in azArg[] */ |
| 11145 | 11599 | ArCommand *pAr /* Populate this object */ |
| 11146 | 11600 | ){ |
| 11147 | 11601 | struct ArSwitch { |
| 11148 | | - char cShort; |
| 11149 | 11602 | const char *zLong; |
| 11150 | | - int eSwitch; |
| 11151 | | - int bArg; |
| 11603 | + char cShort; |
| 11604 | + u8 eSwitch; |
| 11605 | + u8 bArg; |
| 11152 | 11606 | } aSwitch[] = { |
| 11153 | | - { 'c', "create", AR_CMD_CREATE, 0 }, |
| 11154 | | - { 'x', "extract", AR_CMD_EXTRACT, 0 }, |
| 11155 | | - { 't', "list", AR_CMD_LIST, 0 }, |
| 11156 | | - { 'u', "update", AR_CMD_UPDATE, 0 }, |
| 11157 | | - { 'h', "help", AR_CMD_HELP, 0 }, |
| 11158 | | - { 'v', "verbose", AR_SWITCH_VERBOSE, 0 }, |
| 11159 | | - { 'f', "file", AR_SWITCH_FILE, 1 }, |
| 11160 | | - { 'C', "directory", AR_SWITCH_DIRECTORY, 1 }, |
| 11161 | | - { 'z', "zip", AR_SWITCH_ZIP, 0 } |
| 11607 | + { "create", 'c', AR_CMD_CREATE, 0 }, |
| 11608 | + { "extract", 'x', AR_CMD_EXTRACT, 0 }, |
| 11609 | + { "list", 't', AR_CMD_LIST, 0 }, |
| 11610 | + { "update", 'u', AR_CMD_UPDATE, 0 }, |
| 11611 | + { "help", 'h', AR_CMD_HELP, 0 }, |
| 11612 | + { "verbose", 'v', AR_SWITCH_VERBOSE, 0 }, |
| 11613 | + { "file", 'f', AR_SWITCH_FILE, 1 }, |
| 11614 | + { "append", 'a', AR_SWITCH_APPEND, 1 }, |
| 11615 | + { "directory", 'C', AR_SWITCH_DIRECTORY, 1 }, |
| 11616 | + { "dryrun", 'n', AR_SWITCH_DRYRUN, 0 }, |
| 11162 | 11617 | }; |
| 11163 | 11618 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); |
| 11164 | 11619 | struct ArSwitch *pEnd = &aSwitch[nSwitch]; |
| 11165 | 11620 | |
| 11166 | 11621 | if( nArg<=1 ){ |
| | @@ -11283,41 +11738,39 @@ |
| 11283 | 11738 | ** |
| 11284 | 11739 | ** This function strips any trailing '/' characters from each argument. |
| 11285 | 11740 | ** This is consistent with the way the [tar] command seems to work on |
| 11286 | 11741 | ** Linux. |
| 11287 | 11742 | */ |
| 11288 | | -static int arCheckEntries(sqlite3 *db, ArCommand *pAr){ |
| 11743 | +static int arCheckEntries(ArCommand *pAr){ |
| 11289 | 11744 | int rc = SQLITE_OK; |
| 11290 | 11745 | if( pAr->nArg ){ |
| 11291 | | - int i; |
| 11746 | + int i, j; |
| 11292 | 11747 | sqlite3_stmt *pTest = 0; |
| 11293 | 11748 | |
| 11294 | | - shellPreparePrintf(db, &rc, &pTest, "SELECT name FROM %s WHERE name=?1", |
| 11295 | | - pAr->bZip ? "zipfile(?2)" : "sqlar" |
| 11749 | + shellPreparePrintf(pAr->db, &rc, &pTest, |
| 11750 | + "SELECT name FROM %s WHERE name=$name", |
| 11751 | + pAr->zSrcTable |
| 11296 | 11752 | ); |
| 11297 | | - if( rc==SQLITE_OK && pAr->bZip ){ |
| 11298 | | - sqlite3_bind_text(pTest, 2, pAr->zFile, -1, SQLITE_TRANSIENT); |
| 11299 | | - } |
| 11753 | + j = sqlite3_bind_parameter_index(pTest, "$name"); |
| 11300 | 11754 | for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ |
| 11301 | 11755 | char *z = pAr->azArg[i]; |
| 11302 | 11756 | int n = strlen30(z); |
| 11303 | 11757 | int bOk = 0; |
| 11304 | 11758 | while( n>0 && z[n-1]=='/' ) n--; |
| 11305 | 11759 | z[n] = '\0'; |
| 11306 | | - sqlite3_bind_text(pTest, 1, z, -1, SQLITE_STATIC); |
| 11760 | + sqlite3_bind_text(pTest, j, z, -1, SQLITE_STATIC); |
| 11307 | 11761 | if( SQLITE_ROW==sqlite3_step(pTest) ){ |
| 11308 | 11762 | bOk = 1; |
| 11309 | 11763 | } |
| 11310 | 11764 | shellReset(&rc, pTest); |
| 11311 | 11765 | if( rc==SQLITE_OK && bOk==0 ){ |
| 11312 | | - raw_printf(stderr, "not found in archive: %s\n", z); |
| 11766 | + utf8_printf(stderr, "not found in archive: %s\n", z); |
| 11313 | 11767 | rc = SQLITE_ERROR; |
| 11314 | 11768 | } |
| 11315 | 11769 | } |
| 11316 | 11770 | shellFinalize(&rc, pTest); |
| 11317 | 11771 | } |
| 11318 | | - |
| 11319 | 11772 | return rc; |
| 11320 | 11773 | } |
| 11321 | 11774 | |
| 11322 | 11775 | /* |
| 11323 | 11776 | ** Format a WHERE clause that can be used against the "sqlar" table to |
| | @@ -11339,13 +11792,13 @@ |
| 11339 | 11792 | int i; |
| 11340 | 11793 | const char *zSep = ""; |
| 11341 | 11794 | for(i=0; i<pAr->nArg; i++){ |
| 11342 | 11795 | const char *z = pAr->azArg[i]; |
| 11343 | 11796 | zWhere = sqlite3_mprintf( |
| 11344 | | - "%z%s name = '%q' OR name BETWEEN '%q/' AND '%q0'", |
| 11345 | | - zWhere, zSep, z, z, z |
| 11346 | | - ); |
| 11797 | + "%z%s name = '%q' OR substr(name,1,%d) = '%q/'", |
| 11798 | + zWhere, zSep, z, strlen30(z)+1, z |
| 11799 | + ); |
| 11347 | 11800 | if( zWhere==0 ){ |
| 11348 | 11801 | *pRc = SQLITE_NOMEM; |
| 11349 | 11802 | break; |
| 11350 | 11803 | } |
| 11351 | 11804 | zSep = " OR "; |
| | @@ -11353,109 +11806,75 @@ |
| 11353 | 11806 | } |
| 11354 | 11807 | } |
| 11355 | 11808 | *pzWhere = zWhere; |
| 11356 | 11809 | } |
| 11357 | 11810 | |
| 11358 | | -/* |
| 11359 | | -** Argument zMode must point to a buffer at least 11 bytes in size. This |
| 11360 | | -** function populates this buffer with the string interpretation of |
| 11361 | | -** the unix file mode passed as the second argument (e.g. "drwxr-xr-x"). |
| 11362 | | -*/ |
| 11363 | | -static void shellModeToString(char *zMode, int mode){ |
| 11364 | | - int i; |
| 11365 | | - |
| 11366 | | - /* Magic numbers copied from [man 2 stat] */ |
| 11367 | | - if( mode & 0040000 ){ |
| 11368 | | - zMode[0] = 'd'; |
| 11369 | | - }else if( (mode & 0120000)==0120000 ){ |
| 11370 | | - zMode[0] = 'l'; |
| 11371 | | - }else{ |
| 11372 | | - zMode[0] = '-'; |
| 11373 | | - } |
| 11374 | | - |
| 11375 | | - for(i=0; i<3; i++){ |
| 11376 | | - int m = (mode >> ((2-i)*3)); |
| 11377 | | - char *a = &zMode[1 + i*3]; |
| 11378 | | - a[0] = (m & 0x4) ? 'r' : '-'; |
| 11379 | | - a[1] = (m & 0x2) ? 'w' : '-'; |
| 11380 | | - a[2] = (m & 0x1) ? 'x' : '-'; |
| 11381 | | - } |
| 11382 | | - zMode[10] = '\0'; |
| 11383 | | -} |
| 11384 | | - |
| 11385 | 11811 | /* |
| 11386 | 11812 | ** Implementation of .ar "lisT" command. |
| 11387 | 11813 | */ |
| 11388 | | -static int arListCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ |
| 11814 | +static int arListCommand(ArCommand *pAr){ |
| 11389 | 11815 | const char *zSql = "SELECT %s FROM %s WHERE %s"; |
| 11390 | | - const char *zTbl = (pAr->bZip ? "zipfile(?)" : "sqlar"); |
| 11391 | 11816 | const char *azCols[] = { |
| 11392 | 11817 | "name", |
| 11393 | | - "mode, sz, datetime(mtime, 'unixepoch'), name" |
| 11818 | + "lsmode(mode), sz, datetime(mtime, 'unixepoch'), name" |
| 11394 | 11819 | }; |
| 11395 | 11820 | |
| 11396 | 11821 | char *zWhere = 0; |
| 11397 | 11822 | sqlite3_stmt *pSql = 0; |
| 11398 | 11823 | int rc; |
| 11399 | 11824 | |
| 11400 | | - rc = arCheckEntries(db, pAr); |
| 11825 | + rc = arCheckEntries(pAr); |
| 11401 | 11826 | arWhereClause(&rc, pAr, &zWhere); |
| 11402 | 11827 | |
| 11403 | | - shellPreparePrintf(db, &rc, &pSql, zSql, azCols[pAr->bVerbose], zTbl, zWhere); |
| 11404 | | - if( rc==SQLITE_OK && pAr->bZip ){ |
| 11405 | | - sqlite3_bind_text(pSql, 1, pAr->zFile, -1, SQLITE_TRANSIENT); |
| 11406 | | - } |
| 11407 | | - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 11408 | | - if( pAr->bVerbose ){ |
| 11409 | | - char zMode[11]; |
| 11410 | | - shellModeToString(zMode, sqlite3_column_int(pSql, 0)); |
| 11411 | | - |
| 11412 | | - raw_printf(p->out, "%s % 10d %s %s\n", zMode, |
| 11413 | | - sqlite3_column_int(pSql, 1), |
| 11414 | | - sqlite3_column_text(pSql, 2), |
| 11415 | | - sqlite3_column_text(pSql, 3) |
| 11416 | | - ); |
| 11417 | | - }else{ |
| 11418 | | - raw_printf(p->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 11419 | | - } |
| 11420 | | - } |
| 11421 | | - |
| 11828 | + shellPreparePrintf(pAr->db, &rc, &pSql, zSql, azCols[pAr->bVerbose], |
| 11829 | + pAr->zSrcTable, zWhere); |
| 11830 | + if( pAr->bDryRun ){ |
| 11831 | + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); |
| 11832 | + }else{ |
| 11833 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 11834 | + if( pAr->bVerbose ){ |
| 11835 | + utf8_printf(pAr->p->out, "%s % 10d %s %s\n", |
| 11836 | + sqlite3_column_text(pSql, 0), |
| 11837 | + sqlite3_column_int(pSql, 1), |
| 11838 | + sqlite3_column_text(pSql, 2), |
| 11839 | + sqlite3_column_text(pSql, 3) |
| 11840 | + ); |
| 11841 | + }else{ |
| 11842 | + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 11843 | + } |
| 11844 | + } |
| 11845 | + } |
| 11422 | 11846 | shellFinalize(&rc, pSql); |
| 11423 | 11847 | return rc; |
| 11424 | 11848 | } |
| 11425 | 11849 | |
| 11426 | 11850 | |
| 11427 | 11851 | /* |
| 11428 | 11852 | ** Implementation of .ar "eXtract" command. |
| 11429 | 11853 | */ |
| 11430 | | -static int arExtractCommand(ShellState *p, sqlite3 *db, ArCommand *pAr){ |
| 11854 | +static int arExtractCommand(ArCommand *pAr){ |
| 11431 | 11855 | const char *zSql1 = |
| 11432 | 11856 | "SELECT " |
| 11433 | | - " :1 || name, " |
| 11434 | | - " writefile(?1 || name, %s, mode, mtime) " |
| 11435 | | - "FROM %s WHERE (%s) AND (data IS NULL OR ?2 = 0)"; |
| 11857 | + " ($dir || name)," |
| 11858 | + " writefile(($dir || name), %s, mode, mtime) " |
| 11859 | + "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)"; |
| 11436 | 11860 | |
| 11437 | 11861 | const char *azExtraArg[] = { |
| 11438 | 11862 | "sqlar_uncompress(data, sz)", |
| 11439 | | - "zipfile_uncompress(data, sz, method)" |
| 11863 | + "data" |
| 11440 | 11864 | }; |
| 11441 | | - const char *azSource[] = { |
| 11442 | | - "sqlar", "zipfile(?3)" |
| 11443 | | - }; |
| 11444 | | - |
| 11445 | | - |
| 11446 | 11865 | |
| 11447 | 11866 | sqlite3_stmt *pSql = 0; |
| 11448 | 11867 | int rc = SQLITE_OK; |
| 11449 | 11868 | char *zDir = 0; |
| 11450 | 11869 | char *zWhere = 0; |
| 11451 | | - int i; |
| 11870 | + int i, j; |
| 11452 | 11871 | |
| 11453 | 11872 | /* If arguments are specified, check that they actually exist within |
| 11454 | 11873 | ** the archive before proceeding. And formulate a WHERE clause to |
| 11455 | 11874 | ** match them. */ |
| 11456 | | - rc = arCheckEntries(db, pAr); |
| 11875 | + rc = arCheckEntries(pAr); |
| 11457 | 11876 | arWhereClause(&rc, pAr, &zWhere); |
| 11458 | 11877 | |
| 11459 | 11878 | if( rc==SQLITE_OK ){ |
| 11460 | 11879 | if( pAr->zDir ){ |
| 11461 | 11880 | zDir = sqlite3_mprintf("%s/", pAr->zDir); |
| | @@ -11463,30 +11882,33 @@ |
| 11463 | 11882 | zDir = sqlite3_mprintf(""); |
| 11464 | 11883 | } |
| 11465 | 11884 | if( zDir==0 ) rc = SQLITE_NOMEM; |
| 11466 | 11885 | } |
| 11467 | 11886 | |
| 11468 | | - shellPreparePrintf(db, &rc, &pSql, zSql1, |
| 11469 | | - azExtraArg[pAr->bZip], azSource[pAr->bZip], zWhere |
| 11887 | + shellPreparePrintf(pAr->db, &rc, &pSql, zSql1, |
| 11888 | + azExtraArg[pAr->bZip], pAr->zSrcTable, zWhere |
| 11470 | 11889 | ); |
| 11471 | 11890 | |
| 11472 | 11891 | if( rc==SQLITE_OK ){ |
| 11473 | | - sqlite3_bind_text(pSql, 1, zDir, -1, SQLITE_STATIC); |
| 11474 | | - if( pAr->bZip ){ |
| 11475 | | - sqlite3_bind_text(pSql, 3, pAr->zFile, -1, SQLITE_STATIC); |
| 11476 | | - } |
| 11892 | + j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 11893 | + sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 11477 | 11894 | |
| 11478 | 11895 | /* Run the SELECT statement twice. The first time, writefile() is called |
| 11479 | 11896 | ** for all archive members that should be extracted. The second time, |
| 11480 | 11897 | ** only for the directories. This is because the timestamps for |
| 11481 | 11898 | ** extracted directories must be reset after they are populated (as |
| 11482 | 11899 | ** populating them changes the timestamp). */ |
| 11483 | 11900 | for(i=0; i<2; i++){ |
| 11484 | | - sqlite3_bind_int(pSql, 2, i); |
| 11485 | | - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 11486 | | - if( i==0 && pAr->bVerbose ){ |
| 11487 | | - raw_printf(p->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 11901 | + j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); |
| 11902 | + sqlite3_bind_int(pSql, j, i); |
| 11903 | + if( pAr->bDryRun ){ |
| 11904 | + utf8_printf(pAr->p->out, "%s\n", sqlite3_sql(pSql)); |
| 11905 | + }else{ |
| 11906 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 11907 | + if( i==0 && pAr->bVerbose ){ |
| 11908 | + utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 11909 | + } |
| 11488 | 11910 | } |
| 11489 | 11911 | } |
| 11490 | 11912 | shellReset(&rc, pSql); |
| 11491 | 11913 | } |
| 11492 | 11914 | shellFinalize(&rc, pSql); |
| | @@ -11494,10 +11916,29 @@ |
| 11494 | 11916 | |
| 11495 | 11917 | sqlite3_free(zDir); |
| 11496 | 11918 | sqlite3_free(zWhere); |
| 11497 | 11919 | return rc; |
| 11498 | 11920 | } |
| 11921 | + |
| 11922 | +/* |
| 11923 | +** Run the SQL statement in zSql. Or if doing a --dryrun, merely print it out. |
| 11924 | +*/ |
| 11925 | +static int arExecSql(ArCommand *pAr, const char *zSql){ |
| 11926 | + int rc; |
| 11927 | + if( pAr->bDryRun ){ |
| 11928 | + utf8_printf(pAr->p->out, "%s\n", zSql); |
| 11929 | + rc = SQLITE_OK; |
| 11930 | + }else{ |
| 11931 | + char *zErr = 0; |
| 11932 | + rc = sqlite3_exec(pAr->db, zSql, 0, 0, &zErr); |
| 11933 | + if( zErr ){ |
| 11934 | + utf8_printf(stdout, "ERROR: %s\n", zErr); |
| 11935 | + sqlite3_free(zErr); |
| 11936 | + } |
| 11937 | + } |
| 11938 | + return rc; |
| 11939 | +} |
| 11499 | 11940 | |
| 11500 | 11941 | |
| 11501 | 11942 | /* |
| 11502 | 11943 | ** Implementation of .ar "create" and "update" commands. |
| 11503 | 11944 | ** |
| | @@ -11507,116 +11948,60 @@ |
| 11507 | 11948 | ** printed on stdout for each file archived. |
| 11508 | 11949 | ** |
| 11509 | 11950 | ** The create command is the same as update, except that it drops |
| 11510 | 11951 | ** any existing "sqlar" table before beginning. |
| 11511 | 11952 | */ |
| 11512 | | -static int arCreateUpdate( |
| 11513 | | - ShellState *p, /* Shell state pointer */ |
| 11514 | | - sqlite3 *db, |
| 11953 | +static int arCreateOrUpdateCommand( |
| 11515 | 11954 | ArCommand *pAr, /* Command arguments and options */ |
| 11516 | | - int bUpdate |
| 11955 | + int bUpdate /* true for a --create. false for --update */ |
| 11517 | 11956 | ){ |
| 11518 | | - const char *zSql = "SELECT name, mode, mtime, data FROM fsdir(?, ?)"; |
| 11519 | 11957 | const char *zCreate = |
| 11520 | 11958 | "CREATE TABLE IF NOT EXISTS sqlar(\n" |
| 11521 | 11959 | " name TEXT PRIMARY KEY, -- name of the file\n" |
| 11522 | 11960 | " mode INT, -- access permissions\n" |
| 11523 | 11961 | " mtime INT, -- last modification time\n" |
| 11524 | 11962 | " sz INT, -- original file size\n" |
| 11525 | 11963 | " data BLOB -- compressed content\n" |
| 11526 | 11964 | ")"; |
| 11527 | 11965 | const char *zDrop = "DROP TABLE IF EXISTS sqlar"; |
| 11528 | | - const char *zInsert = "REPLACE INTO sqlar VALUES(?,?,?,?,sqlar_compress(?))"; |
| 11529 | | - |
| 11530 | | - sqlite3_stmt *pStmt = 0; /* Directory traverser */ |
| 11531 | | - sqlite3_stmt *pInsert = 0; /* Compilation of zInsert */ |
| 11966 | + const char *zInsertFmt = |
| 11967 | + "REPLACE INTO sqlar(name,mode,mtime,sz,data)\n" |
| 11968 | + " SELECT\n" |
| 11969 | + " %s,\n" |
| 11970 | + " mode,\n" |
| 11971 | + " mtime,\n" |
| 11972 | + " CASE substr(lsmode(mode),1,1)\n" |
| 11973 | + " WHEN '-' THEN length(data)\n" |
| 11974 | + " WHEN 'd' THEN 0\n" |
| 11975 | + " ELSE -1 END,\n" |
| 11976 | + " CASE WHEN lsmode(mode) LIKE 'd%%' THEN NULL else data END\n" |
| 11977 | + " FROM fsdir(%Q,%Q)\n" |
| 11978 | + " WHERE lsmode(mode) NOT LIKE '?%%';"; |
| 11532 | 11979 | int i; /* For iterating through azFile[] */ |
| 11533 | 11980 | int rc; /* Return code */ |
| 11534 | 11981 | |
| 11535 | | - assert( pAr->bZip==0 ); |
| 11536 | | - |
| 11537 | | - rc = sqlite3_exec(db, "SAVEPOINT ar;", 0, 0, 0); |
| 11538 | | - if( rc!=SQLITE_OK ) return rc; |
| 11539 | | - |
| 11540 | | - if( bUpdate==0 ){ |
| 11541 | | - rc = sqlite3_exec(db, zDrop, 0, 0, 0); |
| 11542 | | - if( rc!=SQLITE_OK ) return rc; |
| 11543 | | - } |
| 11544 | | - |
| 11545 | | - rc = sqlite3_exec(db, zCreate, 0, 0, 0); |
| 11546 | | - shellPrepare(db, &rc, zInsert, &pInsert); |
| 11547 | | - shellPrepare(db, &rc, zSql, &pStmt); |
| 11548 | | - sqlite3_bind_text(pStmt, 2, pAr->zDir, -1, SQLITE_STATIC); |
| 11549 | | - |
| 11550 | | - for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ |
| 11551 | | - sqlite3_bind_text(pStmt, 1, pAr->azArg[i], -1, SQLITE_STATIC); |
| 11552 | | - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 11553 | | - int sz; |
| 11554 | | - const char *zName = (const char*)sqlite3_column_text(pStmt, 0); |
| 11555 | | - int mode = sqlite3_column_int(pStmt, 1); |
| 11556 | | - unsigned int mtime = sqlite3_column_int(pStmt, 2); |
| 11557 | | - |
| 11558 | | - if( pAr->bVerbose ){ |
| 11559 | | - raw_printf(p->out, "%s\n", zName); |
| 11560 | | - } |
| 11561 | | - |
| 11562 | | - sqlite3_bind_text(pInsert, 1, zName, -1, SQLITE_STATIC); |
| 11563 | | - sqlite3_bind_int(pInsert, 2, mode); |
| 11564 | | - sqlite3_bind_int64(pInsert, 3, (sqlite3_int64)mtime); |
| 11565 | | - |
| 11566 | | - if( S_ISDIR(mode) ){ |
| 11567 | | - sz = 0; |
| 11568 | | - sqlite3_bind_null(pInsert, 5); |
| 11569 | | - }else{ |
| 11570 | | - sqlite3_bind_value(pInsert, 5, sqlite3_column_value(pStmt, 3)); |
| 11571 | | - if( S_ISLNK(mode) ){ |
| 11572 | | - sz = -1; |
| 11573 | | - }else{ |
| 11574 | | - sz = sqlite3_column_bytes(pStmt, 3); |
| 11575 | | - } |
| 11576 | | - } |
| 11577 | | - |
| 11578 | | - sqlite3_bind_int(pInsert, 4, sz); |
| 11579 | | - sqlite3_step(pInsert); |
| 11580 | | - rc = sqlite3_reset(pInsert); |
| 11581 | | - } |
| 11582 | | - shellReset(&rc, pStmt); |
| 11583 | | - } |
| 11584 | | - |
| 11585 | | - if( rc!=SQLITE_OK ){ |
| 11586 | | - sqlite3_exec(db, "ROLLBACK TO ar; RELEASE ar;", 0, 0, 0); |
| 11587 | | - }else{ |
| 11588 | | - rc = sqlite3_exec(db, "RELEASE ar;", 0, 0, 0); |
| 11589 | | - } |
| 11590 | | - shellFinalize(&rc, pStmt); |
| 11591 | | - shellFinalize(&rc, pInsert); |
| 11592 | | - return rc; |
| 11593 | | -} |
| 11594 | | - |
| 11595 | | -/* |
| 11596 | | -** Implementation of .ar "Create" command. |
| 11597 | | -** |
| 11598 | | -** Create the "sqlar" table in the database if it does not already exist. |
| 11599 | | -** Then add each file in the azFile[] array to the archive. Directories |
| 11600 | | -** are added recursively. If argument bVerbose is non-zero, a message is |
| 11601 | | -** printed on stdout for each file archived. |
| 11602 | | -*/ |
| 11603 | | -static int arCreateCommand( |
| 11604 | | - ShellState *p, /* Shell state pointer */ |
| 11605 | | - sqlite3 *db, |
| 11606 | | - ArCommand *pAr /* Command arguments and options */ |
| 11607 | | -){ |
| 11608 | | - return arCreateUpdate(p, db, pAr, 0); |
| 11609 | | -} |
| 11610 | | - |
| 11611 | | -/* |
| 11612 | | -** Implementation of .ar "Update" command. |
| 11613 | | -*/ |
| 11614 | | -static int arUpdateCmd(ShellState *p, sqlite3 *db, ArCommand *pAr){ |
| 11615 | | - return arCreateUpdate(p, db, pAr, 1); |
| 11616 | | -} |
| 11617 | | - |
| 11982 | + rc = arExecSql(pAr, "SAVEPOINT ar;"); |
| 11983 | + if( rc!=SQLITE_OK ) return rc; |
| 11984 | + if( bUpdate==0 ){ |
| 11985 | + rc = arExecSql(pAr, zDrop); |
| 11986 | + if( rc!=SQLITE_OK ) return rc; |
| 11987 | + } |
| 11988 | + rc = arExecSql(pAr, zCreate); |
| 11989 | + for(i=0; i<pAr->nArg && rc==SQLITE_OK; i++){ |
| 11990 | + char *zSql = sqlite3_mprintf(zInsertFmt, |
| 11991 | + pAr->bVerbose ? "shell_putsnl(name)" : "name", |
| 11992 | + pAr->azArg[i], pAr->zDir); |
| 11993 | + rc = arExecSql(pAr, zSql); |
| 11994 | + sqlite3_free(zSql); |
| 11995 | + } |
| 11996 | + if( rc!=SQLITE_OK ){ |
| 11997 | + arExecSql(pAr, "ROLLBACK TO ar; RELEASE ar;"); |
| 11998 | + }else{ |
| 11999 | + rc = arExecSql(pAr, "RELEASE ar;"); |
| 12000 | + } |
| 12001 | + return rc; |
| 12002 | +} |
| 11618 | 12003 | |
| 11619 | 12004 | /* |
| 11620 | 12005 | ** Implementation of ".ar" dot command. |
| 11621 | 12006 | */ |
| 11622 | 12007 | static int arDotCommand( |
| | @@ -11624,138 +12009,108 @@ |
| 11624 | 12009 | char **azArg, /* Array of arguments passed to dot command */ |
| 11625 | 12010 | int nArg /* Number of entries in azArg[] */ |
| 11626 | 12011 | ){ |
| 11627 | 12012 | ArCommand cmd; |
| 11628 | 12013 | int rc; |
| 12014 | + memset(&cmd, 0, sizeof(cmd)); |
| 11629 | 12015 | rc = arParseCommand(azArg, nArg, &cmd); |
| 11630 | 12016 | if( rc==SQLITE_OK ){ |
| 11631 | | - sqlite3 *db = 0; /* Database handle to use as archive */ |
| 11632 | | - |
| 11633 | | - if( cmd.bZip ){ |
| 12017 | + int eDbType = SHELL_OPEN_UNSPEC; |
| 12018 | + cmd.p = pState; |
| 12019 | + cmd.db = pState->db; |
| 12020 | + if( cmd.zFile ){ |
| 12021 | + eDbType = deduceDatabaseType(cmd.zFile); |
| 12022 | + }else{ |
| 12023 | + eDbType = pState->openMode; |
| 12024 | + } |
| 12025 | + if( eDbType==SHELL_OPEN_ZIPFILE ){ |
| 11634 | 12026 | if( cmd.zFile==0 ){ |
| 11635 | | - raw_printf(stderr, "zip format requires a --file switch\n"); |
| 11636 | | - return SQLITE_ERROR; |
| 11637 | | - }else |
| 12027 | + cmd.zSrcTable = sqlite3_mprintf("zip"); |
| 12028 | + }else{ |
| 12029 | + cmd.zSrcTable = sqlite3_mprintf("zipfile(%Q)", cmd.zFile); |
| 12030 | + } |
| 11638 | 12031 | if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){ |
| 11639 | | - raw_printf(stderr, "zip archives are read-only\n"); |
| 11640 | | - return SQLITE_ERROR; |
| 12032 | + utf8_printf(stderr, "zip archives are read-only\n"); |
| 12033 | + rc = SQLITE_ERROR; |
| 12034 | + goto end_ar_command; |
| 11641 | 12035 | } |
| 11642 | | - db = pState->db; |
| 12036 | + cmd.bZip = 1; |
| 11643 | 12037 | }else if( cmd.zFile ){ |
| 11644 | 12038 | int flags; |
| 12039 | + if( cmd.bAppend ) eDbType = SHELL_OPEN_APPENDVFS; |
| 11645 | 12040 | if( cmd.eCmd==AR_CMD_CREATE || cmd.eCmd==AR_CMD_UPDATE ){ |
| 11646 | 12041 | flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; |
| 11647 | 12042 | }else{ |
| 11648 | 12043 | flags = SQLITE_OPEN_READONLY; |
| 11649 | 12044 | } |
| 11650 | | - rc = sqlite3_open_v2(cmd.zFile, &db, flags, 0); |
| 12045 | + cmd.db = 0; |
| 12046 | + if( cmd.bDryRun ){ |
| 12047 | + utf8_printf(pState->out, "-- open database '%s'%s\n", cmd.zFile, |
| 12048 | + eDbType==SHELL_OPEN_APPENDVFS ? " using 'apndvfs'" : ""); |
| 12049 | + } |
| 12050 | + rc = sqlite3_open_v2(cmd.zFile, &cmd.db, flags, |
| 12051 | + eDbType==SHELL_OPEN_APPENDVFS ? "apndvfs" : 0); |
| 11651 | 12052 | if( rc!=SQLITE_OK ){ |
| 11652 | | - raw_printf(stderr, "cannot open file: %s (%s)\n", |
| 11653 | | - cmd.zFile, sqlite3_errmsg(db) |
| 12053 | + utf8_printf(stderr, "cannot open file: %s (%s)\n", |
| 12054 | + cmd.zFile, sqlite3_errmsg(cmd.db) |
| 11654 | 12055 | ); |
| 11655 | | - sqlite3_close(db); |
| 11656 | | - return rc; |
| 12056 | + goto end_ar_command; |
| 11657 | 12057 | } |
| 11658 | | - sqlite3_fileio_init(db, 0, 0); |
| 12058 | + sqlite3_fileio_init(cmd.db, 0, 0); |
| 11659 | 12059 | #ifdef SQLITE_HAVE_ZLIB |
| 11660 | | - sqlite3_sqlar_init(db, 0, 0); |
| 12060 | + sqlite3_sqlar_init(cmd.db, 0, 0); |
| 11661 | 12061 | #endif |
| 11662 | | - }else{ |
| 11663 | | - db = pState->db; |
| 12062 | + sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, |
| 12063 | + shellPutsFunc, 0, 0); |
| 12064 | + |
| 12065 | + } |
| 12066 | + if( cmd.zSrcTable==0 ){ |
| 12067 | + if( cmd.eCmd!=AR_CMD_CREATE |
| 12068 | + && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) |
| 12069 | + ){ |
| 12070 | + utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); |
| 12071 | + rc = SQLITE_ERROR; |
| 12072 | + goto end_ar_command; |
| 12073 | + } |
| 12074 | + cmd.zSrcTable = sqlite3_mprintf("sqlar"); |
| 11664 | 12075 | } |
| 11665 | 12076 | |
| 11666 | 12077 | switch( cmd.eCmd ){ |
| 11667 | 12078 | case AR_CMD_CREATE: |
| 11668 | | - rc = arCreateCommand(pState, db, &cmd); |
| 12079 | + rc = arCreateOrUpdateCommand(&cmd, 0); |
| 11669 | 12080 | break; |
| 11670 | 12081 | |
| 11671 | 12082 | case AR_CMD_EXTRACT: |
| 11672 | | - rc = arExtractCommand(pState, db, &cmd); |
| 12083 | + rc = arExtractCommand(&cmd); |
| 11673 | 12084 | break; |
| 11674 | 12085 | |
| 11675 | 12086 | case AR_CMD_LIST: |
| 11676 | | - rc = arListCommand(pState, db, &cmd); |
| 12087 | + rc = arListCommand(&cmd); |
| 11677 | 12088 | break; |
| 11678 | 12089 | |
| 11679 | 12090 | case AR_CMD_HELP: |
| 11680 | 12091 | arUsage(pState->out); |
| 11681 | 12092 | break; |
| 11682 | 12093 | |
| 11683 | 12094 | default: |
| 11684 | 12095 | assert( cmd.eCmd==AR_CMD_UPDATE ); |
| 11685 | | - rc = arUpdateCmd(pState, db, &cmd); |
| 12096 | + rc = arCreateOrUpdateCommand(&cmd, 1); |
| 11686 | 12097 | break; |
| 11687 | 12098 | } |
| 11688 | | - |
| 11689 | | - if( cmd.zFile ){ |
| 11690 | | - sqlite3_close(db); |
| 11691 | | - } |
| 12099 | + } |
| 12100 | +end_ar_command: |
| 12101 | + if( cmd.db!=pState->db ){ |
| 12102 | + sqlite3_close(cmd.db); |
| 11692 | 12103 | } |
| 12104 | + sqlite3_free(cmd.zSrcTable); |
| 11693 | 12105 | |
| 11694 | 12106 | return rc; |
| 11695 | 12107 | } |
| 11696 | 12108 | /* End of the ".archive" or ".ar" command logic |
| 11697 | 12109 | **********************************************************************************/ |
| 11698 | 12110 | #endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) */ |
| 11699 | 12111 | |
| 11700 | | -/* |
| 11701 | | -** Implementation of ".expert" dot command. |
| 11702 | | -*/ |
| 11703 | | -static int expertDotCommand( |
| 11704 | | - ShellState *pState, /* Current shell tool state */ |
| 11705 | | - char **azArg, /* Array of arguments passed to dot command */ |
| 11706 | | - int nArg /* Number of entries in azArg[] */ |
| 11707 | | -){ |
| 11708 | | - int rc = SQLITE_OK; |
| 11709 | | - char *zErr = 0; |
| 11710 | | - int i; |
| 11711 | | - int iSample = 0; |
| 11712 | | - |
| 11713 | | - assert( pState->expert.pExpert==0 ); |
| 11714 | | - memset(&pState->expert, 0, sizeof(ExpertInfo)); |
| 11715 | | - |
| 11716 | | - for(i=1; rc==SQLITE_OK && i<nArg; i++){ |
| 11717 | | - char *z = azArg[i]; |
| 11718 | | - int n; |
| 11719 | | - if( z[0]=='-' && z[1]=='-' ) z++; |
| 11720 | | - n = strlen30(z); |
| 11721 | | - if( n>=2 && 0==strncmp(z, "-verbose", n) ){ |
| 11722 | | - pState->expert.bVerbose = 1; |
| 11723 | | - } |
| 11724 | | - else if( n>=2 && 0==strncmp(z, "-sample", n) ){ |
| 11725 | | - if( i==(nArg-1) ){ |
| 11726 | | - raw_printf(stderr, "option requires an argument: %s\n", z); |
| 11727 | | - rc = SQLITE_ERROR; |
| 11728 | | - }else{ |
| 11729 | | - iSample = (int)integerValue(azArg[++i]); |
| 11730 | | - if( iSample<0 || iSample>100 ){ |
| 11731 | | - raw_printf(stderr, "value out of range: %s\n", azArg[i]); |
| 11732 | | - rc = SQLITE_ERROR; |
| 11733 | | - } |
| 11734 | | - } |
| 11735 | | - } |
| 11736 | | - else{ |
| 11737 | | - raw_printf(stderr, "unknown option: %s\n", z); |
| 11738 | | - rc = SQLITE_ERROR; |
| 11739 | | - } |
| 11740 | | - } |
| 11741 | | - |
| 11742 | | - if( rc==SQLITE_OK ){ |
| 11743 | | - pState->expert.pExpert = sqlite3_expert_new(pState->db, &zErr); |
| 11744 | | - if( pState->expert.pExpert==0 ){ |
| 11745 | | - raw_printf(stderr, "sqlite3_expert_new: %s\n", zErr); |
| 11746 | | - rc = SQLITE_ERROR; |
| 11747 | | - }else{ |
| 11748 | | - sqlite3_expert_config( |
| 11749 | | - pState->expert.pExpert, EXPERT_CONFIG_SAMPLE, iSample |
| 11750 | | - ); |
| 11751 | | - } |
| 11752 | | - } |
| 11753 | | - |
| 11754 | | - return rc; |
| 11755 | | -} |
| 11756 | | - |
| 11757 | 12112 | |
| 11758 | 12113 | /* |
| 11759 | 12114 | ** If an input line begins with "." then invoke this routine to |
| 11760 | 12115 | ** process that line. |
| 11761 | 12116 | ** |
| | @@ -11766,13 +12121,15 @@ |
| 11766 | 12121 | int nArg = 0; |
| 11767 | 12122 | int n, c; |
| 11768 | 12123 | int rc = 0; |
| 11769 | 12124 | char *azArg[50]; |
| 11770 | 12125 | |
| 12126 | +#ifndef SQLITE_OMIT_VIRTUALTABLE |
| 11771 | 12127 | if( p->expert.pExpert ){ |
| 11772 | 12128 | expertFinish(p, 1, 0); |
| 11773 | 12129 | } |
| 12130 | +#endif |
| 11774 | 12131 | |
| 11775 | 12132 | /* Parse the input line into tokens. |
| 11776 | 12133 | */ |
| 11777 | 12134 | while( zLine[h] && nArg<ArraySize(azArg) ){ |
| 11778 | 12135 | while( IsSpace(zLine[h]) ){ h++; } |
| | @@ -11799,10 +12156,11 @@ |
| 11799 | 12156 | /* Process the input line. |
| 11800 | 12157 | */ |
| 11801 | 12158 | if( nArg==0 ) return 0; /* no tokens, no error */ |
| 11802 | 12159 | n = strlen30(azArg[0]); |
| 11803 | 12160 | c = azArg[0][0]; |
| 12161 | + clearTempFile(p); |
| 11804 | 12162 | |
| 11805 | 12163 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 11806 | 12164 | if( c=='a' && strncmp(azArg[0], "auth", n)==0 ){ |
| 11807 | 12165 | if( nArg!=2 ){ |
| 11808 | 12166 | raw_printf(stderr, "Usage: .auth ON|OFF\n"); |
| | @@ -12133,14 +12491,16 @@ |
| 12133 | 12491 | if( p->mode==MODE_Explain ) p->mode = p->normalMode; |
| 12134 | 12492 | p->autoExplain = 1; |
| 12135 | 12493 | } |
| 12136 | 12494 | }else |
| 12137 | 12495 | |
| 12496 | +#ifndef SQLITE_OMIT_VIRTUALTABLE |
| 12138 | 12497 | if( c=='e' && strncmp(azArg[0], "expert", n)==0 ){ |
| 12139 | 12498 | open_db(p, 0); |
| 12140 | 12499 | expertDotCommand(p, azArg, nArg); |
| 12141 | 12500 | }else |
| 12501 | +#endif |
| 12142 | 12502 | |
| 12143 | 12503 | if( c=='f' && strncmp(azArg[0], "fullschema", n)==0 ){ |
| 12144 | 12504 | ShellState data; |
| 12145 | 12505 | char *zErrMsg = 0; |
| 12146 | 12506 | int doStats = 0; |
| | @@ -12592,11 +12952,11 @@ |
| 12592 | 12952 | raw_printf(stderr, "Usage: .log FILENAME\n"); |
| 12593 | 12953 | rc = 1; |
| 12594 | 12954 | }else{ |
| 12595 | 12955 | const char *zFile = azArg[1]; |
| 12596 | 12956 | output_file_close(p->pLog); |
| 12597 | | - p->pLog = output_file_open(zFile); |
| 12957 | + p->pLog = output_file_open(zFile, 0); |
| 12598 | 12958 | } |
| 12599 | 12959 | }else |
| 12600 | 12960 | |
| 12601 | 12961 | if( c=='m' && strncmp(azArg[0], "mode", n)==0 ){ |
| 12602 | 12962 | const char *zMode = nArg>=2 ? azArg[1] : ""; |
| | @@ -12701,30 +13061,54 @@ |
| 12701 | 13061 | p->zDbFilename = 0; |
| 12702 | 13062 | open_db(p, 0); |
| 12703 | 13063 | } |
| 12704 | 13064 | }else |
| 12705 | 13065 | |
| 12706 | | - if( c=='o' |
| 12707 | | - && (strncmp(azArg[0], "output", n)==0 || strncmp(azArg[0], "once", n)==0) |
| 13066 | + if( (c=='o' |
| 13067 | + && (strncmp(azArg[0], "output", n)==0||strncmp(azArg[0], "once", n)==0)) |
| 13068 | + || (c=='e' && n==5 && strcmp(azArg[0],"excel")==0) |
| 12708 | 13069 | ){ |
| 12709 | 13070 | const char *zFile = nArg>=2 ? azArg[1] : "stdout"; |
| 13071 | + int bTxtMode = 0; |
| 13072 | + if( azArg[0][0]=='e' ){ |
| 13073 | + /* Transform the ".excel" command into ".once -x" */ |
| 13074 | + nArg = 2; |
| 13075 | + azArg[0] = "once"; |
| 13076 | + zFile = azArg[1] = "-x"; |
| 13077 | + n = 4; |
| 13078 | + } |
| 12710 | 13079 | if( nArg>2 ){ |
| 12711 | | - utf8_printf(stderr, "Usage: .%s FILE\n", azArg[0]); |
| 13080 | + utf8_printf(stderr, "Usage: .%s [-e|-x|FILE]\n", azArg[0]); |
| 12712 | 13081 | rc = 1; |
| 12713 | 13082 | goto meta_command_exit; |
| 12714 | 13083 | } |
| 12715 | 13084 | if( n>1 && strncmp(azArg[0], "once", n)==0 ){ |
| 12716 | 13085 | if( nArg<2 ){ |
| 12717 | | - raw_printf(stderr, "Usage: .once FILE\n"); |
| 13086 | + raw_printf(stderr, "Usage: .once (-e|-x|FILE)\n"); |
| 12718 | 13087 | rc = 1; |
| 12719 | 13088 | goto meta_command_exit; |
| 12720 | 13089 | } |
| 12721 | 13090 | p->outCount = 2; |
| 12722 | 13091 | }else{ |
| 12723 | 13092 | p->outCount = 0; |
| 12724 | 13093 | } |
| 12725 | 13094 | output_reset(p); |
| 13095 | + if( zFile[0]=='-' && zFile[1]=='-' ) zFile++; |
| 13096 | + if( strcmp(zFile, "-e")==0 || strcmp(zFile, "-x")==0 ){ |
| 13097 | + p->doXdgOpen = 1; |
| 13098 | + outputModePush(p); |
| 13099 | + if( zFile[1]=='x' ){ |
| 13100 | + newTempFile(p, "csv"); |
| 13101 | + p->mode = MODE_Csv; |
| 13102 | + sqlite3_snprintf(sizeof(p->colSeparator), p->colSeparator, SEP_Comma); |
| 13103 | + sqlite3_snprintf(sizeof(p->rowSeparator), p->rowSeparator, SEP_CrLf); |
| 13104 | + }else{ |
| 13105 | + newTempFile(p, "txt"); |
| 13106 | + bTxtMode = 1; |
| 13107 | + } |
| 13108 | + zFile = p->zTempFile; |
| 13109 | + } |
| 12726 | 13110 | if( zFile[0]=='|' ){ |
| 12727 | 13111 | #ifdef SQLITE_OMIT_POPEN |
| 12728 | 13112 | raw_printf(stderr, "Error: pipes are not supported in this OS\n"); |
| 12729 | 13113 | rc = 1; |
| 12730 | 13114 | p->out = stdout; |
| | @@ -12737,11 +13121,11 @@ |
| 12737 | 13121 | }else{ |
| 12738 | 13122 | sqlite3_snprintf(sizeof(p->outfile), p->outfile, "%s", zFile); |
| 12739 | 13123 | } |
| 12740 | 13124 | #endif |
| 12741 | 13125 | }else{ |
| 12742 | | - p->out = output_file_open(zFile); |
| 13126 | + p->out = output_file_open(zFile, bTxtMode); |
| 12743 | 13127 | if( p->out==0 ){ |
| 12744 | 13128 | if( strcmp(zFile,"off")!=0 ){ |
| 12745 | 13129 | utf8_printf(stderr,"Error: cannot write to \"%s\"\n", zFile); |
| 12746 | 13130 | } |
| 12747 | 13131 | p->out = stdout; |
| | @@ -13614,11 +13998,11 @@ |
| 13614 | 13998 | }else |
| 13615 | 13999 | |
| 13616 | 14000 | /* Begin redirecting output to the file "testcase-out.txt" */ |
| 13617 | 14001 | if( c=='t' && strcmp(azArg[0],"testcase")==0 ){ |
| 13618 | 14002 | output_reset(p); |
| 13619 | | - p->out = output_file_open("testcase-out.txt"); |
| 14003 | + p->out = output_file_open("testcase-out.txt", 0); |
| 13620 | 14004 | if( p->out==0 ){ |
| 13621 | 14005 | raw_printf(stderr, "Error: cannot open 'testcase-out.txt'\n"); |
| 13622 | 14006 | } |
| 13623 | 14007 | if( nArg>=2 ){ |
| 13624 | 14008 | sqlite3_snprintf(sizeof(p->zTestcase), p->zTestcase, "%s", azArg[1]); |
| | @@ -13820,11 +14204,11 @@ |
| 13820 | 14204 | raw_printf(stderr, "Usage: .trace FILE|off\n"); |
| 13821 | 14205 | rc = 1; |
| 13822 | 14206 | goto meta_command_exit; |
| 13823 | 14207 | } |
| 13824 | 14208 | output_file_close(p->traceOut); |
| 13825 | | - p->traceOut = output_file_open(azArg[1]); |
| 14209 | + p->traceOut = output_file_open(azArg[1], 0); |
| 13826 | 14210 | #if !defined(SQLITE_OMIT_TRACE) && !defined(SQLITE_OMIT_FLOATING_POINT) |
| 13827 | 14211 | if( p->traceOut==0 ){ |
| 13828 | 14212 | sqlite3_trace_v2(p->db, 0, 0, 0); |
| 13829 | 14213 | }else{ |
| 13830 | 14214 | sqlite3_trace_v2(p->db, SQLITE_TRACE_STMT, sql_trace_callback,p->traceOut); |
| | @@ -14150,10 +14534,12 @@ |
| 14150 | 14534 | errCnt += runOneSqlLine(p, zSql, in, startline); |
| 14151 | 14535 | nSql = 0; |
| 14152 | 14536 | if( p->outCount ){ |
| 14153 | 14537 | output_reset(p); |
| 14154 | 14538 | p->outCount = 0; |
| 14539 | + }else{ |
| 14540 | + clearTempFile(p); |
| 14155 | 14541 | } |
| 14156 | 14542 | }else if( nSql && _all_whitespace(zSql) ){ |
| 14157 | 14543 | if( ShellHasFlag(p, SHFLG_Echo) ) printf("%s\n", zSql); |
| 14158 | 14544 | nSql = 0; |
| 14159 | 14545 | } |
| | @@ -14772,11 +15158,14 @@ |
| 14772 | 15158 | session_close_all(&data); |
| 14773 | 15159 | sqlite3_close(data.db); |
| 14774 | 15160 | } |
| 14775 | 15161 | sqlite3_free(data.zFreeOnClose); |
| 14776 | 15162 | find_home_dir(1); |
| 15163 | + output_reset(&data); |
| 15164 | + data.doXdgOpen = 0; |
| 15165 | + clearTempFile(&data); |
| 14777 | 15166 | #if !SQLITE_SHELL_IS_UTF8 |
| 14778 | 15167 | for(i=0; i<argc; i++) sqlite3_free(argv[i]); |
| 14779 | 15168 | sqlite3_free(argv); |
| 14780 | 15169 | #endif |
| 14781 | 15170 | return rc; |
| 14782 | 15171 | } |
| 14783 | 15172 | |