| | @@ -6749,17 +6749,41 @@ |
| 6749 | 6749 | }while( j<p->nDigit ); |
| 6750 | 6750 | } |
| 6751 | 6751 | z[i] = 0; |
| 6752 | 6752 | sqlite3_result_text(pCtx, z, i, sqlite3_free); |
| 6753 | 6753 | } |
| 6754 | + |
| 6755 | +/* |
| 6756 | +** Round a decimal value to N significant digits. N must be positive. |
| 6757 | +*/ |
| 6758 | +static void decimal_round(Decimal *p, int N){ |
| 6759 | + int i; |
| 6760 | + int nZero; |
| 6761 | + if( N<1 ) return; |
| 6762 | + for(nZero=0; nZero<p->nDigit && p->a[nZero]==0; nZero++){} |
| 6763 | + N += nZero; |
| 6764 | + if( p->nDigit<=N ) return; |
| 6765 | + if( p->a[N]>4 ){ |
| 6766 | + p->a[N-1]++; |
| 6767 | + for(i=N-1; i>0 && p->a[i]>9; i--){ |
| 6768 | + p->a[i] = 0; |
| 6769 | + p->a[i-1]++; |
| 6770 | + } |
| 6771 | + if( p->a[0]>9 ){ |
| 6772 | + p->a[0] = 1; |
| 6773 | + p->nFrac--; |
| 6774 | + } |
| 6775 | + } |
| 6776 | + memset(&p->a[N], 0, p->nDigit - N); |
| 6777 | +} |
| 6754 | 6778 | |
| 6755 | 6779 | /* |
| 6756 | 6780 | ** Make the given Decimal the result in an format similar to '%+#e'. |
| 6757 | 6781 | ** In other words, show exponential notation with leading and trailing |
| 6758 | 6782 | ** zeros omitted. |
| 6759 | 6783 | */ |
| 6760 | | -static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p){ |
| 6784 | +static void decimal_result_sci(sqlite3_context *pCtx, Decimal *p, int N){ |
| 6761 | 6785 | char *z; /* The output buffer */ |
| 6762 | 6786 | int i; /* Loop counter */ |
| 6763 | 6787 | int nZero; /* Number of leading zeros */ |
| 6764 | 6788 | int nDigit; /* Number of digits not counting trailing zeros */ |
| 6765 | 6789 | int nFrac; /* Digits to the right of the decimal point */ |
| | @@ -6773,11 +6797,12 @@ |
| 6773 | 6797 | } |
| 6774 | 6798 | if( p->isNull ){ |
| 6775 | 6799 | sqlite3_result_null(pCtx); |
| 6776 | 6800 | return; |
| 6777 | 6801 | } |
| 6778 | | - for(nDigit=p->nDigit; nDigit>0 && p->a[nDigit-1]==0; nDigit--){} |
| 6802 | + if( N<1 ) N = 0; |
| 6803 | + for(nDigit=p->nDigit; nDigit>N && p->a[nDigit-1]==0; nDigit--){} |
| 6779 | 6804 | for(nZero=0; nZero<nDigit && p->a[nZero]==0; nZero++){} |
| 6780 | 6805 | nFrac = p->nFrac + (nDigit - p->nDigit); |
| 6781 | 6806 | nDigit -= nZero; |
| 6782 | 6807 | z = sqlite3_malloc64( (sqlite3_int64)nDigit+20 ); |
| 6783 | 6808 | if( z==0 ){ |
| | @@ -7136,14 +7161,20 @@ |
| 7136 | 7161 | sqlite3_context *context, |
| 7137 | 7162 | int argc, |
| 7138 | 7163 | sqlite3_value **argv |
| 7139 | 7164 | ){ |
| 7140 | 7165 | Decimal *p = decimal_new(context, argv[0], 0); |
| 7141 | | - UNUSED_PARAMETER(argc); |
| 7166 | + int N; |
| 7167 | + if( argc==2 ){ |
| 7168 | + N = sqlite3_value_int(argv[1]); |
| 7169 | + if( N>0 ) decimal_round(p, N); |
| 7170 | + }else{ |
| 7171 | + N = 0; |
| 7172 | + } |
| 7142 | 7173 | if( p ){ |
| 7143 | 7174 | if( sqlite3_user_data(context)!=0 ){ |
| 7144 | | - decimal_result_sci(context, p); |
| 7175 | + decimal_result_sci(context, p, N); |
| 7145 | 7176 | }else{ |
| 7146 | 7177 | decimal_result(context, p); |
| 7147 | 7178 | } |
| 7148 | 7179 | decimal_free(p); |
| 7149 | 7180 | } |
| | @@ -7309,11 +7340,11 @@ |
| 7309 | 7340 | sqlite3_value **argv |
| 7310 | 7341 | ){ |
| 7311 | 7342 | UNUSED_PARAMETER(argc); |
| 7312 | 7343 | if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ |
| 7313 | 7344 | Decimal *pA = decimalPow2(sqlite3_value_int(argv[0])); |
| 7314 | | - decimal_result_sci(context, pA); |
| 7345 | + decimal_result_sci(context, pA, 0); |
| 7315 | 7346 | decimal_free(pA); |
| 7316 | 7347 | } |
| 7317 | 7348 | } |
| 7318 | 7349 | |
| 7319 | 7350 | #ifdef _WIN32 |
| | @@ -7330,11 +7361,13 @@ |
| 7330 | 7361 | int nArg; |
| 7331 | 7362 | int iArg; |
| 7332 | 7363 | void (*xFunc)(sqlite3_context*,int,sqlite3_value**); |
| 7333 | 7364 | } aFunc[] = { |
| 7334 | 7365 | { "decimal", 1, 0, decimalFunc }, |
| 7366 | + { "decimal", 2, 0, decimalFunc }, |
| 7335 | 7367 | { "decimal_exp", 1, 1, decimalFunc }, |
| 7368 | + { "decimal_exp", 2, 1, decimalFunc }, |
| 7336 | 7369 | { "decimal_cmp", 2, 0, decimalCmpFunc }, |
| 7337 | 7370 | { "decimal_add", 2, 0, decimalAddFunc }, |
| 7338 | 7371 | { "decimal_sub", 2, 0, decimalSubFunc }, |
| 7339 | 7372 | { "decimal_mul", 2, 0, decimalMulFunc }, |
| 7340 | 7373 | { "decimal_pow2", 1, 0, decimalPow2Func }, |
| | @@ -8384,10 +8417,42 @@ |
| 8384 | 8417 | v >>= 8; |
| 8385 | 8418 | } |
| 8386 | 8419 | sqlite3_result_blob(context, a, sizeof(r), SQLITE_TRANSIENT); |
| 8387 | 8420 | } |
| 8388 | 8421 | } |
| 8422 | + |
| 8423 | +/* |
| 8424 | +** Functions to convert between 64-bit integers and floats. |
| 8425 | +** |
| 8426 | +** The bit patterns are copied. The numeric values are different. |
| 8427 | +*/ |
| 8428 | +static void ieee754func_from_int( |
| 8429 | + sqlite3_context *context, |
| 8430 | + int argc, |
| 8431 | + sqlite3_value **argv |
| 8432 | +){ |
| 8433 | + UNUSED_PARAMETER(argc); |
| 8434 | + if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){ |
| 8435 | + double r; |
| 8436 | + sqlite3_int64 v = sqlite3_value_int64(argv[0]); |
| 8437 | + memcpy(&r, &v, sizeof(r)); |
| 8438 | + sqlite3_result_double(context, r); |
| 8439 | + } |
| 8440 | +} |
| 8441 | +static void ieee754func_to_int( |
| 8442 | + sqlite3_context *context, |
| 8443 | + int argc, |
| 8444 | + sqlite3_value **argv |
| 8445 | +){ |
| 8446 | + UNUSED_PARAMETER(argc); |
| 8447 | + if( sqlite3_value_type(argv[0])==SQLITE_FLOAT ){ |
| 8448 | + double r = sqlite3_value_double(argv[0]); |
| 8449 | + sqlite3_uint64 v; |
| 8450 | + memcpy(&v, &r, sizeof(v)); |
| 8451 | + sqlite3_result_int64(context, v); |
| 8452 | + } |
| 8453 | +} |
| 8389 | 8454 | |
| 8390 | 8455 | /* |
| 8391 | 8456 | ** SQL Function: ieee754_inc(r,N) |
| 8392 | 8457 | ** |
| 8393 | 8458 | ** Move the floating point value r by N quantums and return the new |
| | @@ -8437,10 +8502,12 @@ |
| 8437 | 8502 | { "ieee754", 2, 0, ieee754func }, |
| 8438 | 8503 | { "ieee754_mantissa", 1, 1, ieee754func }, |
| 8439 | 8504 | { "ieee754_exponent", 1, 2, ieee754func }, |
| 8440 | 8505 | { "ieee754_to_blob", 1, 0, ieee754func_to_blob }, |
| 8441 | 8506 | { "ieee754_from_blob", 1, 0, ieee754func_from_blob }, |
| 8507 | + { "ieee754_to_int", 1, 0, ieee754func_to_int }, |
| 8508 | + { "ieee754_from_int", 1, 0, ieee754func_from_int }, |
| 8442 | 8509 | { "ieee754_inc", 2, 0, ieee754inc }, |
| 8443 | 8510 | }; |
| 8444 | 8511 | unsigned int i; |
| 8445 | 8512 | int rc = SQLITE_OK; |
| 8446 | 8513 | SQLITE_EXTENSION_INIT2(pApi); |
| | @@ -10422,16 +10489,20 @@ |
| 10422 | 10489 | # include <unistd.h> |
| 10423 | 10490 | # include <dirent.h> |
| 10424 | 10491 | # include <utime.h> |
| 10425 | 10492 | # include <sys/time.h> |
| 10426 | 10493 | # define STRUCT_STAT struct stat |
| 10494 | +# include <limits.h> |
| 10495 | +# include <stdlib.h> |
| 10427 | 10496 | #else |
| 10428 | 10497 | /* # include "windirent.h" */ |
| 10429 | 10498 | # include <direct.h> |
| 10430 | 10499 | # define STRUCT_STAT struct _stat |
| 10431 | 10500 | # define chmod(path,mode) fileio_chmod(path,mode) |
| 10432 | 10501 | # define mkdir(path,mode) fileio_mkdir(path) |
| 10502 | + extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); |
| 10503 | + extern char *sqlite3_win32_unicode_to_utf8(LPCWSTR); |
| 10433 | 10504 | #endif |
| 10434 | 10505 | #include <time.h> |
| 10435 | 10506 | #include <errno.h> |
| 10436 | 10507 | |
| 10437 | 10508 | /* When used as part of the CLI, the sqlite3_stdio.h module will have |
| | @@ -10459,16 +10530,13 @@ |
| 10459 | 10530 | /* |
| 10460 | 10531 | ** UTF8 chmod() function for Windows |
| 10461 | 10532 | */ |
| 10462 | 10533 | #if defined(_WIN32) || defined(WIN32) |
| 10463 | 10534 | static int fileio_chmod(const char *zPath, int pmode){ |
| 10464 | | - sqlite3_int64 sz = strlen(zPath); |
| 10465 | | - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 10466 | 10535 | int rc; |
| 10536 | + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); |
| 10467 | 10537 | if( b1==0 ) return -1; |
| 10468 | | - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 10469 | | - b1[sz] = 0; |
| 10470 | 10538 | rc = _wchmod(b1, pmode); |
| 10471 | 10539 | sqlite3_free(b1); |
| 10472 | 10540 | return rc; |
| 10473 | 10541 | } |
| 10474 | 10542 | #endif |
| | @@ -10476,16 +10544,13 @@ |
| 10476 | 10544 | /* |
| 10477 | 10545 | ** UTF8 mkdir() function for Windows |
| 10478 | 10546 | */ |
| 10479 | 10547 | #if defined(_WIN32) || defined(WIN32) |
| 10480 | 10548 | static int fileio_mkdir(const char *zPath){ |
| 10481 | | - sqlite3_int64 sz = strlen(zPath); |
| 10482 | | - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 10483 | 10549 | int rc; |
| 10550 | + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); |
| 10484 | 10551 | if( b1==0 ) return -1; |
| 10485 | | - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 10486 | | - b1[sz] = 0; |
| 10487 | 10552 | rc = _wmkdir(b1); |
| 10488 | 10553 | sqlite3_free(b1); |
| 10489 | 10554 | return rc; |
| 10490 | 10555 | } |
| 10491 | 10556 | #endif |
| | @@ -10594,54 +10659,11 @@ |
| 10594 | 10659 | fileIntervals.LowPart = pFileTime->dwLowDateTime; |
| 10595 | 10660 | fileIntervals.HighPart = pFileTime->dwHighDateTime; |
| 10596 | 10661 | |
| 10597 | 10662 | return (fileIntervals.QuadPart - epochIntervals.QuadPart) / 10000000; |
| 10598 | 10663 | } |
| 10599 | | - |
| 10600 | | - |
| 10601 | | -#if defined(FILEIO_WIN32_DLL) && (defined(_WIN32) || defined(WIN32)) |
| 10602 | | -# /* To allow a standalone DLL, use this next replacement function: */ |
| 10603 | | -# undef sqlite3_win32_utf8_to_unicode |
| 10604 | | -# define sqlite3_win32_utf8_to_unicode utf8_to_utf16 |
| 10605 | | -# |
| 10606 | | -LPWSTR utf8_to_utf16(const char *z){ |
| 10607 | | - int nAllot = MultiByteToWideChar(CP_UTF8, 0, z, -1, NULL, 0); |
| 10608 | | - LPWSTR rv = sqlite3_malloc(nAllot * sizeof(WCHAR)); |
| 10609 | | - if( rv!=0 && 0 < MultiByteToWideChar(CP_UTF8, 0, z, -1, rv, nAllot) ) |
| 10610 | | - return rv; |
| 10611 | | - sqlite3_free(rv); |
| 10612 | | - return 0; |
| 10613 | | -} |
| 10614 | | -#endif |
| 10615 | | - |
| 10616 | | -/* |
| 10617 | | -** This function attempts to normalize the time values found in the stat() |
| 10618 | | -** buffer to UTC. This is necessary on Win32, where the runtime library |
| 10619 | | -** appears to return these values as local times. |
| 10620 | | -*/ |
| 10621 | | -static void statTimesToUtc( |
| 10622 | | - const char *zPath, |
| 10623 | | - STRUCT_STAT *pStatBuf |
| 10624 | | -){ |
| 10625 | | - HANDLE hFindFile; |
| 10626 | | - WIN32_FIND_DATAW fd; |
| 10627 | | - LPWSTR zUnicodeName; |
| 10628 | | - extern LPWSTR sqlite3_win32_utf8_to_unicode(const char*); |
| 10629 | | - zUnicodeName = sqlite3_win32_utf8_to_unicode(zPath); |
| 10630 | | - if( zUnicodeName ){ |
| 10631 | | - memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); |
| 10632 | | - hFindFile = FindFirstFileW(zUnicodeName, &fd); |
| 10633 | | - if( hFindFile!=NULL ){ |
| 10634 | | - pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); |
| 10635 | | - pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); |
| 10636 | | - pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); |
| 10637 | | - FindClose(hFindFile); |
| 10638 | | - } |
| 10639 | | - sqlite3_free(zUnicodeName); |
| 10640 | | - } |
| 10641 | | -} |
| 10642 | | -#endif |
| 10664 | +#endif /* _WIN32 */ |
| 10643 | 10665 | |
| 10644 | 10666 | /* |
| 10645 | 10667 | ** This function is used in place of stat(). On Windows, special handling |
| 10646 | 10668 | ** is required in order for the included time to be returned as UTC. On all |
| 10647 | 10669 | ** other systems, this function simply calls stat(). |
| | @@ -10649,18 +10671,26 @@ |
| 10649 | 10671 | static int fileStat( |
| 10650 | 10672 | const char *zPath, |
| 10651 | 10673 | STRUCT_STAT *pStatBuf |
| 10652 | 10674 | ){ |
| 10653 | 10675 | #if defined(_WIN32) |
| 10654 | | - sqlite3_int64 sz = strlen(zPath); |
| 10655 | | - wchar_t *b1 = sqlite3_malloc64( (sz+1)*sizeof(b1[0]) ); |
| 10656 | 10676 | int rc; |
| 10677 | + wchar_t *b1 = sqlite3_win32_utf8_to_unicode(zPath); |
| 10657 | 10678 | if( b1==0 ) return 1; |
| 10658 | | - sz = MultiByteToWideChar(CP_UTF8, 0, zPath, sz, b1, sz); |
| 10659 | | - b1[sz] = 0; |
| 10660 | 10679 | rc = _wstat(b1, pStatBuf); |
| 10661 | | - if( rc==0 ) statTimesToUtc(zPath, pStatBuf); |
| 10680 | + if( rc==0 ){ |
| 10681 | + HANDLE hFindFile; |
| 10682 | + WIN32_FIND_DATAW fd; |
| 10683 | + memset(&fd, 0, sizeof(WIN32_FIND_DATAW)); |
| 10684 | + hFindFile = FindFirstFileW(b1, &fd); |
| 10685 | + if( hFindFile!=NULL ){ |
| 10686 | + pStatBuf->st_ctime = (time_t)fileTimeToUnixTime(&fd.ftCreationTime); |
| 10687 | + pStatBuf->st_atime = (time_t)fileTimeToUnixTime(&fd.ftLastAccessTime); |
| 10688 | + pStatBuf->st_mtime = (time_t)fileTimeToUnixTime(&fd.ftLastWriteTime); |
| 10689 | + FindClose(hFindFile); |
| 10690 | + } |
| 10691 | + } |
| 10662 | 10692 | sqlite3_free(b1); |
| 10663 | 10693 | return rc; |
| 10664 | 10694 | #else |
| 10665 | 10695 | return stat(zPath, pStatBuf); |
| 10666 | 10696 | #endif |
| | @@ -11420,10 +11450,158 @@ |
| 11420 | 11450 | return rc; |
| 11421 | 11451 | } |
| 11422 | 11452 | #else /* SQLITE_OMIT_VIRTUALTABLE */ |
| 11423 | 11453 | # define fsdirRegister(x) SQLITE_OK |
| 11424 | 11454 | #endif |
| 11455 | + |
| 11456 | +/* |
| 11457 | +** This version of realpath() works on any system. The string |
| 11458 | +** returned is held in memory allocated using sqlite3_malloc64(). |
| 11459 | +** The caller is responsible for calling sqlite3_free(). |
| 11460 | +*/ |
| 11461 | +static char *portable_realpath(const char *zPath){ |
| 11462 | +#if !defined(_WIN32) /* BEGIN unix */ |
| 11463 | + |
| 11464 | + char *zOut = 0; /* Result */ |
| 11465 | + char *z; /* Temporary buffer */ |
| 11466 | +#if defined(PATH_MAX) |
| 11467 | + char zBuf[PATH_MAX+1]; /* Space for the temporary buffer */ |
| 11468 | +#endif |
| 11469 | + |
| 11470 | + if( zPath==0 ) return 0; |
| 11471 | +#if defined(PATH_MAX) |
| 11472 | + z = realpath(zPath, zBuf); |
| 11473 | + if( z ){ |
| 11474 | + zOut = sqlite3_mprintf("%s", zBuf); |
| 11475 | + } |
| 11476 | +#endif /* defined(PATH_MAX) */ |
| 11477 | + if( zOut==0 ){ |
| 11478 | + /* Try POSIX.1-2008 malloc behavior */ |
| 11479 | + z = realpath(zPath, NULL); |
| 11480 | + if( z ){ |
| 11481 | + zOut = sqlite3_mprintf("%s", z); |
| 11482 | + free(z); |
| 11483 | + } |
| 11484 | + } |
| 11485 | + return zOut; |
| 11486 | + |
| 11487 | +#else /* End UNIX, Begin WINDOWS */ |
| 11488 | + |
| 11489 | + wchar_t *zPath16; /* UTF16 translation of zPath */ |
| 11490 | + char *zOut = 0; /* Result */ |
| 11491 | + wchar_t *z = 0; /* Temporary buffer */ |
| 11492 | + |
| 11493 | + if( zPath==0 ) return 0; |
| 11494 | + |
| 11495 | + zPath16 = sqlite3_win32_utf8_to_unicode(zPath); |
| 11496 | + if( zPath16==0 ) return 0; |
| 11497 | + z = _wfullpath(NULL, zPath16, 0); |
| 11498 | + sqlite3_free(zPath16); |
| 11499 | + if( z ){ |
| 11500 | + zOut = sqlite3_win32_unicode_to_utf8(z); |
| 11501 | + free(z); |
| 11502 | + } |
| 11503 | + return zOut; |
| 11504 | + |
| 11505 | +#endif /* End WINDOWS, Begin common code */ |
| 11506 | +} |
| 11507 | + |
| 11508 | +/* |
| 11509 | +** SQL function: realpath(X) |
| 11510 | +** |
| 11511 | +** Try to convert file or pathname X into its real, absolute pathname. |
| 11512 | +** Return NULL if unable. |
| 11513 | +** |
| 11514 | +** The file or directory X is not required to exist. The answer is formed |
| 11515 | +** by calling system realpath() on the prefix of X that does exist and |
| 11516 | +** appending the tail of X that does not (yet) exist. |
| 11517 | +*/ |
| 11518 | +static void realpathFunc( |
| 11519 | + sqlite3_context *context, |
| 11520 | + int argc, |
| 11521 | + sqlite3_value **argv |
| 11522 | +){ |
| 11523 | + const char *zPath; /* Original input path */ |
| 11524 | + char *zCopy; /* An editable copy of zPath */ |
| 11525 | + char *zOut; /* The result */ |
| 11526 | + char cSep = 0; /* Separator turned into \000 */ |
| 11527 | + size_t len; /* Prefix length before cSep */ |
| 11528 | +#ifdef _WIN32 |
| 11529 | + const int isWin = 1; |
| 11530 | +#else |
| 11531 | + const int isWin = 0; |
| 11532 | +#endif |
| 11533 | + |
| 11534 | + (void)argc; |
| 11535 | + zPath = (const char*)sqlite3_value_text(argv[0]); |
| 11536 | + if( zPath==0 ) return; |
| 11537 | + if( zPath[0]==0 ) zPath = "."; |
| 11538 | + zCopy = sqlite3_mprintf("%s",zPath); |
| 11539 | + len = strlen(zCopy); |
| 11540 | + while( len>1 && (zCopy[len-1]=='/' || (isWin && zCopy[len-1]=='\\')) ){ |
| 11541 | + len--; |
| 11542 | + } |
| 11543 | + zCopy[len] = 0; |
| 11544 | + while( 1 /*exit-by-break*/ ){ |
| 11545 | + zOut = portable_realpath(zCopy); |
| 11546 | + zCopy[len] = cSep; |
| 11547 | + if( zOut ){ |
| 11548 | + if( cSep ){ |
| 11549 | + zOut = sqlite3_mprintf("%z%s",zOut,&zCopy[len]); |
| 11550 | + } |
| 11551 | + break; |
| 11552 | + }else{ |
| 11553 | + size_t i = len-1; |
| 11554 | + while( i>0 ){ |
| 11555 | + if( zCopy[i]=='/' || (isWin && zCopy[i]=='\\') ) break; |
| 11556 | + i--; |
| 11557 | + } |
| 11558 | + if( i<=0 ){ |
| 11559 | + if( zCopy[0]=='/' ){ |
| 11560 | + zOut = zCopy; |
| 11561 | + zCopy = 0; |
| 11562 | + }else if( (zOut = portable_realpath("."))!=0 ){ |
| 11563 | + zOut = sqlite3_mprintf("%z/%s", zOut, zCopy); |
| 11564 | + } |
| 11565 | + break; |
| 11566 | + } |
| 11567 | + cSep = zCopy[i]; |
| 11568 | + zCopy[i] = 0; |
| 11569 | + len = i; |
| 11570 | + } |
| 11571 | + } |
| 11572 | + sqlite3_free(zCopy); |
| 11573 | + if( zOut ){ |
| 11574 | + /* Simplify any "/./" or "/../" that might have snuck into the |
| 11575 | + ** pathname due to appending of zCopy. We only have to consider |
| 11576 | + ** unix "/" separators, because the _wfilepath() system call on |
| 11577 | + ** Windows will have already done this simplification for us. */ |
| 11578 | + size_t i, j, n; |
| 11579 | + n = strlen(zOut); |
| 11580 | + for(i=j=0; i<n; i++){ |
| 11581 | + if( zOut[i]=='/' ){ |
| 11582 | + if( zOut[i+1]=='/' ) continue; |
| 11583 | + if( zOut[i+1]=='.' && i+2<n && zOut[i+2]=='/' ){ |
| 11584 | + i += 1; |
| 11585 | + continue; |
| 11586 | + } |
| 11587 | + if( zOut[i+1]=='.' && i+3<n && zOut[i+2]=='.' && zOut[i+3]=='/' ){ |
| 11588 | + while( j>0 && zOut[j-1]!='/' ){ j--; } |
| 11589 | + if( j>0 ){ j--; } |
| 11590 | + i += 2; |
| 11591 | + continue; |
| 11592 | + } |
| 11593 | + } |
| 11594 | + zOut[j++] = zOut[i]; |
| 11595 | + } |
| 11596 | + zOut[j] = 0; |
| 11597 | + |
| 11598 | + /* Return the result */ |
| 11599 | + sqlite3_result_text(context, zOut, -1, sqlite3_free); |
| 11600 | + } |
| 11601 | +} |
| 11602 | + |
| 11425 | 11603 | |
| 11426 | 11604 | #ifdef _WIN32 |
| 11427 | 11605 | |
| 11428 | 11606 | #endif |
| 11429 | 11607 | int sqlite3_fileio_init( |
| | @@ -11447,10 +11625,15 @@ |
| 11447 | 11625 | lsModeFunc, 0, 0); |
| 11448 | 11626 | } |
| 11449 | 11627 | if( rc==SQLITE_OK ){ |
| 11450 | 11628 | rc = fsdirRegister(db); |
| 11451 | 11629 | } |
| 11630 | + if( rc==SQLITE_OK ){ |
| 11631 | + rc = sqlite3_create_function(db, "realpath", 1, |
| 11632 | + SQLITE_UTF8, 0, |
| 11633 | + realpathFunc, 0, 0); |
| 11634 | + } |
| 11452 | 11635 | return rc; |
| 11453 | 11636 | } |
| 11454 | 11637 | |
| 11455 | 11638 | /************************* End ext/misc/fileio.c ********************/ |
| 11456 | 11639 | /************************* Begin ext/misc/completion.c ******************/ |
| | @@ -29882,15 +30065,19 @@ |
| 29882 | 30065 | /* |
| 29883 | 30066 | ** Implementation of .ar "eXtract" command. |
| 29884 | 30067 | */ |
| 29885 | 30068 | static int arExtractCommand(ArCommand *pAr){ |
| 29886 | 30069 | const char *zSql1 = |
| 29887 | | - "SELECT " |
| 29888 | | - " ($dir || name)," |
| 29889 | | - " writefile(($dir || name), %s, mode, mtime) " |
| 29890 | | - "FROM %s WHERE (%s) AND (data IS NULL OR $dirOnly = 0)" |
| 29891 | | - " AND name NOT GLOB '*..[/\\]*'"; |
| 30070 | + "WITH dest(dpath,dlen) AS (SELECT realpath($dir),length(realpath($dir)))\n" |
| 30071 | + "SELECT ($dir || name),\n" |
| 30072 | + " CASE WHEN $dryrun THEN 0\n" |
| 30073 | + " ELSE writefile($dir||name, %s, mode, mtime) END\n" |
| 30074 | + " FROM dest CROSS JOIN %s\n" |
| 30075 | + " WHERE (%s)\n" |
| 30076 | + " AND (data IS NULL OR $pass==0)\n" /* Dirs both passes */ |
| 30077 | + " AND dpath=substr(realpath($dir||name),1,dlen)\n" /* No escapes */ |
| 30078 | + " AND name NOT GLOB '*..[/\\]*'\n"; /* No /../ in paths */ |
| 29892 | 30079 | |
| 29893 | 30080 | const char *azExtraArg[] = { |
| 29894 | 30081 | "sqlar_uncompress(data, sz)", |
| 29895 | 30082 | "data" |
| 29896 | 30083 | }; |
| | @@ -29921,28 +30108,32 @@ |
| 29921 | 30108 | ); |
| 29922 | 30109 | |
| 29923 | 30110 | if( rc==SQLITE_OK ){ |
| 29924 | 30111 | j = sqlite3_bind_parameter_index(pSql, "$dir"); |
| 29925 | 30112 | sqlite3_bind_text(pSql, j, zDir, -1, SQLITE_STATIC); |
| 30113 | + j = sqlite3_bind_parameter_index(pSql, "$dryrun"); |
| 30114 | + sqlite3_bind_int(pSql, j, pAr->bDryRun); |
| 29926 | 30115 | |
| 29927 | | - /* Run the SELECT statement twice. The first time, writefile() is called |
| 29928 | | - ** for all archive members that should be extracted. The second time, |
| 29929 | | - ** only for the directories. This is because the timestamps for |
| 29930 | | - ** extracted directories must be reset after they are populated (as |
| 29931 | | - ** populating them changes the timestamp). */ |
| 30116 | + /* Run the SELECT statement twice |
| 30117 | + ** (0) writefile() all files and directories |
| 30118 | + ** (1) writefile() for directory again |
| 30119 | + ** The second pass is so that the timestamps for extracted directories |
| 30120 | + ** will be reset to the value in the archive, since populating them |
| 30121 | + ** in the first pass will have changed the timestamp. */ |
| 29932 | 30122 | for(i=0; i<2; i++){ |
| 29933 | | - j = sqlite3_bind_parameter_index(pSql, "$dirOnly"); |
| 30123 | + j = sqlite3_bind_parameter_index(pSql, "$pass"); |
| 29934 | 30124 | sqlite3_bind_int(pSql, j, i); |
| 29935 | 30125 | if( pAr->bDryRun ){ |
| 29936 | 30126 | cli_printf(pAr->out, "%s\n", sqlite3_sql(pSql)); |
| 29937 | | - }else{ |
| 29938 | | - while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 29939 | | - if( i==0 && pAr->bVerbose ){ |
| 29940 | | - cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 29941 | | - } |
| 30127 | + if( pAr->bVerbose==0 ) break; |
| 30128 | + } |
| 30129 | + while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){ |
| 30130 | + if( i==0 && pAr->bVerbose ){ |
| 30131 | + cli_printf(pAr->out, "%s\n", sqlite3_column_text(pSql, 0)); |
| 29942 | 30132 | } |
| 29943 | 30133 | } |
| 30134 | + if( pAr->bDryRun ) break; |
| 29944 | 30135 | shellReset(&rc, pSql); |
| 29945 | 30136 | } |
| 29946 | 30137 | shellFinalize(&rc, pSql); |
| 29947 | 30138 | } |
| 29948 | 30139 | |
| | @@ -32484,10 +32675,11 @@ |
| 32484 | 32675 | { "enable_fkey", SQLITE_DBCONFIG_ENABLE_FKEY }, |
| 32485 | 32676 | { "enable_qpsg", SQLITE_DBCONFIG_ENABLE_QPSG }, |
| 32486 | 32677 | { "enable_trigger", SQLITE_DBCONFIG_ENABLE_TRIGGER }, |
| 32487 | 32678 | { "enable_view", SQLITE_DBCONFIG_ENABLE_VIEW }, |
| 32488 | 32679 | { "fts3_tokenizer", SQLITE_DBCONFIG_ENABLE_FTS3_TOKENIZER }, |
| 32680 | + { "fp_digits", SQLITE_DBCONFIG_FP_DIGITS }, |
| 32489 | 32681 | { "legacy_alter_table", SQLITE_DBCONFIG_LEGACY_ALTER_TABLE }, |
| 32490 | 32682 | { "legacy_file_format", SQLITE_DBCONFIG_LEGACY_FILE_FORMAT }, |
| 32491 | 32683 | { "load_extension", SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION }, |
| 32492 | 32684 | { "no_ckpt_on_close", SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE }, |
| 32493 | 32685 | { "reset_database", SQLITE_DBCONFIG_RESET_DATABASE }, |
| | @@ -32500,15 +32692,23 @@ |
| 32500 | 32692 | int ii, v; |
| 32501 | 32693 | open_db(p, 0); |
| 32502 | 32694 | for(ii=0; ii<ArraySize(aDbConfig); ii++){ |
| 32503 | 32695 | if( nArg>1 && cli_strcmp(azArg[1], aDbConfig[ii].zName)!=0 ) continue; |
| 32504 | 32696 | if( nArg>=3 ){ |
| 32505 | | - sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); |
| 32697 | + if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){ |
| 32698 | + sqlite3_db_config(p->db, aDbConfig[ii].op, atoi(azArg[2]), 0); |
| 32699 | + }else{ |
| 32700 | + sqlite3_db_config(p->db, aDbConfig[ii].op, booleanValue(azArg[2]), 0); |
| 32701 | + } |
| 32506 | 32702 | } |
| 32507 | 32703 | sqlite3_db_config(p->db, aDbConfig[ii].op, -1, &v); |
| 32508 | | - cli_printf(p->out, "%19s %s\n", |
| 32509 | | - aDbConfig[ii].zName, v ? "on" : "off"); |
| 32704 | + if( aDbConfig[ii].op==SQLITE_DBCONFIG_FP_DIGITS ){ |
| 32705 | + cli_printf(p->out, "%19s %d\n", aDbConfig[ii].zName, v); |
| 32706 | + }else{ |
| 32707 | + cli_printf(p->out, "%19s %s\n", |
| 32708 | + aDbConfig[ii].zName, v ? "on" : "off"); |
| 32709 | + } |
| 32510 | 32710 | if( nArg>1 ) break; |
| 32511 | 32711 | } |
| 32512 | 32712 | if( nArg>1 && ii==ArraySize(aDbConfig) ){ |
| 32513 | 32713 | dotCmdError(p, 1, "unknown dbconfig", |
| 32514 | 32714 | "Enter \".dbconfig\" with no arguments for a list"); |
| | @@ -36563,11 +36763,11 @@ |
| 36563 | 36763 | ** we retain the goofy behavior for historical compatibility. */ |
| 36564 | 36764 | if( i==argc-1 ) break; |
| 36565 | 36765 | z = cmdline_option_value(argc,argv,++i); |
| 36566 | 36766 | if( z[0]=='.' ){ |
| 36567 | 36767 | rc = do_meta_command(z, &data); |
| 36568 | | - if( rc && bail_on_error ){ |
| 36768 | + if( rc && (bail_on_error || rc==2) ){ |
| 36569 | 36769 | if( rc==2 ) rc = 0; |
| 36570 | 36770 | goto shell_main_exit; |
| 36571 | 36771 | } |
| 36572 | 36772 | }else{ |
| 36573 | 36773 | open_db(&data, 0); |
| 36574 | 36774 | |