| | @@ -16,11 +16,13 @@ |
| 16 | 16 | ** if you want a wrapper to interface SQLite with your choice of programming |
| 17 | 17 | ** language. The code for the "sqlite3" command-line shell is also in a |
| 18 | 18 | ** separate file. This file contains only code for the core SQLite library. |
| 19 | 19 | ** |
| 20 | 20 | ** The content in this amalgamation comes from Fossil check-in |
| 21 | | -** 7a0cdc7edb704a88a77b748cd28f6e00c498. |
| 21 | +** 9a9d0f6301faefe324261f03543023ffb6a9 with changes in files: |
| 22 | +** |
| 23 | +** src/shell.c.in |
| 22 | 24 | */ |
| 23 | 25 | #define SQLITE_CORE 1 |
| 24 | 26 | #define SQLITE_AMALGAMATION 1 |
| 25 | 27 | #ifndef SQLITE_PRIVATE |
| 26 | 28 | # define SQLITE_PRIVATE static |
| | @@ -462,11 +464,11 @@ |
| 462 | 464 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 463 | 465 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 464 | 466 | */ |
| 465 | 467 | #define SQLITE_VERSION "3.47.0" |
| 466 | 468 | #define SQLITE_VERSION_NUMBER 3047000 |
| 467 | | -#define SQLITE_SOURCE_ID "2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9" |
| 469 | +#define SQLITE_SOURCE_ID "2024-08-23 17:40:29 9a9d0f6301faefe324261f03543023ffb6a90823349c6946abb0df2f69b3alt1" |
| 468 | 470 | |
| 469 | 471 | /* |
| 470 | 472 | ** CAPI3REF: Run-Time Library Version Numbers |
| 471 | 473 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 472 | 474 | ** |
| | @@ -7741,13 +7743,15 @@ |
| 7741 | 7743 | ** |
| 7742 | 7744 | ** ^The estimatedRows value is an estimate of the number of rows that |
| 7743 | 7745 | ** will be returned by the strategy. |
| 7744 | 7746 | ** |
| 7745 | 7747 | ** The xBestIndex method may optionally populate the idxFlags field with a |
| 7746 | | -** mask of SQLITE_INDEX_SCAN_* flags. Currently there is only one such flag - |
| 7747 | | -** SQLITE_INDEX_SCAN_UNIQUE. If the xBestIndex method sets this flag, SQLite |
| 7748 | | -** assumes that the strategy may visit at most one row. |
| 7748 | +** mask of SQLITE_INDEX_SCAN_* flags. One such flag is |
| 7749 | +** [SQLITE_INDEX_SCAN_HEX], which if set causes the [EXPLAIN QUERY PLAN] |
| 7750 | +** output to show the idxNum has hex instead of as decimal. Another flag is |
| 7751 | +** SQLITE_INDEX_SCAN_UNIQUE, which if set indicates that the query plan will |
| 7752 | +** return at most one row. |
| 7749 | 7753 | ** |
| 7750 | 7754 | ** Additionally, if xBestIndex sets the SQLITE_INDEX_SCAN_UNIQUE flag, then |
| 7751 | 7755 | ** SQLite also assumes that if a call to the xUpdate() method is made as |
| 7752 | 7756 | ** part of the same statement to delete or update a virtual table row and the |
| 7753 | 7757 | ** implementation returns SQLITE_CONSTRAINT, then there is no need to rollback |
| | @@ -7807,11 +7811,13 @@ |
| 7807 | 7811 | ** |
| 7808 | 7812 | ** Virtual table implementations are allowed to set the |
| 7809 | 7813 | ** [sqlite3_index_info].idxFlags field to some combination of |
| 7810 | 7814 | ** these bits. |
| 7811 | 7815 | */ |
| 7812 | | -#define SQLITE_INDEX_SCAN_UNIQUE 1 /* Scan visits at most 1 row */ |
| 7816 | +#define SQLITE_INDEX_SCAN_UNIQUE 0x00000001 /* Scan visits at most 1 row */ |
| 7817 | +#define SQLITE_INDEX_SCAN_HEX 0x00000002 /* Display idxNum as hex */ |
| 7818 | + /* in EXPLAIN QUERY PLAN */ |
| 7813 | 7819 | |
| 7814 | 7820 | /* |
| 7815 | 7821 | ** CAPI3REF: Virtual Table Constraint Operator Codes |
| 7816 | 7822 | ** |
| 7817 | 7823 | ** These macros define the allowed values for the |
| | @@ -8644,10 +8650,11 @@ |
| 8644 | 8650 | #define SQLITE_TESTCTRL_ALWAYS 13 |
| 8645 | 8651 | #define SQLITE_TESTCTRL_RESERVE 14 /* NOT USED */ |
| 8646 | 8652 | #define SQLITE_TESTCTRL_JSON_SELFCHECK 14 |
| 8647 | 8653 | #define SQLITE_TESTCTRL_OPTIMIZATIONS 15 |
| 8648 | 8654 | #define SQLITE_TESTCTRL_ISKEYWORD 16 /* NOT USED */ |
| 8655 | +#define SQLITE_TESTCTRL_GETOPT 16 |
| 8649 | 8656 | #define SQLITE_TESTCTRL_SCRATCHMALLOC 17 /* NOT USED */ |
| 8650 | 8657 | #define SQLITE_TESTCTRL_INTERNAL_FUNCTIONS 17 |
| 8651 | 8658 | #define SQLITE_TESTCTRL_LOCALTIME_FAULT 18 |
| 8652 | 8659 | #define SQLITE_TESTCTRL_EXPLAIN_STMT 19 /* NOT USED */ |
| 8653 | 8660 | #define SQLITE_TESTCTRL_ONCE_RESET_THRESHOLD 19 |
| | @@ -13418,13 +13425,36 @@ |
| 13418 | 13425 | ** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 13419 | 13426 | ** includes any embedded 0x00 and trailing data. |
| 13420 | 13427 | ** |
| 13421 | 13428 | ** This API can be quite slow if used with an FTS5 table created with the |
| 13422 | 13429 | ** "detail=none" or "detail=column" option. |
| 13430 | +** |
| 13431 | +** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) |
| 13432 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 13433 | +** number of columns in the table, SQLITE_RANGE is returned. |
| 13434 | +** |
| 13435 | +** Otherwise, this function attempts to retrieve the locale associated |
| 13436 | +** with column iCol of the current row. Usually, there is no associated |
| 13437 | +** locale, and output parameters (*pzLocale) and (*pnLocale) are set |
| 13438 | +** to NULL and 0, respectively. However, if the fts5_locale() function |
| 13439 | +** was used to associate a locale with the value when it was inserted |
| 13440 | +** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated |
| 13441 | +** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) |
| 13442 | +** is set to the size in bytes of the buffer, not including the |
| 13443 | +** nul-terminator. |
| 13444 | +** |
| 13445 | +** If successful, SQLITE_OK is returned. Or, if an error occurs, an |
| 13446 | +** SQLite error code is returned. The final value of the output parameters |
| 13447 | +** is undefined in this case. |
| 13448 | +** |
| 13449 | +** xTokenize_v2: |
| 13450 | +** Tokenize text using the tokenizer belonging to the FTS5 table. This |
| 13451 | +** API is the same as the xTokenize() API, except that it allows a tokenizer |
| 13452 | +** locale to be specified. |
| 13423 | 13453 | */ |
| 13424 | 13454 | struct Fts5ExtensionApi { |
| 13425 | | - int iVersion; /* Currently always set to 3 */ |
| 13455 | + int iVersion; /* Currently always set to 4 */ |
| 13426 | 13456 | |
| 13427 | 13457 | void *(*xUserData)(Fts5Context*); |
| 13428 | 13458 | |
| 13429 | 13459 | int (*xColumnCount)(Fts5Context*); |
| 13430 | 13460 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -13462,10 +13492,19 @@ |
| 13462 | 13492 | int (*xQueryToken)(Fts5Context*, |
| 13463 | 13493 | int iPhrase, int iToken, |
| 13464 | 13494 | const char **ppToken, int *pnToken |
| 13465 | 13495 | ); |
| 13466 | 13496 | int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); |
| 13497 | + |
| 13498 | + /* Below this point are iVersion>=4 only */ |
| 13499 | + int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); |
| 13500 | + int (*xTokenize_v2)(Fts5Context*, |
| 13501 | + const char *pText, int nText, /* Text to tokenize */ |
| 13502 | + const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ |
| 13503 | + void *pCtx, /* Context passed to xToken() */ |
| 13504 | + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ |
| 13505 | + ); |
| 13467 | 13506 | }; |
| 13468 | 13507 | |
| 13469 | 13508 | /* |
| 13470 | 13509 | ** CUSTOM AUXILIARY FUNCTIONS |
| 13471 | 13510 | *************************************************************************/ |
| | @@ -13474,19 +13513,20 @@ |
| 13474 | 13513 | ** CUSTOM TOKENIZERS |
| 13475 | 13514 | ** |
| 13476 | 13515 | ** Applications may also register custom tokenizer types. A tokenizer |
| 13477 | 13516 | ** is registered by providing fts5 with a populated instance of the |
| 13478 | 13517 | ** following structure. All structure methods must be defined, setting |
| 13518 | +** |
| 13479 | 13519 | ** any member of the fts5_tokenizer struct to NULL leads to undefined |
| 13480 | 13520 | ** behaviour. The structure methods are expected to function as follows: |
| 13481 | 13521 | ** |
| 13482 | 13522 | ** xCreate: |
| 13483 | 13523 | ** This function is used to allocate and initialize a tokenizer instance. |
| 13484 | 13524 | ** A tokenizer instance is required to actually tokenize text. |
| 13485 | 13525 | ** |
| 13486 | 13526 | ** The first argument passed to this function is a copy of the (void*) |
| 13487 | | -** pointer provided by the application when the fts5_tokenizer object |
| 13527 | +** pointer provided by the application when the fts5_tokenizer_v2 object |
| 13488 | 13528 | ** was registered with FTS5 (the third argument to xCreateTokenizer()). |
| 13489 | 13529 | ** The second and third arguments are an array of nul-terminated strings |
| 13490 | 13530 | ** containing the tokenizer arguments, if any, specified following the |
| 13491 | 13531 | ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used |
| 13492 | 13532 | ** to create the FTS5 table. |
| | @@ -13506,11 +13546,11 @@ |
| 13506 | 13546 | ** This function is expected to tokenize the nText byte string indicated |
| 13507 | 13547 | ** by argument pText. pText may or may not be nul-terminated. The first |
| 13508 | 13548 | ** argument passed to this function is a pointer to an Fts5Tokenizer object |
| 13509 | 13549 | ** returned by an earlier call to xCreate(). |
| 13510 | 13550 | ** |
| 13511 | | -** The second argument indicates the reason that FTS5 is requesting |
| 13551 | +** The third argument indicates the reason that FTS5 is requesting |
| 13512 | 13552 | ** tokenization of the supplied text. This is always one of the following |
| 13513 | 13553 | ** four values: |
| 13514 | 13554 | ** |
| 13515 | 13555 | ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into |
| 13516 | 13556 | ** or removed from the FTS table. The tokenizer is being invoked to |
| | @@ -13529,10 +13569,17 @@ |
| 13529 | 13569 | ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to |
| 13530 | 13570 | ** satisfy an fts5_api.xTokenize() request made by an auxiliary |
| 13531 | 13571 | ** function. Or an fts5_api.xColumnSize() request made by the same |
| 13532 | 13572 | ** on a columnsize=0 database. |
| 13533 | 13573 | ** </ul> |
| 13574 | +** |
| 13575 | +** The sixth and seventh arguments passed to xTokenize() - pLocale and |
| 13576 | +** nLocale - are a pointer to a buffer containing the locale to use for |
| 13577 | +** tokenization (e.g. "en_US") and its size in bytes, respectively. The |
| 13578 | +** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in |
| 13579 | +** which case nLocale is always 0) to indicate that the tokenizer should |
| 13580 | +** use its default locale. |
| 13534 | 13581 | ** |
| 13535 | 13582 | ** For each token in the input string, the supplied callback xToken() must |
| 13536 | 13583 | ** be invoked. The first argument to it should be a copy of the pointer |
| 13537 | 13584 | ** passed as the second argument to xTokenize(). The third and fourth |
| 13538 | 13585 | ** arguments are a pointer to a buffer containing the token text, and the |
| | @@ -13552,10 +13599,33 @@ |
| 13552 | 13599 | ** immediately return a copy of the xToken() return value. Or, if the |
| 13553 | 13600 | ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, |
| 13554 | 13601 | ** if an error occurs with the xTokenize() implementation itself, it |
| 13555 | 13602 | ** may abandon the tokenization and return any error code other than |
| 13556 | 13603 | ** SQLITE_OK or SQLITE_DONE. |
| 13604 | +** |
| 13605 | +** If the tokenizer is registered using an fts5_tokenizer_v2 object, |
| 13606 | +** then the xTokenize() method has two additional arguments - pLocale |
| 13607 | +** and nLocale. These specify the locale that the tokenizer should use |
| 13608 | +** for the current request. If pLocale and nLocale are both 0, then the |
| 13609 | +** tokenizer should use its default locale. Otherwise, pLocale points to |
| 13610 | +** an nLocale byte buffer containing the name of the locale to use as utf-8 |
| 13611 | +** text. pLocale is not nul-terminated. |
| 13612 | +** |
| 13613 | +** FTS5_TOKENIZER |
| 13614 | +** |
| 13615 | +** There is also an fts5_tokenizer object. This is an older version of |
| 13616 | +** fts5_tokenizer_v2. It is similar except that: |
| 13617 | +** |
| 13618 | +** <ul> |
| 13619 | +** <li> There is no "iVersion" field, and |
| 13620 | +** <li> The xTokenize() method does not take a locale argument. |
| 13621 | +** </ul> |
| 13622 | +** |
| 13623 | +** fts5_tokenizer tokenizers should be registered with the xCreateTokenizer() |
| 13624 | +** function, instead of xCreateTokenizer_v2(). Tokenizers implementations |
| 13625 | +** registered using either API may be retrieved using both xFindTokenizer() |
| 13626 | +** and xFindTokenizer_v2(). |
| 13557 | 13627 | ** |
| 13558 | 13628 | ** SYNONYM SUPPORT |
| 13559 | 13629 | ** |
| 13560 | 13630 | ** Custom tokenizers may also support synonyms. Consider a case in which a |
| 13561 | 13631 | ** user wishes to query for a phrase such as "first place". Using the |
| | @@ -13661,10 +13731,37 @@ |
| 13661 | 13731 | ** provide synonyms when tokenizing document text (method (3)) or query |
| 13662 | 13732 | ** text (method (2)), not both. Doing so will not cause any errors, but is |
| 13663 | 13733 | ** inefficient. |
| 13664 | 13734 | */ |
| 13665 | 13735 | typedef struct Fts5Tokenizer Fts5Tokenizer; |
| 13736 | +typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; |
| 13737 | +struct fts5_tokenizer_v2 { |
| 13738 | + int iVersion; /* Currently always 2 */ |
| 13739 | + |
| 13740 | + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); |
| 13741 | + void (*xDelete)(Fts5Tokenizer*); |
| 13742 | + int (*xTokenize)(Fts5Tokenizer*, |
| 13743 | + void *pCtx, |
| 13744 | + int flags, /* Mask of FTS5_TOKENIZE_* flags */ |
| 13745 | + const char *pText, int nText, |
| 13746 | + const char *pLocale, int nLocale, |
| 13747 | + int (*xToken)( |
| 13748 | + void *pCtx, /* Copy of 2nd argument to xTokenize() */ |
| 13749 | + int tflags, /* Mask of FTS5_TOKEN_* flags */ |
| 13750 | + const char *pToken, /* Pointer to buffer containing token */ |
| 13751 | + int nToken, /* Size of token in bytes */ |
| 13752 | + int iStart, /* Byte offset of token within input text */ |
| 13753 | + int iEnd /* Byte offset of end of token within input text */ |
| 13754 | + ) |
| 13755 | + ); |
| 13756 | +}; |
| 13757 | + |
| 13758 | +/* |
| 13759 | +** New code should use the fts5_tokenizer_v2 type to define tokenizer |
| 13760 | +** implementations. The following type is included for legacy applications |
| 13761 | +** that still use it. |
| 13762 | +*/ |
| 13666 | 13763 | typedef struct fts5_tokenizer fts5_tokenizer; |
| 13667 | 13764 | struct fts5_tokenizer { |
| 13668 | 13765 | int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); |
| 13669 | 13766 | void (*xDelete)(Fts5Tokenizer*); |
| 13670 | 13767 | int (*xTokenize)(Fts5Tokenizer*, |
| | @@ -13679,10 +13776,11 @@ |
| 13679 | 13776 | int iStart, /* Byte offset of token within input text */ |
| 13680 | 13777 | int iEnd /* Byte offset of end of token within input text */ |
| 13681 | 13778 | ) |
| 13682 | 13779 | ); |
| 13683 | 13780 | }; |
| 13781 | + |
| 13684 | 13782 | |
| 13685 | 13783 | /* Flags that may be passed as the third argument to xTokenize() */ |
| 13686 | 13784 | #define FTS5_TOKENIZE_QUERY 0x0001 |
| 13687 | 13785 | #define FTS5_TOKENIZE_PREFIX 0x0002 |
| 13688 | 13786 | #define FTS5_TOKENIZE_DOCUMENT 0x0004 |
| | @@ -13699,11 +13797,11 @@ |
| 13699 | 13797 | /************************************************************************* |
| 13700 | 13798 | ** FTS5 EXTENSION REGISTRATION API |
| 13701 | 13799 | */ |
| 13702 | 13800 | typedef struct fts5_api fts5_api; |
| 13703 | 13801 | struct fts5_api { |
| 13704 | | - int iVersion; /* Currently always set to 2 */ |
| 13802 | + int iVersion; /* Currently always set to 3 */ |
| 13705 | 13803 | |
| 13706 | 13804 | /* Create a new tokenizer */ |
| 13707 | 13805 | int (*xCreateTokenizer)( |
| 13708 | 13806 | fts5_api *pApi, |
| 13709 | 13807 | const char *zName, |
| | @@ -13726,10 +13824,29 @@ |
| 13726 | 13824 | const char *zName, |
| 13727 | 13825 | void *pUserData, |
| 13728 | 13826 | fts5_extension_function xFunction, |
| 13729 | 13827 | void (*xDestroy)(void*) |
| 13730 | 13828 | ); |
| 13829 | + |
| 13830 | + /* APIs below this point are only available if iVersion>=3 */ |
| 13831 | + |
| 13832 | + /* Create a new tokenizer */ |
| 13833 | + int (*xCreateTokenizer_v2)( |
| 13834 | + fts5_api *pApi, |
| 13835 | + const char *zName, |
| 13836 | + void *pUserData, |
| 13837 | + fts5_tokenizer_v2 *pTokenizer, |
| 13838 | + void (*xDestroy)(void*) |
| 13839 | + ); |
| 13840 | + |
| 13841 | + /* Find an existing tokenizer */ |
| 13842 | + int (*xFindTokenizer_v2)( |
| 13843 | + fts5_api *pApi, |
| 13844 | + const char *zName, |
| 13845 | + void **ppUserData, |
| 13846 | + fts5_tokenizer_v2 **ppTokenizer |
| 13847 | + ); |
| 13731 | 13848 | }; |
| 13732 | 13849 | |
| 13733 | 13850 | /* |
| 13734 | 13851 | ** END OF REGISTRATION API |
| 13735 | 13852 | *************************************************************************/ |
| | @@ -15380,10 +15497,11 @@ |
| 15380 | 15497 | typedef struct RowSet RowSet; |
| 15381 | 15498 | typedef struct Savepoint Savepoint; |
| 15382 | 15499 | typedef struct Select Select; |
| 15383 | 15500 | typedef struct SQLiteThread SQLiteThread; |
| 15384 | 15501 | typedef struct SelectDest SelectDest; |
| 15502 | +typedef struct Subquery Subquery; |
| 15385 | 15503 | typedef struct SrcItem SrcItem; |
| 15386 | 15504 | typedef struct SrcList SrcList; |
| 15387 | 15505 | typedef struct sqlite3_str StrAccum; /* Internal alias for sqlite3_str */ |
| 15388 | 15506 | typedef struct Table Table; |
| 15389 | 15507 | typedef struct TableLock TableLock; |
| | @@ -19263,10 +19381,20 @@ |
| 19263 | 19381 | */ |
| 19264 | 19382 | #define EU4_NONE 0 /* Does not use IdList.a.u4 */ |
| 19265 | 19383 | #define EU4_IDX 1 /* Uses IdList.a.u4.idx */ |
| 19266 | 19384 | #define EU4_EXPR 2 /* Uses IdList.a.u4.pExpr -- NOT CURRENTLY USED */ |
| 19267 | 19385 | |
| 19386 | +/* |
| 19387 | +** Details of the implementation of a subquery. |
| 19388 | +*/ |
| 19389 | +struct Subquery { |
| 19390 | + Select *pSelect; /* A SELECT statement used in place of a table name */ |
| 19391 | + int addrFillSub; /* Address of subroutine to initialize a subquery */ |
| 19392 | + int regReturn; /* Register holding return address of addrFillSub */ |
| 19393 | + int regResult; /* Registers holding results of a co-routine */ |
| 19394 | +}; |
| 19395 | + |
| 19268 | 19396 | /* |
| 19269 | 19397 | ** The SrcItem object represents a single term in the FROM clause of a query. |
| 19270 | 19398 | ** The SrcList object is mostly an array of SrcItems. |
| 19271 | 19399 | ** |
| 19272 | 19400 | ** The jointype starts out showing the join type between the current table |
| | @@ -19275,33 +19403,44 @@ |
| 19275 | 19403 | ** jointype expresses the join between the table and the previous table. |
| 19276 | 19404 | ** |
| 19277 | 19405 | ** In the colUsed field, the high-order bit (bit 63) is set if the table |
| 19278 | 19406 | ** contains more than 63 columns and the 64-th or later column is used. |
| 19279 | 19407 | ** |
| 19280 | | -** Union member validity: |
| 19408 | +** Aggressive use of "union" helps keep the size of the object small. This |
| 19409 | +** has been shown to boost performance, in addition to saving memory. |
| 19410 | +** Access to union elements is gated by the following rules which should |
| 19411 | +** always be checked, either by an if-statement or by an assert(). |
| 19281 | 19412 | ** |
| 19282 | | -** u1.zIndexedBy fg.isIndexedBy && !fg.isTabFunc |
| 19283 | | -** u1.pFuncArg fg.isTabFunc && !fg.isIndexedBy |
| 19413 | +** Field Only access if this is true |
| 19414 | +** --------------- ----------------------------------- |
| 19415 | +** u1.zIndexedBy fg.isIndexedBy |
| 19416 | +** u1.pFuncArg fg.isTabFunc |
| 19284 | 19417 | ** u1.nRow !fg.isTabFunc && !fg.isIndexedBy |
| 19285 | 19418 | ** |
| 19286 | | -** u2.pIBIndex fg.isIndexedBy && !fg.isCte |
| 19287 | | -** u2.pCteUse fg.isCte && !fg.isIndexedBy |
| 19419 | +** u2.pIBIndex fg.isIndexedBy |
| 19420 | +** u2.pCteUse fg.isCte |
| 19421 | +** |
| 19422 | +** u3.pOn !fg.isUsing |
| 19423 | +** u3.pUsing fg.isUsing |
| 19424 | +** |
| 19425 | +** u4.zDatabase !fg.fixedSchema && !fg.isSubquery |
| 19426 | +** u4.pSchema fg.fixedSchema |
| 19427 | +** u4.pSubq fg.isSubquery |
| 19428 | +** |
| 19429 | +** See also the sqlite3SrcListDelete() routine for assert() statements that |
| 19430 | +** check invariants on the fields of this object, especially the flags |
| 19431 | +** inside the fg struct. |
| 19288 | 19432 | */ |
| 19289 | 19433 | struct SrcItem { |
| 19290 | | - Schema *pSchema; /* Schema to which this item is fixed */ |
| 19291 | | - char *zDatabase; /* Name of database holding this table */ |
| 19292 | 19434 | char *zName; /* Name of the table */ |
| 19293 | 19435 | char *zAlias; /* The "B" part of a "A AS B" phrase. zName is the "A" */ |
| 19294 | | - Table *pTab; /* An SQL table corresponding to zName */ |
| 19295 | | - Select *pSelect; /* A SELECT statement used in place of a table name */ |
| 19296 | | - int addrFillSub; /* Address of subroutine to manifest a subquery */ |
| 19297 | | - int regReturn; /* Register holding return address of addrFillSub */ |
| 19298 | | - int regResult; /* Registers holding results of a co-routine */ |
| 19436 | + Table *pSTab; /* Table object for zName. Mnemonic: Srcitem-TABle */ |
| 19299 | 19437 | struct { |
| 19300 | 19438 | u8 jointype; /* Type of join between this table and the previous */ |
| 19301 | 19439 | unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ |
| 19302 | 19440 | unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ |
| 19441 | + unsigned isSubquery :1; /* True if this term is a subquery */ |
| 19303 | 19442 | unsigned isTabFunc :1; /* True if table-valued-function syntax */ |
| 19304 | 19443 | unsigned isCorrelated :1; /* True if sub-query is correlated */ |
| 19305 | 19444 | unsigned isMaterialized:1; /* This is a materialized view */ |
| 19306 | 19445 | unsigned viaCoroutine :1; /* Implemented as a co-routine */ |
| 19307 | 19446 | unsigned isRecursive :1; /* True for recursive reference in WITH */ |
| | @@ -19311,16 +19450,14 @@ |
| 19311 | 19450 | unsigned isUsing :1; /* u3.pUsing is valid */ |
| 19312 | 19451 | unsigned isOn :1; /* u3.pOn was once valid and non-NULL */ |
| 19313 | 19452 | unsigned isSynthUsing :1; /* u3.pUsing is synthesized from NATURAL */ |
| 19314 | 19453 | unsigned isNestedFrom :1; /* pSelect is a SF_NestedFrom subquery */ |
| 19315 | 19454 | unsigned rowidUsed :1; /* The ROWID of this table is referenced */ |
| 19455 | + unsigned fixedSchema :1; /* Uses u4.pSchema, not u4.zDatabase */ |
| 19456 | + unsigned hadSchema :1; /* Had u4.zDatabase before u4.pSchema */ |
| 19316 | 19457 | } fg; |
| 19317 | 19458 | int iCursor; /* The VDBE cursor number used to access this table */ |
| 19318 | | - union { |
| 19319 | | - Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ |
| 19320 | | - IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ |
| 19321 | | - } u3; |
| 19322 | 19459 | Bitmask colUsed; /* Bit N set if column N used. Details above for N>62 */ |
| 19323 | 19460 | union { |
| 19324 | 19461 | char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ |
| 19325 | 19462 | ExprList *pFuncArg; /* Arguments to table-valued-function */ |
| 19326 | 19463 | u32 nRow; /* Number of rows in a VALUES clause */ |
| | @@ -19327,10 +19464,19 @@ |
| 19327 | 19464 | } u1; |
| 19328 | 19465 | union { |
| 19329 | 19466 | Index *pIBIndex; /* Index structure corresponding to u1.zIndexedBy */ |
| 19330 | 19467 | CteUse *pCteUse; /* CTE Usage info when fg.isCte is true */ |
| 19331 | 19468 | } u2; |
| 19469 | + union { |
| 19470 | + Expr *pOn; /* fg.isUsing==0 => The ON clause of a join */ |
| 19471 | + IdList *pUsing; /* fg.isUsing==1 => The USING clause of a join */ |
| 19472 | + } u3; |
| 19473 | + union { |
| 19474 | + Schema *pSchema; /* Schema to which this item is fixed */ |
| 19475 | + char *zDatabase; /* Name of database holding this table */ |
| 19476 | + Subquery *pSubq; /* Description of a subquery */ |
| 19477 | + } u4; |
| 19332 | 19478 | }; |
| 19333 | 19479 | |
| 19334 | 19480 | /* |
| 19335 | 19481 | ** The OnOrUsing object represents either an ON clause or a USING clause. |
| 19336 | 19482 | ** It can never be both at the same time, but it can be neither. |
| | @@ -19586,12 +19732,14 @@ |
| 19586 | 19732 | #define SF_CopyCte 0x4000000 /* SELECT statement is a copy of a CTE */ |
| 19587 | 19733 | #define SF_OrderByReqd 0x8000000 /* The ORDER BY clause may not be omitted */ |
| 19588 | 19734 | #define SF_UpdateFrom 0x10000000 /* Query originates with UPDATE FROM */ |
| 19589 | 19735 | #define SF_Correlated 0x20000000 /* True if references the outer context */ |
| 19590 | 19736 | |
| 19591 | | -/* True if S exists and has SF_NestedFrom */ |
| 19592 | | -#define IsNestedFrom(S) ((S)!=0 && ((S)->selFlags&SF_NestedFrom)!=0) |
| 19737 | +/* True if SrcItem X is a subquery that has SF_NestedFrom */ |
| 19738 | +#define IsNestedFrom(X) \ |
| 19739 | + ((X)->fg.isSubquery && \ |
| 19740 | + ((X)->u4.pSubq->pSelect->selFlags&SF_NestedFrom)!=0) |
| 19593 | 19741 | |
| 19594 | 19742 | /* |
| 19595 | 19743 | ** The results of a SELECT can be distributed in several ways, as defined |
| 19596 | 19744 | ** by one of the following macros. The "SRT" prefix means "SELECT Result |
| 19597 | 19745 | ** Type". |
| | @@ -20979,10 +21127,13 @@ |
| 20979 | 21127 | SQLITE_PRIVATE IdList *sqlite3IdListAppend(Parse*, IdList*, Token*); |
| 20980 | 21128 | SQLITE_PRIVATE int sqlite3IdListIndex(IdList*,const char*); |
| 20981 | 21129 | SQLITE_PRIVATE SrcList *sqlite3SrcListEnlarge(Parse*, SrcList*, int, int); |
| 20982 | 21130 | SQLITE_PRIVATE SrcList *sqlite3SrcListAppendList(Parse *pParse, SrcList *p1, SrcList *p2); |
| 20983 | 21131 | SQLITE_PRIVATE SrcList *sqlite3SrcListAppend(Parse*, SrcList*, Token*, Token*); |
| 21132 | +SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3*,Subquery*); |
| 21133 | +SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3*,SrcItem*); |
| 21134 | +SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery(Parse*, SrcItem*, Select*, int); |
| 20984 | 21135 | SQLITE_PRIVATE SrcList *sqlite3SrcListAppendFromTerm(Parse*, SrcList*, Token*, Token*, |
| 20985 | 21136 | Token*, Select*, OnOrUsing*); |
| 20986 | 21137 | SQLITE_PRIVATE void sqlite3SrcListIndexedBy(Parse *, SrcList *, Token *); |
| 20987 | 21138 | SQLITE_PRIVATE void sqlite3SrcListFuncArgs(Parse*, SrcList*, ExprList*); |
| 20988 | 21139 | SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *, SrcItem *); |
| | @@ -24521,12 +24672,12 @@ |
| 24521 | 24672 | } |
| 24522 | 24673 | if( M<=2 ){ |
| 24523 | 24674 | Y--; |
| 24524 | 24675 | M += 12; |
| 24525 | 24676 | } |
| 24526 | | - A = Y/100; |
| 24527 | | - B = 2 - A + (A/4); |
| 24677 | + A = (Y+4800)/100; |
| 24678 | + B = 38 - A + (A/4); |
| 24528 | 24679 | X1 = 36525*(Y+4716)/100; |
| 24529 | 24680 | X2 = 306001*(M+1)/10000; |
| 24530 | 24681 | p->iJD = (sqlite3_int64)((X1 + X2 + D + B - 1524.5 ) * 86400000); |
| 24531 | 24682 | p->validJD = 1; |
| 24532 | 24683 | if( p->validHMS ){ |
| | @@ -24706,11 +24857,11 @@ |
| 24706 | 24857 | |
| 24707 | 24858 | /* |
| 24708 | 24859 | ** Compute the Year, Month, and Day from the julian day number. |
| 24709 | 24860 | */ |
| 24710 | 24861 | static void computeYMD(DateTime *p){ |
| 24711 | | - int Z, A, B, C, D, E, X1; |
| 24862 | + int Z, alpha, A, B, C, D, E, X1; |
| 24712 | 24863 | if( p->validYMD ) return; |
| 24713 | 24864 | if( !p->validJD ){ |
| 24714 | 24865 | p->Y = 2000; |
| 24715 | 24866 | p->M = 1; |
| 24716 | 24867 | p->D = 1; |
| | @@ -24717,12 +24868,12 @@ |
| 24717 | 24868 | }else if( !validJulianDay(p->iJD) ){ |
| 24718 | 24869 | datetimeError(p); |
| 24719 | 24870 | return; |
| 24720 | 24871 | }else{ |
| 24721 | 24872 | Z = (int)((p->iJD + 43200000)/86400000); |
| 24722 | | - A = (int)((Z - 1867216.25)/36524.25); |
| 24723 | | - A = Z + 1 + A - (A/4); |
| 24873 | + alpha = (int)((Z + 32044.75)/36524.25) - 52; |
| 24874 | + A = Z + 1 + alpha - ((alpha+100)/4) + 25; |
| 24724 | 24875 | B = A + 1524; |
| 24725 | 24876 | C = (int)((B - 122.1)/365.25); |
| 24726 | 24877 | D = (36525*(C&32767))/100; |
| 24727 | 24878 | E = (int)((B-D)/30.6001); |
| 24728 | 24879 | X1 = (int)(30.6001*E); |
| | @@ -32017,20 +32168,23 @@ |
| 32017 | 32168 | pItem = va_arg(ap, SrcItem*); |
| 32018 | 32169 | assert( bArgList==0 ); |
| 32019 | 32170 | if( pItem->zAlias && !flag_altform2 ){ |
| 32020 | 32171 | sqlite3_str_appendall(pAccum, pItem->zAlias); |
| 32021 | 32172 | }else if( pItem->zName ){ |
| 32022 | | - if( pItem->zDatabase ){ |
| 32023 | | - sqlite3_str_appendall(pAccum, pItem->zDatabase); |
| 32173 | + if( pItem->fg.fixedSchema==0 |
| 32174 | + && pItem->fg.isSubquery==0 |
| 32175 | + && pItem->u4.zDatabase!=0 |
| 32176 | + ){ |
| 32177 | + sqlite3_str_appendall(pAccum, pItem->u4.zDatabase); |
| 32024 | 32178 | sqlite3_str_append(pAccum, ".", 1); |
| 32025 | 32179 | } |
| 32026 | 32180 | sqlite3_str_appendall(pAccum, pItem->zName); |
| 32027 | 32181 | }else if( pItem->zAlias ){ |
| 32028 | 32182 | sqlite3_str_appendall(pAccum, pItem->zAlias); |
| 32029 | | - }else{ |
| 32030 | | - Select *pSel = pItem->pSelect; |
| 32031 | | - assert( pSel!=0 ); /* Because of tag-20240424-1 */ |
| 32183 | + }else if( ALWAYS(pItem->fg.isSubquery) ){/* Because of tag-20240424-1 */ |
| 32184 | + Select *pSel = pItem->u4.pSubq->pSelect; |
| 32185 | + assert( pSel!=0 ); |
| 32032 | 32186 | if( pSel->selFlags & SF_NestedFrom ){ |
| 32033 | 32187 | sqlite3_str_appendf(pAccum, "(join-%u)", pSel->selId); |
| 32034 | 32188 | }else if( pSel->selFlags & SF_MultiValue ){ |
| 32035 | 32189 | assert( !pItem->fg.isTabFunc && !pItem->fg.isIndexedBy ); |
| 32036 | 32190 | sqlite3_str_appendf(pAccum, "%u-ROW VALUES CLAUSE", |
| | @@ -32808,13 +32962,13 @@ |
| 32808 | 32962 | int n = 0; |
| 32809 | 32963 | char zLine[1000]; |
| 32810 | 32964 | sqlite3StrAccumInit(&x, 0, zLine, sizeof(zLine), 0); |
| 32811 | 32965 | x.printfFlags |= SQLITE_PRINTF_INTERNAL; |
| 32812 | 32966 | sqlite3_str_appendf(&x, "{%d:*} %!S", pItem->iCursor, pItem); |
| 32813 | | - if( pItem->pTab ){ |
| 32967 | + if( pItem->pSTab ){ |
| 32814 | 32968 | sqlite3_str_appendf(&x, " tab=%Q nCol=%d ptr=%p used=%llx%s", |
| 32815 | | - pItem->pTab->zName, pItem->pTab->nCol, pItem->pTab, |
| 32969 | + pItem->pSTab->zName, pItem->pSTab->nCol, pItem->pSTab, |
| 32816 | 32970 | pItem->colUsed, |
| 32817 | 32971 | pItem->fg.rowidUsed ? "+rowid" : ""); |
| 32818 | 32972 | } |
| 32819 | 32973 | if( (pItem->fg.jointype & (JT_LEFT|JT_RIGHT))==(JT_LEFT|JT_RIGHT) ){ |
| 32820 | 32974 | sqlite3_str_appendf(&x, " FULL-OUTER-JOIN"); |
| | @@ -32841,27 +32995,34 @@ |
| 32841 | 32995 | if( pItem->fg.isCorrelated ) sqlite3_str_appendf(&x, " isCorrelated"); |
| 32842 | 32996 | if( pItem->fg.isMaterialized ) sqlite3_str_appendf(&x, " isMaterialized"); |
| 32843 | 32997 | if( pItem->fg.viaCoroutine ) sqlite3_str_appendf(&x, " viaCoroutine"); |
| 32844 | 32998 | if( pItem->fg.notCte ) sqlite3_str_appendf(&x, " notCte"); |
| 32845 | 32999 | if( pItem->fg.isNestedFrom ) sqlite3_str_appendf(&x, " isNestedFrom"); |
| 33000 | + if( pItem->fg.fixedSchema ) sqlite3_str_appendf(&x, " fixedSchema"); |
| 33001 | + if( pItem->fg.hadSchema ) sqlite3_str_appendf(&x, " hadSchema"); |
| 33002 | + if( pItem->fg.isSubquery ) sqlite3_str_appendf(&x, " isSubquery"); |
| 32846 | 33003 | |
| 32847 | 33004 | sqlite3StrAccumFinish(&x); |
| 32848 | 33005 | sqlite3TreeViewItem(pView, zLine, i<pSrc->nSrc-1); |
| 32849 | 33006 | n = 0; |
| 32850 | | - if( pItem->pSelect ) n++; |
| 33007 | + if( pItem->fg.isSubquery ) n++; |
| 32851 | 33008 | if( pItem->fg.isTabFunc ) n++; |
| 32852 | 33009 | if( pItem->fg.isUsing ) n++; |
| 32853 | 33010 | if( pItem->fg.isUsing ){ |
| 32854 | 33011 | sqlite3TreeViewIdList(pView, pItem->u3.pUsing, (--n)>0, "USING"); |
| 32855 | 33012 | } |
| 32856 | | - if( pItem->pSelect ){ |
| 32857 | | - if( pItem->pTab ){ |
| 32858 | | - Table *pTab = pItem->pTab; |
| 33013 | + if( pItem->fg.isSubquery ){ |
| 33014 | + assert( n==1 ); |
| 33015 | + if( pItem->pSTab ){ |
| 33016 | + Table *pTab = pItem->pSTab; |
| 32859 | 33017 | sqlite3TreeViewColumnList(pView, pTab->aCol, pTab->nCol, 1); |
| 32860 | 33018 | } |
| 32861 | | - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); |
| 32862 | | - sqlite3TreeViewSelect(pView, pItem->pSelect, (--n)>0); |
| 33019 | + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); |
| 33020 | + sqlite3TreeViewPush(&pView, 0); |
| 33021 | + sqlite3TreeViewLine(pView, "SUBQUERY"); |
| 33022 | + sqlite3TreeViewPop(&pView); |
| 33023 | + sqlite3TreeViewSelect(pView, pItem->u4.pSubq->pSelect, 0); |
| 32863 | 33024 | } |
| 32864 | 33025 | if( pItem->fg.isTabFunc ){ |
| 32865 | 33026 | sqlite3TreeViewExprList(pView, pItem->u1.pFuncArg, 0, "func-args:"); |
| 32866 | 33027 | } |
| 32867 | 33028 | sqlite3TreeViewPop(&pView); |
| | @@ -38721,11 +38882,11 @@ |
| 38721 | 38882 | ** Allowed values for the unixFile.ctrlFlags bitmask: |
| 38722 | 38883 | */ |
| 38723 | 38884 | #define UNIXFILE_EXCL 0x01 /* Connections from one process only */ |
| 38724 | 38885 | #define UNIXFILE_RDONLY 0x02 /* Connection is read only */ |
| 38725 | 38886 | #define UNIXFILE_PERSIST_WAL 0x04 /* Persistent WAL mode */ |
| 38726 | | -#ifndef SQLITE_DISABLE_DIRSYNC |
| 38887 | +#if !defined(SQLITE_DISABLE_DIRSYNC) && !defined(_AIX) |
| 38727 | 38888 | # define UNIXFILE_DIRSYNC 0x08 /* Directory sync needed */ |
| 38728 | 38889 | #else |
| 38729 | 38890 | # define UNIXFILE_DIRSYNC 0x00 |
| 38730 | 38891 | #endif |
| 38731 | 38892 | #define UNIXFILE_PSOW 0x10 /* SQLITE_IOCAP_POWERSAFE_OVERWRITE */ |
| | @@ -95267,11 +95428,11 @@ |
| 95267 | 95428 | } |
| 95268 | 95429 | break; |
| 95269 | 95430 | } |
| 95270 | 95431 | #endif |
| 95271 | 95432 | |
| 95272 | | -#if !defined(SQLITE_OMIT_CAST) && !defined(SQLITE_OMIT_ANALYZE) |
| 95433 | +#if !defined(SQLITE_OMIT_CAST) || !defined(SQLITE_OMIT_ANALYZE) |
| 95273 | 95434 | /* Opcode: Cast P1 P2 * * * |
| 95274 | 95435 | ** Synopsis: affinity(r[P1]) |
| 95275 | 95436 | ** |
| 95276 | 95437 | ** Force the value in register P1 to be the type defined by P2. |
| 95277 | 95438 | ** |
| | @@ -106731,11 +106892,13 @@ |
| 106731 | 106892 | SrcItem *pItem; |
| 106732 | 106893 | |
| 106733 | 106894 | pSrc = p->pSrc; |
| 106734 | 106895 | if( ALWAYS(pSrc) ){ |
| 106735 | 106896 | for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ |
| 106736 | | - if( pItem->pSelect && sqlite3WalkSelect(pWalker, pItem->pSelect) ){ |
| 106897 | + if( pItem->fg.isSubquery |
| 106898 | + && sqlite3WalkSelect(pWalker, pItem->u4.pSubq->pSelect) |
| 106899 | + ){ |
| 106737 | 106900 | return WRC_Abort; |
| 106738 | 106901 | } |
| 106739 | 106902 | if( pItem->fg.isTabFunc |
| 106740 | 106903 | && sqlite3WalkExprList(pWalker, pItem->u1.pFuncArg) |
| 106741 | 106904 | ){ |
| | @@ -107037,11 +107200,11 @@ |
| 107037 | 107200 | ){ |
| 107038 | 107201 | Expr *pNew = sqlite3ExprAlloc(pParse->db, TK_COLUMN, 0, 0); |
| 107039 | 107202 | if( pNew ){ |
| 107040 | 107203 | pNew->iTable = pMatch->iCursor; |
| 107041 | 107204 | pNew->iColumn = iColumn; |
| 107042 | | - pNew->y.pTab = pMatch->pTab; |
| 107205 | + pNew->y.pTab = pMatch->pSTab; |
| 107043 | 107206 | assert( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ); |
| 107044 | 107207 | ExprSetProperty(pNew, EP_CanBeNull); |
| 107045 | 107208 | *ppList = sqlite3ExprListAppend(pParse, *ppList, pNew); |
| 107046 | 107209 | } |
| 107047 | 107210 | } |
| | @@ -107168,24 +107331,28 @@ |
| 107168 | 107331 | SrcList *pSrcList = pNC->pSrcList; |
| 107169 | 107332 | |
| 107170 | 107333 | if( pSrcList ){ |
| 107171 | 107334 | for(i=0, pItem=pSrcList->a; i<pSrcList->nSrc; i++, pItem++){ |
| 107172 | 107335 | u8 hCol; |
| 107173 | | - pTab = pItem->pTab; |
| 107336 | + pTab = pItem->pSTab; |
| 107174 | 107337 | assert( pTab!=0 && pTab->zName!=0 ); |
| 107175 | 107338 | assert( pTab->nCol>0 || pParse->nErr ); |
| 107176 | | - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); |
| 107339 | + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem)); |
| 107177 | 107340 | if( pItem->fg.isNestedFrom ){ |
| 107178 | 107341 | /* In this case, pItem is a subquery that has been formed from a |
| 107179 | 107342 | ** parenthesized subset of the FROM clause terms. Example: |
| 107180 | 107343 | ** .... FROM t1 LEFT JOIN (t2 RIGHT JOIN t3 USING(x)) USING(y) ... |
| 107181 | 107344 | ** \_________________________/ |
| 107182 | 107345 | ** This pItem -------------^ |
| 107183 | 107346 | */ |
| 107184 | 107347 | int hit = 0; |
| 107185 | | - assert( pItem->pSelect!=0 ); |
| 107186 | | - pEList = pItem->pSelect->pEList; |
| 107348 | + Select *pSel; |
| 107349 | + assert( pItem->fg.isSubquery ); |
| 107350 | + assert( pItem->u4.pSubq!=0 ); |
| 107351 | + pSel = pItem->u4.pSubq->pSelect; |
| 107352 | + assert( pSel!=0 ); |
| 107353 | + pEList = pSel->pEList; |
| 107187 | 107354 | assert( pEList!=0 ); |
| 107188 | 107355 | assert( pEList->nExpr==pTab->nCol ); |
| 107189 | 107356 | for(j=0; j<pEList->nExpr; j++){ |
| 107190 | 107357 | int bRowid = 0; /* True if possible rowid match */ |
| 107191 | 107358 | if( !sqlite3MatchEName(&pEList->a[j], zCol, zTab, zDb, &bRowid) ){ |
| | @@ -107305,12 +107472,12 @@ |
| 107305 | 107472 | ** words non-VIEW candidate terms take precedence over VIEWs. |
| 107306 | 107473 | */ |
| 107307 | 107474 | if( cntTab==0 |
| 107308 | 107475 | || (cntTab==1 |
| 107309 | 107476 | && ALWAYS(pMatch!=0) |
| 107310 | | - && ALWAYS(pMatch->pTab!=0) |
| 107311 | | - && (pMatch->pTab->tabFlags & TF_Ephemeral)!=0 |
| 107477 | + && ALWAYS(pMatch->pSTab!=0) |
| 107478 | + && (pMatch->pSTab->tabFlags & TF_Ephemeral)!=0 |
| 107312 | 107479 | && (pTab->tabFlags & TF_Ephemeral)==0) |
| 107313 | 107480 | ){ |
| 107314 | 107481 | cntTab = 1; |
| 107315 | 107482 | pMatch = pItem; |
| 107316 | 107483 | }else{ |
| | @@ -107327,11 +107494,11 @@ |
| 107327 | 107494 | } |
| 107328 | 107495 | } |
| 107329 | 107496 | if( pMatch ){ |
| 107330 | 107497 | pExpr->iTable = pMatch->iCursor; |
| 107331 | 107498 | assert( ExprUseYTab(pExpr) ); |
| 107332 | | - pExpr->y.pTab = pMatch->pTab; |
| 107499 | + pExpr->y.pTab = pMatch->pSTab; |
| 107333 | 107500 | if( (pMatch->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 ){ |
| 107334 | 107501 | ExprSetProperty(pExpr, EP_CanBeNull); |
| 107335 | 107502 | } |
| 107336 | 107503 | pSchema = pExpr->y.pTab->pSchema; |
| 107337 | 107504 | } |
| | @@ -107369,11 +107536,11 @@ |
| 107369 | 107536 | #endif /* SQLITE_OMIT_TRIGGER */ |
| 107370 | 107537 | #ifndef SQLITE_OMIT_UPSERT |
| 107371 | 107538 | if( (pNC->ncFlags & NC_UUpsert)!=0 && zTab!=0 ){ |
| 107372 | 107539 | Upsert *pUpsert = pNC->uNC.pUpsert; |
| 107373 | 107540 | if( pUpsert && sqlite3StrICmp("excluded",zTab)==0 ){ |
| 107374 | | - pTab = pUpsert->pUpsertSrc->a[0].pTab; |
| 107541 | + pTab = pUpsert->pUpsertSrc->a[0].pSTab; |
| 107375 | 107542 | pExpr->iTable = EXCLUDED_TABLE_NUMBER; |
| 107376 | 107543 | } |
| 107377 | 107544 | } |
| 107378 | 107545 | #endif /* SQLITE_OMIT_UPSERT */ |
| 107379 | 107546 | |
| | @@ -107452,15 +107619,15 @@ |
| 107452 | 107619 | if( cnt==0 |
| 107453 | 107620 | && cntTab>=1 |
| 107454 | 107621 | && pMatch |
| 107455 | 107622 | && (pNC->ncFlags & (NC_IdxExpr|NC_GenCol))==0 |
| 107456 | 107623 | && sqlite3IsRowid(zCol) |
| 107457 | | - && ALWAYS(VisibleRowid(pMatch->pTab) || pMatch->fg.isNestedFrom) |
| 107624 | + && ALWAYS(VisibleRowid(pMatch->pSTab) || pMatch->fg.isNestedFrom) |
| 107458 | 107625 | ){ |
| 107459 | 107626 | cnt = cntTab; |
| 107460 | 107627 | #if SQLITE_ALLOW_ROWID_IN_VIEW+0==2 |
| 107461 | | - if( pMatch->pTab!=0 && IsView(pMatch->pTab) ){ |
| 107628 | + if( pMatch->pSTab!=0 && IsView(pMatch->pSTab) ){ |
| 107462 | 107629 | eNewExprOp = TK_NULL; |
| 107463 | 107630 | } |
| 107464 | 107631 | #endif |
| 107465 | 107632 | if( pMatch->fg.isNestedFrom==0 ) pExpr->iColumn = -1; |
| 107466 | 107633 | pExpr->affExpr = SQLITE_AFF_INTEGER; |
| | @@ -107693,11 +107860,11 @@ |
| 107693 | 107860 | Expr *p = sqlite3ExprAlloc(db, TK_COLUMN, 0, 0); |
| 107694 | 107861 | if( p ){ |
| 107695 | 107862 | SrcItem *pItem = &pSrc->a[iSrc]; |
| 107696 | 107863 | Table *pTab; |
| 107697 | 107864 | assert( ExprUseYTab(p) ); |
| 107698 | | - pTab = p->y.pTab = pItem->pTab; |
| 107865 | + pTab = p->y.pTab = pItem->pSTab; |
| 107699 | 107866 | p->iTable = pItem->iCursor; |
| 107700 | 107867 | if( p->y.pTab->iPKey==iCol ){ |
| 107701 | 107868 | p->iColumn = -1; |
| 107702 | 107869 | }else{ |
| 107703 | 107870 | p->iColumn = (ynVar)iCol; |
| | @@ -107812,11 +107979,11 @@ |
| 107812 | 107979 | SrcItem *pItem; |
| 107813 | 107980 | assert( pSrcList && pSrcList->nSrc>=1 ); |
| 107814 | 107981 | pItem = pSrcList->a; |
| 107815 | 107982 | pExpr->op = TK_COLUMN; |
| 107816 | 107983 | assert( ExprUseYTab(pExpr) ); |
| 107817 | | - pExpr->y.pTab = pItem->pTab; |
| 107984 | + pExpr->y.pTab = pItem->pSTab; |
| 107818 | 107985 | pExpr->iTable = pItem->iCursor; |
| 107819 | 107986 | pExpr->iColumn--; |
| 107820 | 107987 | pExpr->affExpr = SQLITE_AFF_INTEGER; |
| 107821 | 107988 | break; |
| 107822 | 107989 | } |
| | @@ -108702,11 +108869,15 @@ |
| 108702 | 108869 | ** In this case the ORDER BY clause (p->pOrderBy) should be resolved |
| 108703 | 108870 | ** as if it were part of the sub-query, not the parent. This block |
| 108704 | 108871 | ** moves the pOrderBy down to the sub-query. It will be moved back |
| 108705 | 108872 | ** after the names have been resolved. */ |
| 108706 | 108873 | if( p->selFlags & SF_Converted ){ |
| 108707 | | - Select *pSub = p->pSrc->a[0].pSelect; |
| 108874 | + Select *pSub; |
| 108875 | + assert( p->pSrc->a[0].fg.isSubquery ); |
| 108876 | + assert( p->pSrc->a[0].u4.pSubq!=0 ); |
| 108877 | + pSub = p->pSrc->a[0].u4.pSubq->pSelect; |
| 108878 | + assert( pSub!=0 ); |
| 108708 | 108879 | assert( p->pSrc->nSrc==1 && p->pOrderBy ); |
| 108709 | 108880 | assert( pSub->pPrior && pSub->pOrderBy==0 ); |
| 108710 | 108881 | pSub->pOrderBy = p->pOrderBy; |
| 108711 | 108882 | p->pOrderBy = 0; |
| 108712 | 108883 | } |
| | @@ -108714,17 +108885,20 @@ |
| 108714 | 108885 | /* Recursively resolve names in all subqueries in the FROM clause |
| 108715 | 108886 | */ |
| 108716 | 108887 | if( pOuterNC ) pOuterNC->nNestedSelect++; |
| 108717 | 108888 | for(i=0; i<p->pSrc->nSrc; i++){ |
| 108718 | 108889 | SrcItem *pItem = &p->pSrc->a[i]; |
| 108719 | | - assert( pItem->zName!=0 || pItem->pSelect!=0 );/* Test of tag-20240424-1*/ |
| 108720 | | - if( pItem->pSelect && (pItem->pSelect->selFlags & SF_Resolved)==0 ){ |
| 108890 | + assert( pItem->zName!=0 |
| 108891 | + || pItem->fg.isSubquery ); /* Test of tag-20240424-1*/ |
| 108892 | + if( pItem->fg.isSubquery |
| 108893 | + && (pItem->u4.pSubq->pSelect->selFlags & SF_Resolved)==0 |
| 108894 | + ){ |
| 108721 | 108895 | int nRef = pOuterNC ? pOuterNC->nRef : 0; |
| 108722 | 108896 | const char *zSavedContext = pParse->zAuthContext; |
| 108723 | 108897 | |
| 108724 | 108898 | if( pItem->zName ) pParse->zAuthContext = pItem->zName; |
| 108725 | | - sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); |
| 108899 | + sqlite3ResolveSelectNames(pParse, pItem->u4.pSubq->pSelect, pOuterNC); |
| 108726 | 108900 | pParse->zAuthContext = zSavedContext; |
| 108727 | 108901 | if( pParse->nErr ) return WRC_Abort; |
| 108728 | 108902 | assert( db->mallocFailed==0 ); |
| 108729 | 108903 | |
| 108730 | 108904 | /* If the number of references to the outer context changed when |
| | @@ -108822,11 +108996,14 @@ |
| 108822 | 108996 | ** the sub-query back to the parent query. At this point each term |
| 108823 | 108997 | ** within the ORDER BY clause has been transformed to an integer value. |
| 108824 | 108998 | ** These integers will be replaced by copies of the corresponding result |
| 108825 | 108999 | ** set expressions by the call to resolveOrderGroupBy() below. */ |
| 108826 | 109000 | if( p->selFlags & SF_Converted ){ |
| 108827 | | - Select *pSub = p->pSrc->a[0].pSelect; |
| 109001 | + Select *pSub; |
| 109002 | + assert( p->pSrc->a[0].fg.isSubquery ); |
| 109003 | + pSub = p->pSrc->a[0].u4.pSubq->pSelect; |
| 109004 | + assert( pSub!=0 ); |
| 108828 | 109005 | p->pOrderBy = pSub->pOrderBy; |
| 108829 | 109006 | pSub->pOrderBy = 0; |
| 108830 | 109007 | } |
| 108831 | 109008 | |
| 108832 | 109009 | /* Process the ORDER BY clause for singleton SELECT statements. |
| | @@ -109089,11 +109266,11 @@ |
| 109089 | 109266 | memset(&sNC, 0, sizeof(sNC)); |
| 109090 | 109267 | memset(&sSrc, 0, sizeof(sSrc)); |
| 109091 | 109268 | if( pTab ){ |
| 109092 | 109269 | sSrc.nSrc = 1; |
| 109093 | 109270 | sSrc.a[0].zName = pTab->zName; |
| 109094 | | - sSrc.a[0].pTab = pTab; |
| 109271 | + sSrc.a[0].pSTab = pTab; |
| 109095 | 109272 | sSrc.a[0].iCursor = -1; |
| 109096 | 109273 | if( pTab->pSchema!=pParse->db->aDb[1].pSchema ){ |
| 109097 | 109274 | /* Cause EP_FromDDL to be set on TK_FUNCTION nodes of non-TEMP |
| 109098 | 109275 | ** schema elements */ |
| 109099 | 109276 | type |= NC_FromDDL; |
| | @@ -110986,19 +111163,34 @@ |
| 110986 | 111163 | pNew->nSrc = pNew->nAlloc = p->nSrc; |
| 110987 | 111164 | for(i=0; i<p->nSrc; i++){ |
| 110988 | 111165 | SrcItem *pNewItem = &pNew->a[i]; |
| 110989 | 111166 | const SrcItem *pOldItem = &p->a[i]; |
| 110990 | 111167 | Table *pTab; |
| 110991 | | - pNewItem->pSchema = pOldItem->pSchema; |
| 110992 | | - pNewItem->zDatabase = sqlite3DbStrDup(db, pOldItem->zDatabase); |
| 111168 | + pNewItem->fg = pOldItem->fg; |
| 111169 | + if( pOldItem->fg.isSubquery ){ |
| 111170 | + Subquery *pNewSubq = sqlite3DbMallocRaw(db, sizeof(Subquery)); |
| 111171 | + if( pNewSubq==0 ){ |
| 111172 | + assert( db->mallocFailed ); |
| 111173 | + pNewItem->fg.isSubquery = 0; |
| 111174 | + }else{ |
| 111175 | + memcpy(pNewSubq, pOldItem->u4.pSubq, sizeof(*pNewSubq)); |
| 111176 | + pNewSubq->pSelect = sqlite3SelectDup(db, pNewSubq->pSelect, flags); |
| 111177 | + if( pNewSubq->pSelect==0 ){ |
| 111178 | + sqlite3DbFree(db, pNewSubq); |
| 111179 | + pNewSubq = 0; |
| 111180 | + pNewItem->fg.isSubquery = 0; |
| 111181 | + } |
| 111182 | + } |
| 111183 | + pNewItem->u4.pSubq = pNewSubq; |
| 111184 | + }else if( pOldItem->fg.fixedSchema ){ |
| 111185 | + pNewItem->u4.pSchema = pOldItem->u4.pSchema; |
| 111186 | + }else{ |
| 111187 | + pNewItem->u4.zDatabase = sqlite3DbStrDup(db, pOldItem->u4.zDatabase); |
| 111188 | + } |
| 110993 | 111189 | pNewItem->zName = sqlite3DbStrDup(db, pOldItem->zName); |
| 110994 | 111190 | pNewItem->zAlias = sqlite3DbStrDup(db, pOldItem->zAlias); |
| 110995 | | - pNewItem->fg = pOldItem->fg; |
| 110996 | 111191 | pNewItem->iCursor = pOldItem->iCursor; |
| 110997 | | - pNewItem->addrFillSub = pOldItem->addrFillSub; |
| 110998 | | - pNewItem->regReturn = pOldItem->regReturn; |
| 110999 | | - pNewItem->regResult = pOldItem->regResult; |
| 111000 | 111192 | if( pNewItem->fg.isIndexedBy ){ |
| 111001 | 111193 | pNewItem->u1.zIndexedBy = sqlite3DbStrDup(db, pOldItem->u1.zIndexedBy); |
| 111002 | 111194 | }else if( pNewItem->fg.isTabFunc ){ |
| 111003 | 111195 | pNewItem->u1.pFuncArg = |
| 111004 | 111196 | sqlite3ExprListDup(db, pOldItem->u1.pFuncArg, flags); |
| | @@ -111007,15 +111199,14 @@ |
| 111007 | 111199 | } |
| 111008 | 111200 | pNewItem->u2 = pOldItem->u2; |
| 111009 | 111201 | if( pNewItem->fg.isCte ){ |
| 111010 | 111202 | pNewItem->u2.pCteUse->nUse++; |
| 111011 | 111203 | } |
| 111012 | | - pTab = pNewItem->pTab = pOldItem->pTab; |
| 111204 | + pTab = pNewItem->pSTab = pOldItem->pSTab; |
| 111013 | 111205 | if( pTab ){ |
| 111014 | 111206 | pTab->nTabRef++; |
| 111015 | 111207 | } |
| 111016 | | - pNewItem->pSelect = sqlite3SelectDup(db, pOldItem->pSelect, flags); |
| 111017 | 111208 | if( pOldItem->fg.isUsing ){ |
| 111018 | 111209 | assert( pNewItem->fg.isUsing ); |
| 111019 | 111210 | pNewItem->u3.pUsing = sqlite3IdListDup(db, pOldItem->u3.pUsing); |
| 111020 | 111211 | }else{ |
| 111021 | 111212 | pNewItem->u3.pOn = sqlite3ExprDup(db, pOldItem->u3.pOn, flags); |
| | @@ -111085,11 +111276,10 @@ |
| 111085 | 111276 | } |
| 111086 | 111277 | *pp = pNew; |
| 111087 | 111278 | pp = &pNew->pPrior; |
| 111088 | 111279 | pNext = pNew; |
| 111089 | 111280 | } |
| 111090 | | - |
| 111091 | 111281 | return pRet; |
| 111092 | 111282 | } |
| 111093 | 111283 | #else |
| 111094 | 111284 | SQLITE_PRIVATE Select *sqlite3SelectDup(sqlite3 *db, const Select *p, int flags){ |
| 111095 | 111285 | assert( p==0 ); |
| | @@ -112105,12 +112295,12 @@ |
| 112105 | 112295 | if( p->pLimit ) return 0; /* Has no LIMIT clause */ |
| 112106 | 112296 | if( p->pWhere ) return 0; /* Has no WHERE clause */ |
| 112107 | 112297 | pSrc = p->pSrc; |
| 112108 | 112298 | assert( pSrc!=0 ); |
| 112109 | 112299 | if( pSrc->nSrc!=1 ) return 0; /* Single term in FROM clause */ |
| 112110 | | - if( pSrc->a[0].pSelect ) return 0; /* FROM is not a subquery or view */ |
| 112111 | | - pTab = pSrc->a[0].pTab; |
| 112300 | + if( pSrc->a[0].fg.isSubquery) return 0;/* FROM is not a subquery or view */ |
| 112301 | + pTab = pSrc->a[0].pSTab; |
| 112112 | 112302 | assert( pTab!=0 ); |
| 112113 | 112303 | assert( !IsView(pTab) ); /* FROM clause is not a view */ |
| 112114 | 112304 | if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */ |
| 112115 | 112305 | pEList = p->pEList; |
| 112116 | 112306 | assert( pEList!=0 ); |
| | @@ -112289,11 +112479,11 @@ |
| 112289 | 112479 | int nExpr = pEList->nExpr; |
| 112290 | 112480 | |
| 112291 | 112481 | assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */ |
| 112292 | 112482 | assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */ |
| 112293 | 112483 | assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */ |
| 112294 | | - pTab = p->pSrc->a[0].pTab; |
| 112484 | + pTab = p->pSrc->a[0].pSTab; |
| 112295 | 112485 | |
| 112296 | 112486 | /* Code an OP_Transaction and OP_TableLock for <table>. */ |
| 112297 | 112487 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 112298 | 112488 | assert( iDb>=0 && iDb<SQLITE_MAX_DB ); |
| 112299 | 112489 | sqlite3CodeVerifySchema(pParse, iDb); |
| | @@ -117727,12 +117917,13 @@ |
| 117727 | 117917 | } |
| 117728 | 117918 | if( pStep->pFrom ){ |
| 117729 | 117919 | int i; |
| 117730 | 117920 | for(i=0; i<pStep->pFrom->nSrc && rc==SQLITE_OK; i++){ |
| 117731 | 117921 | SrcItem *p = &pStep->pFrom->a[i]; |
| 117732 | | - if( p->pSelect ){ |
| 117733 | | - sqlite3SelectPrep(pParse, p->pSelect, 0); |
| 117922 | + if( p->fg.isSubquery ){ |
| 117923 | + assert( p->u4.pSubq!=0 ); |
| 117924 | + sqlite3SelectPrep(pParse, p->u4.pSubq->pSelect, 0); |
| 117734 | 117925 | } |
| 117735 | 117926 | } |
| 117736 | 117927 | } |
| 117737 | 117928 | |
| 117738 | 117929 | if( db->mallocFailed ){ |
| | @@ -117796,12 +117987,16 @@ |
| 117796 | 117987 | sqlite3WalkExpr(pWalker, pUpsert->pUpsertWhere); |
| 117797 | 117988 | sqlite3WalkExpr(pWalker, pUpsert->pUpsertTargetWhere); |
| 117798 | 117989 | } |
| 117799 | 117990 | if( pStep->pFrom ){ |
| 117800 | 117991 | int i; |
| 117801 | | - for(i=0; i<pStep->pFrom->nSrc; i++){ |
| 117802 | | - sqlite3WalkSelect(pWalker, pStep->pFrom->a[i].pSelect); |
| 117992 | + SrcList *pFrom = pStep->pFrom; |
| 117993 | + for(i=0; i<pFrom->nSrc; i++){ |
| 117994 | + if( pFrom->a[i].fg.isSubquery ){ |
| 117995 | + assert( pFrom->a[i].u4.pSubq!=0 ); |
| 117996 | + sqlite3WalkSelect(pWalker, pFrom->a[i].u4.pSubq->pSelect); |
| 117997 | + } |
| 117803 | 117998 | } |
| 117804 | 117999 | } |
| 117805 | 118000 | } |
| 117806 | 118001 | } |
| 117807 | 118002 | |
| | @@ -118044,11 +118239,11 @@ |
| 118044 | 118239 | assert( pWalker->pParse->db->mallocFailed ); |
| 118045 | 118240 | return WRC_Abort; |
| 118046 | 118241 | } |
| 118047 | 118242 | for(i=0; i<pSrc->nSrc; i++){ |
| 118048 | 118243 | SrcItem *pItem = &pSrc->a[i]; |
| 118049 | | - if( pItem->pTab==p->pTab ){ |
| 118244 | + if( pItem->pSTab==p->pTab ){ |
| 118050 | 118245 | renameTokenFind(pWalker->pParse, p, pItem->zName); |
| 118051 | 118246 | } |
| 118052 | 118247 | } |
| 118053 | 118248 | renameWalkWith(pWalker, pSelect); |
| 118054 | 118249 | |
| | @@ -121178,24 +121373,25 @@ |
| 121178 | 121373 | int iDb = sqlite3FindDbName(db, pFix->zDb); |
| 121179 | 121374 | SrcList *pList = pSelect->pSrc; |
| 121180 | 121375 | |
| 121181 | 121376 | if( NEVER(pList==0) ) return WRC_Continue; |
| 121182 | 121377 | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ |
| 121183 | | - if( pFix->bTemp==0 ){ |
| 121184 | | - if( pItem->zDatabase ){ |
| 121185 | | - if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ |
| 121378 | + if( pFix->bTemp==0 && pItem->fg.isSubquery==0 ){ |
| 121379 | + if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ |
| 121380 | + if( iDb!=sqlite3FindDbName(db, pItem->u4.zDatabase) ){ |
| 121186 | 121381 | sqlite3ErrorMsg(pFix->pParse, |
| 121187 | 121382 | "%s %T cannot reference objects in database %s", |
| 121188 | | - pFix->zType, pFix->pName, pItem->zDatabase); |
| 121383 | + pFix->zType, pFix->pName, pItem->u4.zDatabase); |
| 121189 | 121384 | return WRC_Abort; |
| 121190 | 121385 | } |
| 121191 | | - sqlite3DbFree(db, pItem->zDatabase); |
| 121192 | | - pItem->zDatabase = 0; |
| 121386 | + sqlite3DbFree(db, pItem->u4.zDatabase); |
| 121193 | 121387 | pItem->fg.notCte = 1; |
| 121388 | + pItem->fg.hadSchema = 1; |
| 121194 | 121389 | } |
| 121195 | | - pItem->pSchema = pFix->pSchema; |
| 121390 | + pItem->u4.pSchema = pFix->pSchema; |
| 121196 | 121391 | pItem->fg.fromDDL = 1; |
| 121392 | + pItem->fg.fixedSchema = 1; |
| 121197 | 121393 | } |
| 121198 | 121394 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) |
| 121199 | 121395 | if( pList->a[i].fg.isUsing==0 |
| 121200 | 121396 | && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn) |
| 121201 | 121397 | ){ |
| | @@ -121484,11 +121680,11 @@ |
| 121484 | 121680 | pTab = pParse->pTriggerTab; |
| 121485 | 121681 | }else{ |
| 121486 | 121682 | assert( pTabList ); |
| 121487 | 121683 | for(iSrc=0; iSrc<pTabList->nSrc; iSrc++){ |
| 121488 | 121684 | if( pExpr->iTable==pTabList->a[iSrc].iCursor ){ |
| 121489 | | - pTab = pTabList->a[iSrc].pTab; |
| 121685 | + pTab = pTabList->a[iSrc].pSTab; |
| 121490 | 121686 | break; |
| 121491 | 121687 | } |
| 121492 | 121688 | } |
| 121493 | 121689 | } |
| 121494 | 121690 | iCol = pExpr->iColumn; |
| | @@ -122087,16 +122283,16 @@ |
| 122087 | 122283 | Parse *pParse, |
| 122088 | 122284 | u32 flags, |
| 122089 | 122285 | SrcItem *p |
| 122090 | 122286 | ){ |
| 122091 | 122287 | const char *zDb; |
| 122092 | | - assert( p->pSchema==0 || p->zDatabase==0 ); |
| 122093 | | - if( p->pSchema ){ |
| 122094 | | - int iDb = sqlite3SchemaToIndex(pParse->db, p->pSchema); |
| 122288 | + if( p->fg.fixedSchema ){ |
| 122289 | + int iDb = sqlite3SchemaToIndex(pParse->db, p->u4.pSchema); |
| 122095 | 122290 | zDb = pParse->db->aDb[iDb].zDbSName; |
| 122096 | 122291 | }else{ |
| 122097 | | - zDb = p->zDatabase; |
| 122292 | + assert( !p->fg.isSubquery ); |
| 122293 | + zDb = p->u4.zDatabase; |
| 122098 | 122294 | } |
| 122099 | 122295 | return sqlite3LocateTable(pParse, flags, p->zName, zDb); |
| 122100 | 122296 | } |
| 122101 | 122297 | |
| 122102 | 122298 | /* |
| | @@ -125077,19 +125273,21 @@ |
| 125077 | 125273 | if( db->mallocFailed ){ |
| 125078 | 125274 | goto exit_drop_table; |
| 125079 | 125275 | } |
| 125080 | 125276 | assert( pParse->nErr==0 ); |
| 125081 | 125277 | assert( pName->nSrc==1 ); |
| 125278 | + assert( pName->a[0].fg.fixedSchema==0 ); |
| 125279 | + assert( pName->a[0].fg.isSubquery==0 ); |
| 125082 | 125280 | if( sqlite3ReadSchema(pParse) ) goto exit_drop_table; |
| 125083 | 125281 | if( noErr ) db->suppressErr++; |
| 125084 | 125282 | assert( isView==0 || isView==LOCATE_VIEW ); |
| 125085 | 125283 | pTab = sqlite3LocateTableItem(pParse, isView, &pName->a[0]); |
| 125086 | 125284 | if( noErr ) db->suppressErr--; |
| 125087 | 125285 | |
| 125088 | 125286 | if( pTab==0 ){ |
| 125089 | 125287 | if( noErr ){ |
| 125090 | | - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); |
| 125288 | + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); |
| 125091 | 125289 | sqlite3ForceNotReadOnly(pParse); |
| 125092 | 125290 | } |
| 125093 | 125291 | goto exit_drop_table; |
| 125094 | 125292 | } |
| 125095 | 125293 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| | @@ -126176,19 +126374,21 @@ |
| 126176 | 126374 | if( db->mallocFailed ){ |
| 126177 | 126375 | goto exit_drop_index; |
| 126178 | 126376 | } |
| 126179 | 126377 | assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ |
| 126180 | 126378 | assert( pName->nSrc==1 ); |
| 126379 | + assert( pName->a[0].fg.fixedSchema==0 ); |
| 126380 | + assert( pName->a[0].fg.isSubquery==0 ); |
| 126181 | 126381 | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| 126182 | 126382 | goto exit_drop_index; |
| 126183 | 126383 | } |
| 126184 | | - pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].zDatabase); |
| 126384 | + pIndex = sqlite3FindIndex(db, pName->a[0].zName, pName->a[0].u4.zDatabase); |
| 126185 | 126385 | if( pIndex==0 ){ |
| 126186 | 126386 | if( !ifExists ){ |
| 126187 | 126387 | sqlite3ErrorMsg(pParse, "no such index: %S", pName->a); |
| 126188 | 126388 | }else{ |
| 126189 | | - sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].zDatabase); |
| 126389 | + sqlite3CodeVerifyNamedSchema(pParse, pName->a[0].u4.zDatabase); |
| 126190 | 126390 | sqlite3ForceNotReadOnly(pParse); |
| 126191 | 126391 | } |
| 126192 | 126392 | pParse->checkSchema = 1; |
| 126193 | 126393 | goto exit_drop_index; |
| 126194 | 126394 | } |
| | @@ -126481,16 +126681,18 @@ |
| 126481 | 126681 | } |
| 126482 | 126682 | pItem = &pList->a[pList->nSrc-1]; |
| 126483 | 126683 | if( pDatabase && pDatabase->z==0 ){ |
| 126484 | 126684 | pDatabase = 0; |
| 126485 | 126685 | } |
| 126686 | + assert( pItem->fg.fixedSchema==0 ); |
| 126687 | + assert( pItem->fg.isSubquery==0 ); |
| 126486 | 126688 | if( pDatabase ){ |
| 126487 | 126689 | pItem->zName = sqlite3NameFromToken(db, pDatabase); |
| 126488 | | - pItem->zDatabase = sqlite3NameFromToken(db, pTable); |
| 126690 | + pItem->u4.zDatabase = sqlite3NameFromToken(db, pTable); |
| 126489 | 126691 | }else{ |
| 126490 | 126692 | pItem->zName = sqlite3NameFromToken(db, pTable); |
| 126491 | | - pItem->zDatabase = 0; |
| 126693 | + pItem->u4.zDatabase = 0; |
| 126492 | 126694 | } |
| 126493 | 126695 | return pList; |
| 126494 | 126696 | } |
| 126495 | 126697 | |
| 126496 | 126698 | /* |
| | @@ -126502,16 +126704,43 @@ |
| 126502 | 126704 | assert( pList || pParse->db->mallocFailed ); |
| 126503 | 126705 | if( ALWAYS(pList) ){ |
| 126504 | 126706 | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ |
| 126505 | 126707 | if( pItem->iCursor>=0 ) continue; |
| 126506 | 126708 | pItem->iCursor = pParse->nTab++; |
| 126507 | | - if( pItem->pSelect ){ |
| 126508 | | - sqlite3SrcListAssignCursors(pParse, pItem->pSelect->pSrc); |
| 126709 | + if( pItem->fg.isSubquery ){ |
| 126710 | + assert( pItem->u4.pSubq!=0 ); |
| 126711 | + assert( pItem->u4.pSubq->pSelect!=0 ); |
| 126712 | + assert( pItem->u4.pSubq->pSelect->pSrc!=0 ); |
| 126713 | + sqlite3SrcListAssignCursors(pParse, pItem->u4.pSubq->pSelect->pSrc); |
| 126509 | 126714 | } |
| 126510 | 126715 | } |
| 126511 | 126716 | } |
| 126512 | 126717 | } |
| 126718 | + |
| 126719 | +/* |
| 126720 | +** Delete a Subquery object and its substructure. |
| 126721 | +*/ |
| 126722 | +SQLITE_PRIVATE void sqlite3SubqueryDelete(sqlite3 *db, Subquery *pSubq){ |
| 126723 | + assert( pSubq!=0 && pSubq->pSelect!=0 ); |
| 126724 | + sqlite3SelectDelete(db, pSubq->pSelect); |
| 126725 | + sqlite3DbFree(db, pSubq); |
| 126726 | +} |
| 126727 | + |
| 126728 | +/* |
| 126729 | +** Remove a Subquery from a SrcItem. Return the associated Select object. |
| 126730 | +** The returned Select becomes the responsibility of the caller. |
| 126731 | +*/ |
| 126732 | +SQLITE_PRIVATE Select *sqlite3SubqueryDetach(sqlite3 *db, SrcItem *pItem){ |
| 126733 | + Select *pSel; |
| 126734 | + assert( pItem!=0 ); |
| 126735 | + assert( pItem->fg.isSubquery ); |
| 126736 | + pSel = pItem->u4.pSubq->pSelect; |
| 126737 | + sqlite3DbFree(db, pItem->u4.pSubq); |
| 126738 | + pItem->u4.pSubq = 0; |
| 126739 | + pItem->fg.isSubquery = 0; |
| 126740 | + return pSel; |
| 126741 | +} |
| 126513 | 126742 | |
| 126514 | 126743 | /* |
| 126515 | 126744 | ** Delete an entire SrcList including all its substructure. |
| 126516 | 126745 | */ |
| 126517 | 126746 | SQLITE_PRIVATE void sqlite3SrcListDelete(sqlite3 *db, SrcList *pList){ |
| | @@ -126518,25 +126747,84 @@ |
| 126518 | 126747 | int i; |
| 126519 | 126748 | SrcItem *pItem; |
| 126520 | 126749 | assert( db!=0 ); |
| 126521 | 126750 | if( pList==0 ) return; |
| 126522 | 126751 | for(pItem=pList->a, i=0; i<pList->nSrc; i++, pItem++){ |
| 126523 | | - if( pItem->zDatabase ) sqlite3DbNNFreeNN(db, pItem->zDatabase); |
| 126752 | + |
| 126753 | + /* Check invariants on SrcItem */ |
| 126754 | + assert( !pItem->fg.isIndexedBy || !pItem->fg.isTabFunc ); |
| 126755 | + assert( !pItem->fg.isCte || !pItem->fg.isIndexedBy ); |
| 126756 | + assert( !pItem->fg.fixedSchema || !pItem->fg.isSubquery ); |
| 126757 | + assert( !pItem->fg.isSubquery || (pItem->u4.pSubq!=0 && |
| 126758 | + pItem->u4.pSubq->pSelect!=0) ); |
| 126759 | + |
| 126524 | 126760 | if( pItem->zName ) sqlite3DbNNFreeNN(db, pItem->zName); |
| 126525 | 126761 | if( pItem->zAlias ) sqlite3DbNNFreeNN(db, pItem->zAlias); |
| 126762 | + if( pItem->fg.isSubquery ){ |
| 126763 | + sqlite3SubqueryDelete(db, pItem->u4.pSubq); |
| 126764 | + }else if( pItem->fg.fixedSchema==0 && pItem->u4.zDatabase!=0 ){ |
| 126765 | + sqlite3DbNNFreeNN(db, pItem->u4.zDatabase); |
| 126766 | + } |
| 126526 | 126767 | if( pItem->fg.isIndexedBy ) sqlite3DbFree(db, pItem->u1.zIndexedBy); |
| 126527 | 126768 | if( pItem->fg.isTabFunc ) sqlite3ExprListDelete(db, pItem->u1.pFuncArg); |
| 126528 | | - sqlite3DeleteTable(db, pItem->pTab); |
| 126529 | | - if( pItem->pSelect ) sqlite3SelectDelete(db, pItem->pSelect); |
| 126769 | + sqlite3DeleteTable(db, pItem->pSTab); |
| 126530 | 126770 | if( pItem->fg.isUsing ){ |
| 126531 | 126771 | sqlite3IdListDelete(db, pItem->u3.pUsing); |
| 126532 | 126772 | }else if( pItem->u3.pOn ){ |
| 126533 | 126773 | sqlite3ExprDelete(db, pItem->u3.pOn); |
| 126534 | 126774 | } |
| 126535 | 126775 | } |
| 126536 | 126776 | sqlite3DbNNFreeNN(db, pList); |
| 126537 | 126777 | } |
| 126778 | + |
| 126779 | +/* |
| 126780 | +** Attach a Subquery object to pItem->uv.pSubq. Set the |
| 126781 | +** pSelect value but leave all the other values initialized |
| 126782 | +** to zero. |
| 126783 | +** |
| 126784 | +** A copy of the Select object is made if dupSelect is true, and the |
| 126785 | +** SrcItem takes responsibility for deleting the copy. If dupSelect is |
| 126786 | +** false, ownership of the Select passes to the SrcItem. Either way, |
| 126787 | +** the SrcItem will take responsibility for deleting the Select. |
| 126788 | +** |
| 126789 | +** When dupSelect is zero, that means the Select might get deleted right |
| 126790 | +** away if there is an OOM error. Beware. |
| 126791 | +** |
| 126792 | +** Return non-zero on success. Return zero on an OOM error. |
| 126793 | +*/ |
| 126794 | +SQLITE_PRIVATE int sqlite3SrcItemAttachSubquery( |
| 126795 | + Parse *pParse, /* Parsing context */ |
| 126796 | + SrcItem *pItem, /* Item to which the subquery is to be attached */ |
| 126797 | + Select *pSelect, /* The subquery SELECT. Must be non-NULL */ |
| 126798 | + int dupSelect /* If true, attach a copy of pSelect, not pSelect itself.*/ |
| 126799 | +){ |
| 126800 | + Subquery *p; |
| 126801 | + assert( pSelect!=0 ); |
| 126802 | + assert( pItem->fg.isSubquery==0 ); |
| 126803 | + if( pItem->fg.fixedSchema ){ |
| 126804 | + pItem->u4.pSchema = 0; |
| 126805 | + pItem->fg.fixedSchema = 0; |
| 126806 | + }else if( pItem->u4.zDatabase!=0 ){ |
| 126807 | + sqlite3DbFree(pParse->db, pItem->u4.zDatabase); |
| 126808 | + pItem->u4.zDatabase = 0; |
| 126809 | + } |
| 126810 | + if( dupSelect ){ |
| 126811 | + pSelect = sqlite3SelectDup(pParse->db, pSelect, 0); |
| 126812 | + if( pSelect==0 ) return 0; |
| 126813 | + } |
| 126814 | + p = pItem->u4.pSubq = sqlite3DbMallocRawNN(pParse->db, sizeof(Subquery)); |
| 126815 | + if( p==0 ){ |
| 126816 | + sqlite3SelectDelete(pParse->db, pSelect); |
| 126817 | + return 0; |
| 126818 | + } |
| 126819 | + pItem->fg.isSubquery = 1; |
| 126820 | + p->pSelect = pSelect; |
| 126821 | + assert( offsetof(Subquery, pSelect)==0 ); |
| 126822 | + memset(((char*)p)+sizeof(p->pSelect), 0, sizeof(*p)-sizeof(p->pSelect)); |
| 126823 | + return 1; |
| 126824 | +} |
| 126825 | + |
| 126538 | 126826 | |
| 126539 | 126827 | /* |
| 126540 | 126828 | ** This routine is called by the parser to add a new term to the |
| 126541 | 126829 | ** end of a growing FROM clause. The "p" parameter is the part of |
| 126542 | 126830 | ** the FROM clause that has already been constructed. "p" is NULL |
| | @@ -126583,14 +126871,16 @@ |
| 126583 | 126871 | } |
| 126584 | 126872 | assert( pAlias!=0 ); |
| 126585 | 126873 | if( pAlias->n ){ |
| 126586 | 126874 | pItem->zAlias = sqlite3NameFromToken(db, pAlias); |
| 126587 | 126875 | } |
| 126876 | + assert( pSubquery==0 || pDatabase==0 ); |
| 126588 | 126877 | if( pSubquery ){ |
| 126589 | | - pItem->pSelect = pSubquery; |
| 126590 | | - if( pSubquery->selFlags & SF_NestedFrom ){ |
| 126591 | | - pItem->fg.isNestedFrom = 1; |
| 126878 | + if( sqlite3SrcItemAttachSubquery(pParse, pItem, pSubquery, 0) ){ |
| 126879 | + if( pSubquery->selFlags & SF_NestedFrom ){ |
| 126880 | + pItem->fg.isNestedFrom = 1; |
| 126881 | + } |
| 126592 | 126882 | } |
| 126593 | 126883 | } |
| 126594 | 126884 | assert( pOnUsing==0 || pOnUsing->pOn==0 || pOnUsing->pUsing==0 ); |
| 126595 | 126885 | assert( pItem->fg.isUsing==0 ); |
| 126596 | 126886 | if( pOnUsing==0 ){ |
| | @@ -127864,21 +128154,21 @@ |
| 127864 | 128154 | ** return a pointer. Set an error message and return NULL if the table |
| 127865 | 128155 | ** name is not found or if any other error occurs. |
| 127866 | 128156 | ** |
| 127867 | 128157 | ** The following fields are initialized appropriate in pSrc: |
| 127868 | 128158 | ** |
| 127869 | | -** pSrc->a[0].pTab Pointer to the Table object |
| 127870 | | -** pSrc->a[0].pIndex Pointer to the INDEXED BY index, if there is one |
| 128159 | +** pSrc->a[0].spTab Pointer to the Table object |
| 128160 | +** pSrc->a[0].u2.pIBIndex Pointer to the INDEXED BY index, if there is one |
| 127871 | 128161 | ** |
| 127872 | 128162 | */ |
| 127873 | 128163 | SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ |
| 127874 | 128164 | SrcItem *pItem = pSrc->a; |
| 127875 | 128165 | Table *pTab; |
| 127876 | 128166 | assert( pItem && pSrc->nSrc>=1 ); |
| 127877 | 128167 | pTab = sqlite3LocateTableItem(pParse, 0, pItem); |
| 127878 | | - if( pItem->pTab ) sqlite3DeleteTable(pParse->db, pItem->pTab); |
| 127879 | | - pItem->pTab = pTab; |
| 128168 | + if( pItem->pSTab ) sqlite3DeleteTable(pParse->db, pItem->pSTab); |
| 128169 | + pItem->pSTab = pTab; |
| 127880 | 128170 | pItem->fg.notCte = 1; |
| 127881 | 128171 | if( pTab ){ |
| 127882 | 128172 | pTab->nTabRef++; |
| 127883 | 128173 | if( pItem->fg.isIndexedBy && sqlite3IndexedByLookup(pParse, pItem) ){ |
| 127884 | 128174 | pTab = 0; |
| | @@ -127996,11 +128286,12 @@ |
| 127996 | 128286 | pWhere = sqlite3ExprDup(db, pWhere, 0); |
| 127997 | 128287 | pFrom = sqlite3SrcListAppend(pParse, 0, 0, 0); |
| 127998 | 128288 | if( pFrom ){ |
| 127999 | 128289 | assert( pFrom->nSrc==1 ); |
| 128000 | 128290 | pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName); |
| 128001 | | - pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); |
| 128291 | + assert( pFrom->a[0].fg.fixedSchema==0 && pFrom->a[0].fg.isSubquery==0 ); |
| 128292 | + pFrom->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); |
| 128002 | 128293 | assert( pFrom->a[0].fg.isUsing==0 ); |
| 128003 | 128294 | assert( pFrom->a[0].u3.pOn==0 ); |
| 128004 | 128295 | } |
| 128005 | 128296 | pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, pOrderBy, |
| 128006 | 128297 | SF_IncludeHidden, pLimit); |
| | @@ -128058,11 +128349,11 @@ |
| 128058 | 128349 | ** DELETE FROM table_a WHERE rowid IN ( |
| 128059 | 128350 | ** SELECT rowid FROM table_a WHERE col1=1 ORDER BY col2 LIMIT 1 OFFSET 1 |
| 128060 | 128351 | ** ); |
| 128061 | 128352 | */ |
| 128062 | 128353 | |
| 128063 | | - pTab = pSrc->a[0].pTab; |
| 128354 | + pTab = pSrc->a[0].pSTab; |
| 128064 | 128355 | if( HasRowid(pTab) ){ |
| 128065 | 128356 | pLhs = sqlite3PExpr(pParse, TK_ROW, 0, 0); |
| 128066 | 128357 | pEList = sqlite3ExprListAppend( |
| 128067 | 128358 | pParse, 0, sqlite3PExpr(pParse, TK_ROW, 0, 0) |
| 128068 | 128359 | ); |
| | @@ -128091,13 +128382,13 @@ |
| 128091 | 128382 | } |
| 128092 | 128383 | } |
| 128093 | 128384 | |
| 128094 | 128385 | /* duplicate the FROM clause as it is needed by both the DELETE/UPDATE tree |
| 128095 | 128386 | ** and the SELECT subtree. */ |
| 128096 | | - pSrc->a[0].pTab = 0; |
| 128387 | + pSrc->a[0].pSTab = 0; |
| 128097 | 128388 | pSelectSrc = sqlite3SrcListDup(db, pSrc, 0); |
| 128098 | | - pSrc->a[0].pTab = pTab; |
| 128389 | + pSrc->a[0].pSTab = pTab; |
| 128099 | 128390 | if( pSrc->a[0].fg.isIndexedBy ){ |
| 128100 | 128391 | assert( pSrc->a[0].fg.isCte==0 ); |
| 128101 | 128392 | pSrc->a[0].u2.pIBIndex = 0; |
| 128102 | 128393 | pSrc->a[0].fg.isIndexedBy = 0; |
| 128103 | 128394 | sqlite3DbFree(db, pSrc->a[0].u1.zIndexedBy); |
| | @@ -132675,13 +132966,13 @@ |
| 132675 | 132966 | /* Create a SrcList structure containing the child table. We need the |
| 132676 | 132967 | ** child table as a SrcList for sqlite3WhereBegin() */ |
| 132677 | 132968 | pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); |
| 132678 | 132969 | if( pSrc ){ |
| 132679 | 132970 | SrcItem *pItem = pSrc->a; |
| 132680 | | - pItem->pTab = pFKey->pFrom; |
| 132971 | + pItem->pSTab = pFKey->pFrom; |
| 132681 | 132972 | pItem->zName = pFKey->pFrom->zName; |
| 132682 | | - pItem->pTab->nTabRef++; |
| 132973 | + pItem->pSTab->nTabRef++; |
| 132683 | 132974 | pItem->iCursor = pParse->nTab++; |
| 132684 | 132975 | |
| 132685 | 132976 | if( regNew!=0 ){ |
| 132686 | 132977 | fkScanChildren(pParse, pSrc, pTab, pIdx, pFKey, aiCol, regNew, -1); |
| 132687 | 132978 | } |
| | @@ -132969,11 +133260,12 @@ |
| 132969 | 133260 | } |
| 132970 | 133261 | pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); |
| 132971 | 133262 | if( pSrc ){ |
| 132972 | 133263 | assert( pSrc->nSrc==1 ); |
| 132973 | 133264 | pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom); |
| 132974 | | - pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); |
| 133265 | + assert( pSrc->a[0].fg.fixedSchema==0 && pSrc->a[0].fg.isSubquery==0 ); |
| 133266 | + pSrc->a[0].u4.zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName); |
| 132975 | 133267 | } |
| 132976 | 133268 | pSelect = sqlite3SelectNew(pParse, |
| 132977 | 133269 | sqlite3ExprListAppend(pParse, 0, pRaise), |
| 132978 | 133270 | pSrc, |
| 132979 | 133271 | pWhere, |
| | @@ -133703,12 +133995,15 @@ |
| 133703 | 133995 | ** co-routine. |
| 133704 | 133996 | */ |
| 133705 | 133997 | SQLITE_PRIVATE void sqlite3MultiValuesEnd(Parse *pParse, Select *pVal){ |
| 133706 | 133998 | if( ALWAYS(pVal) && pVal->pSrc->nSrc>0 ){ |
| 133707 | 133999 | SrcItem *pItem = &pVal->pSrc->a[0]; |
| 133708 | | - sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->regReturn); |
| 133709 | | - sqlite3VdbeJumpHere(pParse->pVdbe, pItem->addrFillSub - 1); |
| 134000 | + assert( (pItem->fg.isSubquery && pItem->u4.pSubq!=0) || pParse->nErr ); |
| 134001 | + if( pItem->fg.isSubquery ){ |
| 134002 | + sqlite3VdbeEndCoroutine(pParse->pVdbe, pItem->u4.pSubq->regReturn); |
| 134003 | + sqlite3VdbeJumpHere(pParse->pVdbe, pItem->u4.pSubq->addrFillSub - 1); |
| 134004 | + } |
| 133710 | 134005 | } |
| 133711 | 134006 | } |
| 133712 | 134007 | |
| 133713 | 134008 | /* |
| 133714 | 134009 | ** Return true if all expressions in the expression-list passed as the |
| | @@ -133832,56 +134127,67 @@ |
| 133832 | 134127 | sqlite3ReadSchema(pParse); |
| 133833 | 134128 | } |
| 133834 | 134129 | |
| 133835 | 134130 | if( pRet ){ |
| 133836 | 134131 | SelectDest dest; |
| 134132 | + Subquery *pSubq; |
| 133837 | 134133 | pRet->pSrc->nSrc = 1; |
| 133838 | 134134 | pRet->pPrior = pLeft->pPrior; |
| 133839 | 134135 | pRet->op = pLeft->op; |
| 133840 | 134136 | if( pRet->pPrior ) pRet->selFlags |= SF_Values; |
| 133841 | 134137 | pLeft->pPrior = 0; |
| 133842 | 134138 | pLeft->op = TK_SELECT; |
| 133843 | 134139 | assert( pLeft->pNext==0 ); |
| 133844 | 134140 | assert( pRet->pNext==0 ); |
| 133845 | 134141 | p = &pRet->pSrc->a[0]; |
| 133846 | | - p->pSelect = pLeft; |
| 133847 | 134142 | p->fg.viaCoroutine = 1; |
| 133848 | | - p->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; |
| 133849 | | - p->regReturn = ++pParse->nMem; |
| 133850 | 134143 | p->iCursor = -1; |
| 134144 | + assert( !p->fg.isIndexedBy && !p->fg.isTabFunc ); |
| 133851 | 134145 | p->u1.nRow = 2; |
| 133852 | | - sqlite3VdbeAddOp3(v,OP_InitCoroutine,p->regReturn,0,p->addrFillSub); |
| 133853 | | - sqlite3SelectDestInit(&dest, SRT_Coroutine, p->regReturn); |
| 133854 | | - |
| 133855 | | - /* Allocate registers for the output of the co-routine. Do so so |
| 133856 | | - ** that there are two unused registers immediately before those |
| 133857 | | - ** used by the co-routine. This allows the code in sqlite3Insert() |
| 133858 | | - ** to use these registers directly, instead of copying the output |
| 133859 | | - ** of the co-routine to a separate array for processing. */ |
| 133860 | | - dest.iSdst = pParse->nMem + 3; |
| 133861 | | - dest.nSdst = pLeft->pEList->nExpr; |
| 133862 | | - pParse->nMem += 2 + dest.nSdst; |
| 133863 | | - |
| 133864 | | - pLeft->selFlags |= SF_MultiValue; |
| 133865 | | - sqlite3Select(pParse, pLeft, &dest); |
| 133866 | | - p->regResult = dest.iSdst; |
| 133867 | | - assert( pParse->nErr || dest.iSdst>0 ); |
| 134146 | + if( sqlite3SrcItemAttachSubquery(pParse, p, pLeft, 0) ){ |
| 134147 | + pSubq = p->u4.pSubq; |
| 134148 | + pSubq->addrFillSub = sqlite3VdbeCurrentAddr(v) + 1; |
| 134149 | + pSubq->regReturn = ++pParse->nMem; |
| 134150 | + sqlite3VdbeAddOp3(v, OP_InitCoroutine, |
| 134151 | + pSubq->regReturn, 0, pSubq->addrFillSub); |
| 134152 | + sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); |
| 134153 | + |
| 134154 | + /* Allocate registers for the output of the co-routine. Do so so |
| 134155 | + ** that there are two unused registers immediately before those |
| 134156 | + ** used by the co-routine. This allows the code in sqlite3Insert() |
| 134157 | + ** to use these registers directly, instead of copying the output |
| 134158 | + ** of the co-routine to a separate array for processing. */ |
| 134159 | + dest.iSdst = pParse->nMem + 3; |
| 134160 | + dest.nSdst = pLeft->pEList->nExpr; |
| 134161 | + pParse->nMem += 2 + dest.nSdst; |
| 134162 | + |
| 134163 | + pLeft->selFlags |= SF_MultiValue; |
| 134164 | + sqlite3Select(pParse, pLeft, &dest); |
| 134165 | + pSubq->regResult = dest.iSdst; |
| 134166 | + assert( pParse->nErr || dest.iSdst>0 ); |
| 134167 | + } |
| 133868 | 134168 | pLeft = pRet; |
| 133869 | 134169 | } |
| 133870 | 134170 | }else{ |
| 133871 | 134171 | p = &pLeft->pSrc->a[0]; |
| 133872 | 134172 | assert( !p->fg.isTabFunc && !p->fg.isIndexedBy ); |
| 133873 | 134173 | p->u1.nRow++; |
| 133874 | 134174 | } |
| 133875 | 134175 | |
| 133876 | 134176 | if( pParse->nErr==0 ){ |
| 134177 | + Subquery *pSubq; |
| 133877 | 134178 | assert( p!=0 ); |
| 133878 | | - if( p->pSelect->pEList->nExpr!=pRow->nExpr ){ |
| 133879 | | - sqlite3SelectWrongNumTermsError(pParse, p->pSelect); |
| 134179 | + assert( p->fg.isSubquery ); |
| 134180 | + pSubq = p->u4.pSubq; |
| 134181 | + assert( pSubq!=0 ); |
| 134182 | + assert( pSubq->pSelect!=0 ); |
| 134183 | + assert( pSubq->pSelect->pEList!=0 ); |
| 134184 | + if( pSubq->pSelect->pEList->nExpr!=pRow->nExpr ){ |
| 134185 | + sqlite3SelectWrongNumTermsError(pParse, pSubq->pSelect); |
| 133880 | 134186 | }else{ |
| 133881 | | - sqlite3ExprCodeExprList(pParse, pRow, p->regResult, 0, 0); |
| 133882 | | - sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, p->regReturn); |
| 134187 | + sqlite3ExprCodeExprList(pParse, pRow, pSubq->regResult, 0, 0); |
| 134188 | + sqlite3VdbeAddOp1(pParse->pVdbe, OP_Yield, pSubq->regReturn); |
| 133883 | 134189 | } |
| 133884 | 134190 | } |
| 133885 | 134191 | sqlite3ExprListDelete(pParse->db, pRow); |
| 133886 | 134192 | } |
| 133887 | 134193 | |
| | @@ -134228,13 +134534,18 @@ |
| 134228 | 134534 | if( pSelect->pSrc->nSrc==1 |
| 134229 | 134535 | && pSelect->pSrc->a[0].fg.viaCoroutine |
| 134230 | 134536 | && pSelect->pPrior==0 |
| 134231 | 134537 | ){ |
| 134232 | 134538 | SrcItem *pItem = &pSelect->pSrc->a[0]; |
| 134233 | | - dest.iSDParm = pItem->regReturn; |
| 134234 | | - regFromSelect = pItem->regResult; |
| 134235 | | - nColumn = pItem->pSelect->pEList->nExpr; |
| 134539 | + Subquery *pSubq; |
| 134540 | + assert( pItem->fg.isSubquery ); |
| 134541 | + pSubq = pItem->u4.pSubq; |
| 134542 | + dest.iSDParm = pSubq->regReturn; |
| 134543 | + regFromSelect = pSubq->regResult; |
| 134544 | + assert( pSubq->pSelect!=0 ); |
| 134545 | + assert( pSubq->pSelect->pEList!=0 ); |
| 134546 | + nColumn = pSubq->pSelect->pEList->nExpr; |
| 134236 | 134547 | ExplainQueryPlan((pParse, 0, "SCAN %S", pItem)); |
| 134237 | 134548 | if( bIdListInOrder && nColumn==pTab->nCol ){ |
| 134238 | 134549 | regData = regFromSelect; |
| 134239 | 134550 | regRowid = regData - 1; |
| 134240 | 134551 | regIns = regRowid - (IsVirtual(pTab) ? 1 : 0); |
| | @@ -136150,11 +136461,11 @@ |
| 136150 | 136461 | } |
| 136151 | 136462 | assert(pSelect->pSrc); /* allocated even if there is no FROM clause */ |
| 136152 | 136463 | if( pSelect->pSrc->nSrc!=1 ){ |
| 136153 | 136464 | return 0; /* FROM clause must have exactly one term */ |
| 136154 | 136465 | } |
| 136155 | | - if( pSelect->pSrc->a[0].pSelect ){ |
| 136466 | + if( pSelect->pSrc->a[0].fg.isSubquery ){ |
| 136156 | 136467 | return 0; /* FROM clause cannot contain a subquery */ |
| 136157 | 136468 | } |
| 136158 | 136469 | if( pSelect->pWhere ){ |
| 136159 | 136470 | return 0; /* SELECT may not have a WHERE clause */ |
| 136160 | 136471 | } |
| | @@ -143448,15 +143759,17 @@ |
| 143448 | 143759 | /* |
| 143449 | 143760 | ** Mark a subquery result column as having been used. |
| 143450 | 143761 | */ |
| 143451 | 143762 | SQLITE_PRIVATE void sqlite3SrcItemColumnUsed(SrcItem *pItem, int iCol){ |
| 143452 | 143763 | assert( pItem!=0 ); |
| 143453 | | - assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem->pSelect) ); |
| 143764 | + assert( (int)pItem->fg.isNestedFrom == IsNestedFrom(pItem) ); |
| 143454 | 143765 | if( pItem->fg.isNestedFrom ){ |
| 143455 | 143766 | ExprList *pResults; |
| 143456 | | - assert( pItem->pSelect!=0 ); |
| 143457 | | - pResults = pItem->pSelect->pEList; |
| 143767 | + assert( pItem->fg.isSubquery ); |
| 143768 | + assert( pItem->u4.pSubq!=0 ); |
| 143769 | + assert( pItem->u4.pSubq->pSelect!=0 ); |
| 143770 | + pResults = pItem->u4.pSubq->pSelect->pEList; |
| 143458 | 143771 | assert( pResults!=0 ); |
| 143459 | 143772 | assert( iCol>=0 && iCol<pResults->nExpr ); |
| 143460 | 143773 | pResults->a[iCol].fg.bUsed = 1; |
| 143461 | 143774 | } |
| 143462 | 143775 | } |
| | @@ -143486,13 +143799,13 @@ |
| 143486 | 143799 | assert( iEnd<pSrc->nSrc ); |
| 143487 | 143800 | assert( iStart>=0 ); |
| 143488 | 143801 | assert( (piTab==0)==(piCol==0) ); /* Both or neither are NULL */ |
| 143489 | 143802 | |
| 143490 | 143803 | for(i=iStart; i<=iEnd; i++){ |
| 143491 | | - iCol = sqlite3ColumnIndex(pSrc->a[i].pTab, zCol); |
| 143804 | + iCol = sqlite3ColumnIndex(pSrc->a[i].pSTab, zCol); |
| 143492 | 143805 | if( iCol>=0 |
| 143493 | | - && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pTab->aCol[iCol])==0) |
| 143806 | + && (bIgnoreHidden==0 || IsHiddenColumn(&pSrc->a[i].pSTab->aCol[iCol])==0) |
| 143494 | 143807 | ){ |
| 143495 | 143808 | if( piTab ){ |
| 143496 | 143809 | sqlite3SrcItemColumnUsed(&pSrc->a[i], iCol); |
| 143497 | 143810 | *piTab = i; |
| 143498 | 143811 | *piCol = iCol; |
| | @@ -143617,14 +143930,14 @@ |
| 143617 | 143930 | |
| 143618 | 143931 | pSrc = p->pSrc; |
| 143619 | 143932 | pLeft = &pSrc->a[0]; |
| 143620 | 143933 | pRight = &pLeft[1]; |
| 143621 | 143934 | for(i=0; i<pSrc->nSrc-1; i++, pRight++, pLeft++){ |
| 143622 | | - Table *pRightTab = pRight->pTab; |
| 143935 | + Table *pRightTab = pRight->pSTab; |
| 143623 | 143936 | u32 joinType; |
| 143624 | 143937 | |
| 143625 | | - if( NEVER(pLeft->pTab==0 || pRightTab==0) ) continue; |
| 143938 | + if( NEVER(pLeft->pSTab==0 || pRightTab==0) ) continue; |
| 143626 | 143939 | joinType = (pRight->fg.jointype & JT_OUTER)!=0 ? EP_OuterON : EP_InnerON; |
| 143627 | 143940 | |
| 143628 | 143941 | /* If this is a NATURAL join, synthesize an appropriate USING clause |
| 143629 | 143942 | ** to specify which columns should be joined. |
| 143630 | 143943 | */ |
| | @@ -145046,12 +145359,16 @@ |
| 145046 | 145359 | int iCol = pExpr->iColumn; /* Index of column in pTab */ |
| 145047 | 145360 | while( pNC && !pTab ){ |
| 145048 | 145361 | SrcList *pTabList = pNC->pSrcList; |
| 145049 | 145362 | for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); |
| 145050 | 145363 | if( j<pTabList->nSrc ){ |
| 145051 | | - pTab = pTabList->a[j].pTab; |
| 145052 | | - pS = pTabList->a[j].pSelect; |
| 145364 | + pTab = pTabList->a[j].pSTab; |
| 145365 | + if( pTabList->a[j].fg.isSubquery ){ |
| 145366 | + pS = pTabList->a[j].u4.pSubq->pSelect; |
| 145367 | + }else{ |
| 145368 | + pS = 0; |
| 145369 | + } |
| 145053 | 145370 | }else{ |
| 145054 | 145371 | pNC = pNC->pNext; |
| 145055 | 145372 | } |
| 145056 | 145373 | } |
| 145057 | 145374 | |
| | @@ -147099,11 +147416,13 @@ |
| 147099 | 147416 | p->pHaving = substExpr(pSubst, p->pHaving); |
| 147100 | 147417 | p->pWhere = substExpr(pSubst, p->pWhere); |
| 147101 | 147418 | pSrc = p->pSrc; |
| 147102 | 147419 | assert( pSrc!=0 ); |
| 147103 | 147420 | for(i=pSrc->nSrc, pItem=pSrc->a; i>0; i--, pItem++){ |
| 147104 | | - substSelect(pSubst, pItem->pSelect, 1); |
| 147421 | + if( pItem->fg.isSubquery ){ |
| 147422 | + substSelect(pSubst, pItem->u4.pSubq->pSelect, 1); |
| 147423 | + } |
| 147105 | 147424 | if( pItem->fg.isTabFunc ){ |
| 147106 | 147425 | substExprList(pSubst, pItem->u1.pFuncArg); |
| 147107 | 147426 | } |
| 147108 | 147427 | } |
| 147109 | 147428 | }while( doPrior && (p = p->pPrior)!=0 ); |
| | @@ -147130,11 +147449,11 @@ |
| 147130 | 147449 | static void recomputeColumnsUsed( |
| 147131 | 147450 | Select *pSelect, /* The complete SELECT statement */ |
| 147132 | 147451 | SrcItem *pSrcItem /* Which FROM clause item to recompute */ |
| 147133 | 147452 | ){ |
| 147134 | 147453 | Walker w; |
| 147135 | | - if( NEVER(pSrcItem->pTab==0) ) return; |
| 147454 | + if( NEVER(pSrcItem->pSTab==0) ) return; |
| 147136 | 147455 | memset(&w, 0, sizeof(w)); |
| 147137 | 147456 | w.xExprCallback = recomputeColumnsUsedExpr; |
| 147138 | 147457 | w.xSelectCallback = sqlite3SelectWalkNoop; |
| 147139 | 147458 | w.u.pSrcItem = pSrcItem; |
| 147140 | 147459 | pSrcItem->colUsed = 0; |
| | @@ -147170,12 +147489,14 @@ |
| 147170 | 147489 | assert( pItem->iCursor < aCsrMap[0] ); |
| 147171 | 147490 | if( !pItem->fg.isRecursive || aCsrMap[pItem->iCursor+1]==0 ){ |
| 147172 | 147491 | aCsrMap[pItem->iCursor+1] = pParse->nTab++; |
| 147173 | 147492 | } |
| 147174 | 147493 | pItem->iCursor = aCsrMap[pItem->iCursor+1]; |
| 147175 | | - for(p=pItem->pSelect; p; p=p->pPrior){ |
| 147176 | | - srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); |
| 147494 | + if( pItem->fg.isSubquery ){ |
| 147495 | + for(p=pItem->u4.pSubq->pSelect; p; p=p->pPrior){ |
| 147496 | + srclistRenumberCursors(pParse, aCsrMap, p->pSrc, -1); |
| 147497 | + } |
| 147177 | 147498 | } |
| 147178 | 147499 | } |
| 147179 | 147500 | } |
| 147180 | 147501 | } |
| 147181 | 147502 | |
| | @@ -147482,11 +147803,12 @@ |
| 147482 | 147803 | if( OptimizationDisabled(db, SQLITE_QueryFlattener) ) return 0; |
| 147483 | 147804 | pSrc = p->pSrc; |
| 147484 | 147805 | assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc ); |
| 147485 | 147806 | pSubitem = &pSrc->a[iFrom]; |
| 147486 | 147807 | iParent = pSubitem->iCursor; |
| 147487 | | - pSub = pSubitem->pSelect; |
| 147808 | + assert( pSubitem->fg.isSubquery ); |
| 147809 | + pSub = pSubitem->u4.pSubq->pSelect; |
| 147488 | 147810 | assert( pSub!=0 ); |
| 147489 | 147811 | |
| 147490 | 147812 | #ifndef SQLITE_OMIT_WINDOWFUNC |
| 147491 | 147813 | if( p->pWin || pSub->pWin ) return 0; /* Restriction (25) */ |
| 147492 | 147814 | #endif |
| | @@ -147535,11 +147857,11 @@ |
| 147535 | 147857 | ** |
| 147536 | 147858 | ** See also tickets #306, #350, and #3300. |
| 147537 | 147859 | */ |
| 147538 | 147860 | if( (pSubitem->fg.jointype & (JT_OUTER|JT_LTORJ))!=0 ){ |
| 147539 | 147861 | if( pSubSrc->nSrc>1 /* (3a) */ |
| 147540 | | - || IsVirtual(pSubSrc->a[0].pTab) /* (3b) */ |
| 147862 | + || IsVirtual(pSubSrc->a[0].pSTab) /* (3b) */ |
| 147541 | 147863 | || (p->selFlags & SF_Distinct)!=0 /* (3d) */ |
| 147542 | 147864 | || (pSubitem->fg.jointype & JT_RIGHT)!=0 /* (26) */ |
| 147543 | 147865 | ){ |
| 147544 | 147866 | return 0; |
| 147545 | 147867 | } |
| | @@ -147621,18 +147943,22 @@ |
| 147621 | 147943 | TESTONLY(i =) sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0); |
| 147622 | 147944 | testcase( i==SQLITE_DENY ); |
| 147623 | 147945 | pParse->zAuthContext = zSavedAuthContext; |
| 147624 | 147946 | |
| 147625 | 147947 | /* Delete the transient structures associated with the subquery */ |
| 147626 | | - pSub1 = pSubitem->pSelect; |
| 147627 | | - sqlite3DbFree(db, pSubitem->zDatabase); |
| 147948 | + |
| 147949 | + if( ALWAYS(pSubitem->fg.isSubquery) ){ |
| 147950 | + pSub1 = sqlite3SubqueryDetach(db, pSubitem); |
| 147951 | + }else{ |
| 147952 | + pSub1 = 0; |
| 147953 | + } |
| 147954 | + assert( pSubitem->fg.isSubquery==0 ); |
| 147955 | + assert( pSubitem->fg.fixedSchema==0 ); |
| 147628 | 147956 | sqlite3DbFree(db, pSubitem->zName); |
| 147629 | 147957 | sqlite3DbFree(db, pSubitem->zAlias); |
| 147630 | | - pSubitem->zDatabase = 0; |
| 147631 | 147958 | pSubitem->zName = 0; |
| 147632 | 147959 | pSubitem->zAlias = 0; |
| 147633 | | - pSubitem->pSelect = 0; |
| 147634 | 147960 | assert( pSubitem->fg.isUsing!=0 || pSubitem->u3.pOn==0 ); |
| 147635 | 147961 | |
| 147636 | 147962 | /* If the sub-query is a compound SELECT statement, then (by restrictions |
| 147637 | 147963 | ** 17 and 18 above) it must be a UNION ALL and the parent query must |
| 147638 | 147964 | ** be of the form: |
| | @@ -147669,20 +147995,20 @@ |
| 147669 | 147995 | for(pSub=pSub->pPrior; pSub; pSub=pSub->pPrior){ |
| 147670 | 147996 | Select *pNew; |
| 147671 | 147997 | ExprList *pOrderBy = p->pOrderBy; |
| 147672 | 147998 | Expr *pLimit = p->pLimit; |
| 147673 | 147999 | Select *pPrior = p->pPrior; |
| 147674 | | - Table *pItemTab = pSubitem->pTab; |
| 147675 | | - pSubitem->pTab = 0; |
| 148000 | + Table *pItemTab = pSubitem->pSTab; |
| 148001 | + pSubitem->pSTab = 0; |
| 147676 | 148002 | p->pOrderBy = 0; |
| 147677 | 148003 | p->pPrior = 0; |
| 147678 | 148004 | p->pLimit = 0; |
| 147679 | 148005 | pNew = sqlite3SelectDup(db, p, 0); |
| 147680 | 148006 | p->pLimit = pLimit; |
| 147681 | 148007 | p->pOrderBy = pOrderBy; |
| 147682 | 148008 | p->op = TK_ALL; |
| 147683 | | - pSubitem->pTab = pItemTab; |
| 148009 | + pSubitem->pSTab = pItemTab; |
| 147684 | 148010 | if( pNew==0 ){ |
| 147685 | 148011 | p->pPrior = pPrior; |
| 147686 | 148012 | }else{ |
| 147687 | 148013 | pNew->selId = ++pParse->nSelect; |
| 147688 | 148014 | if( aCsrMap && ALWAYS(db->mallocFailed==0) ){ |
| | @@ -147693,15 +148019,18 @@ |
| 147693 | 148019 | pNew->pNext = p; |
| 147694 | 148020 | p->pPrior = pNew; |
| 147695 | 148021 | TREETRACE(0x4,pParse,p,("compound-subquery flattener" |
| 147696 | 148022 | " creates %u as peer\n",pNew->selId)); |
| 147697 | 148023 | } |
| 147698 | | - assert( pSubitem->pSelect==0 ); |
| 148024 | + assert( pSubitem->fg.isSubquery==0 ); |
| 147699 | 148025 | } |
| 147700 | 148026 | sqlite3DbFree(db, aCsrMap); |
| 147701 | 148027 | if( db->mallocFailed ){ |
| 147702 | | - pSubitem->pSelect = pSub1; |
| 148028 | + assert( pSubitem->fg.fixedSchema==0 ); |
| 148029 | + assert( pSubitem->fg.isSubquery==0 ); |
| 148030 | + assert( pSubitem->u4.zDatabase==0 ); |
| 148031 | + sqlite3SrcItemAttachSubquery(pParse, pSubitem, pSub1, 0); |
| 147703 | 148032 | return 1; |
| 147704 | 148033 | } |
| 147705 | 148034 | |
| 147706 | 148035 | /* Defer deleting the Table object associated with the |
| 147707 | 148036 | ** subquery until code generation is |
| | @@ -147708,20 +148037,20 @@ |
| 147708 | 148037 | ** complete, since there may still exist Expr.pTab entries that |
| 147709 | 148038 | ** refer to the subquery even after flattening. Ticket #3346. |
| 147710 | 148039 | ** |
| 147711 | 148040 | ** pSubitem->pTab is always non-NULL by test restrictions and tests above. |
| 147712 | 148041 | */ |
| 147713 | | - if( ALWAYS(pSubitem->pTab!=0) ){ |
| 147714 | | - Table *pTabToDel = pSubitem->pTab; |
| 148042 | + if( ALWAYS(pSubitem->pSTab!=0) ){ |
| 148043 | + Table *pTabToDel = pSubitem->pSTab; |
| 147715 | 148044 | if( pTabToDel->nTabRef==1 ){ |
| 147716 | 148045 | Parse *pToplevel = sqlite3ParseToplevel(pParse); |
| 147717 | 148046 | sqlite3ParserAddCleanup(pToplevel, sqlite3DeleteTableGeneric, pTabToDel); |
| 147718 | 148047 | testcase( pToplevel->earlyCleanup ); |
| 147719 | 148048 | }else{ |
| 147720 | 148049 | pTabToDel->nTabRef--; |
| 147721 | 148050 | } |
| 147722 | | - pSubitem->pTab = 0; |
| 148051 | + pSubitem->pSTab = 0; |
| 147723 | 148052 | } |
| 147724 | 148053 | |
| 147725 | 148054 | /* The following loop runs once for each term in a compound-subquery |
| 147726 | 148055 | ** flattening (as described above). If we are doing a different kind |
| 147727 | 148056 | ** of flattening - a flattening other than a compound-subquery flattening - |
| | @@ -147773,12 +148102,15 @@ |
| 147773 | 148102 | /* Transfer the FROM clause terms from the subquery into the |
| 147774 | 148103 | ** outer query. |
| 147775 | 148104 | */ |
| 147776 | 148105 | for(i=0; i<nSubSrc; i++){ |
| 147777 | 148106 | SrcItem *pItem = &pSrc->a[i+iFrom]; |
| 147778 | | - if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); |
| 147779 | 148107 | assert( pItem->fg.isTabFunc==0 ); |
| 148108 | + assert( pItem->fg.isSubquery |
| 148109 | + || pItem->fg.fixedSchema |
| 148110 | + || pItem->u4.zDatabase==0 ); |
| 148111 | + if( pItem->fg.isUsing ) sqlite3IdListDelete(db, pItem->u3.pUsing); |
| 147780 | 148112 | *pItem = pSubSrc->a[i]; |
| 147781 | 148113 | pItem->fg.jointype |= ltorj; |
| 147782 | 148114 | iNewParent = pSubSrc->a[i].iCursor; |
| 147783 | 148115 | memset(&pSubSrc->a[i], 0, sizeof(pSubSrc->a[i])); |
| 147784 | 148116 | } |
| | @@ -148458,14 +148790,14 @@ |
| 148458 | 148790 | |
| 148459 | 148791 | assert( pItem!=0 ); |
| 148460 | 148792 | if( pItem->fg.isCorrelated || pItem->fg.isCte ){ |
| 148461 | 148793 | return 0; |
| 148462 | 148794 | } |
| 148463 | | - assert( pItem->pTab!=0 ); |
| 148464 | | - pTab = pItem->pTab; |
| 148465 | | - assert( pItem->pSelect!=0 ); |
| 148466 | | - pSub = pItem->pSelect; |
| 148795 | + assert( pItem->pSTab!=0 ); |
| 148796 | + pTab = pItem->pSTab; |
| 148797 | + assert( pItem->fg.isSubquery ); |
| 148798 | + pSub = pItem->u4.pSubq->pSelect; |
| 148467 | 148799 | assert( pSub->pEList->nExpr==pTab->nCol ); |
| 148468 | 148800 | for(pX=pSub; pX; pX=pX->pPrior){ |
| 148469 | 148801 | if( (pX->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){ |
| 148470 | 148802 | testcase( pX->selFlags & SF_Distinct ); |
| 148471 | 148803 | testcase( pX->selFlags & SF_Aggregate ); |
| | @@ -148590,17 +148922,17 @@ |
| 148590 | 148922 | assert( !p->pGroupBy ); |
| 148591 | 148923 | |
| 148592 | 148924 | if( p->pWhere |
| 148593 | 148925 | || p->pEList->nExpr!=1 |
| 148594 | 148926 | || p->pSrc->nSrc!=1 |
| 148595 | | - || p->pSrc->a[0].pSelect |
| 148927 | + || p->pSrc->a[0].fg.isSubquery |
| 148596 | 148928 | || pAggInfo->nFunc!=1 |
| 148597 | 148929 | || p->pHaving |
| 148598 | 148930 | ){ |
| 148599 | 148931 | return 0; |
| 148600 | 148932 | } |
| 148601 | | - pTab = p->pSrc->a[0].pTab; |
| 148933 | + pTab = p->pSrc->a[0].pSTab; |
| 148602 | 148934 | assert( pTab!=0 ); |
| 148603 | 148935 | assert( !IsView(pTab) ); |
| 148604 | 148936 | if( !IsOrdinaryTable(pTab) ) return 0; |
| 148605 | 148937 | pExpr = p->pEList->a[0].pExpr; |
| 148606 | 148938 | assert( pExpr!=0 ); |
| | @@ -148621,11 +148953,11 @@ |
| 148621 | 148953 | ** was such a clause and the named index cannot be found, return |
| 148622 | 148954 | ** SQLITE_ERROR and leave an error in pParse. Otherwise, populate |
| 148623 | 148955 | ** pFrom->pIndex and return SQLITE_OK. |
| 148624 | 148956 | */ |
| 148625 | 148957 | SQLITE_PRIVATE int sqlite3IndexedByLookup(Parse *pParse, SrcItem *pFrom){ |
| 148626 | | - Table *pTab = pFrom->pTab; |
| 148958 | + Table *pTab = pFrom->pSTab; |
| 148627 | 148959 | char *zIndexedBy = pFrom->u1.zIndexedBy; |
| 148628 | 148960 | Index *pIdx; |
| 148629 | 148961 | assert( pTab!=0 ); |
| 148630 | 148962 | assert( pFrom->fg.isIndexedBy!=0 ); |
| 148631 | 148963 | |
| | @@ -148698,11 +149030,15 @@ |
| 148698 | 149030 | db = pParse->db; |
| 148699 | 149031 | pNew = sqlite3DbMallocZero(db, sizeof(*pNew) ); |
| 148700 | 149032 | if( pNew==0 ) return WRC_Abort; |
| 148701 | 149033 | memset(&dummy, 0, sizeof(dummy)); |
| 148702 | 149034 | pNewSrc = sqlite3SrcListAppendFromTerm(pParse,0,0,0,&dummy,pNew,0); |
| 148703 | | - if( pNewSrc==0 ) return WRC_Abort; |
| 149035 | + assert( pNewSrc!=0 || pParse->nErr ); |
| 149036 | + if( pParse->nErr ){ |
| 149037 | + sqlite3SrcListDelete(db, pNewSrc); |
| 149038 | + return WRC_Abort; |
| 149039 | + } |
| 148704 | 149040 | *pNew = *p; |
| 148705 | 149041 | p->pSrc = pNewSrc; |
| 148706 | 149042 | p->pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db, TK_ASTERISK, 0)); |
| 148707 | 149043 | p->op = TK_SELECT; |
| 148708 | 149044 | p->pWhere = 0; |
| | @@ -148753,11 +149089,11 @@ |
| 148753 | 149089 | SrcItem *pItem, /* FROM clause element to resolve */ |
| 148754 | 149090 | With **ppContext /* OUT: WITH clause return value belongs to */ |
| 148755 | 149091 | ){ |
| 148756 | 149092 | const char *zName = pItem->zName; |
| 148757 | 149093 | With *p; |
| 148758 | | - assert( pItem->zDatabase==0 ); |
| 149094 | + assert( pItem->fg.fixedSchema || pItem->u4.zDatabase==0 ); |
| 148759 | 149095 | assert( zName!=0 ); |
| 148760 | 149096 | for(p=pWith; p; p=p->pOuter){ |
| 148761 | 149097 | int i; |
| 148762 | 149098 | for(i=0; i<p->nCte; i++){ |
| 148763 | 149099 | if( sqlite3StrICmp(zName, p->a[i].zName)==0 ){ |
| | @@ -148823,21 +149159,22 @@ |
| 148823 | 149159 | SrcItem *pFrom /* The FROM clause term to check */ |
| 148824 | 149160 | ){ |
| 148825 | 149161 | Cte *pCte; /* Matched CTE (or NULL if no match) */ |
| 148826 | 149162 | With *pWith; /* The matching WITH */ |
| 148827 | 149163 | |
| 148828 | | - assert( pFrom->pTab==0 ); |
| 149164 | + assert( pFrom->pSTab==0 ); |
| 148829 | 149165 | if( pParse->pWith==0 ){ |
| 148830 | 149166 | /* There are no WITH clauses in the stack. No match is possible */ |
| 148831 | 149167 | return 0; |
| 148832 | 149168 | } |
| 148833 | 149169 | if( pParse->nErr ){ |
| 148834 | 149170 | /* Prior errors might have left pParse->pWith in a goofy state, so |
| 148835 | 149171 | ** go no further. */ |
| 148836 | 149172 | return 0; |
| 148837 | 149173 | } |
| 148838 | | - if( pFrom->zDatabase!=0 ){ |
| 149174 | + assert( pFrom->fg.hadSchema==0 || pFrom->fg.notCte!=0 ); |
| 149175 | + if( pFrom->fg.fixedSchema==0 && pFrom->u4.zDatabase!=0 ){ |
| 148839 | 149176 | /* The FROM term contains a schema qualifier (ex: main.t1) and so |
| 148840 | 149177 | ** it cannot possibly be a CTE reference. */ |
| 148841 | 149178 | return 0; |
| 148842 | 149179 | } |
| 148843 | 149180 | if( pFrom->fg.notCte ){ |
| | @@ -148869,11 +149206,11 @@ |
| 148869 | 149206 | sqlite3ErrorMsg(pParse, pCte->zCteErr, pCte->zName); |
| 148870 | 149207 | return 2; |
| 148871 | 149208 | } |
| 148872 | 149209 | if( cannotBeFunction(pParse, pFrom) ) return 2; |
| 148873 | 149210 | |
| 148874 | | - assert( pFrom->pTab==0 ); |
| 149211 | + assert( pFrom->pSTab==0 ); |
| 148875 | 149212 | pTab = sqlite3DbMallocZero(db, sizeof(Table)); |
| 148876 | 149213 | if( pTab==0 ) return 2; |
| 148877 | 149214 | pCteUse = pCte->pUse; |
| 148878 | 149215 | if( pCteUse==0 ){ |
| 148879 | 149216 | pCte->pUse = pCteUse = sqlite3DbMallocZero(db, sizeof(pCteUse[0])); |
| | @@ -148883,42 +149220,47 @@ |
| 148883 | 149220 | sqlite3DbFree(db, pTab); |
| 148884 | 149221 | return 2; |
| 148885 | 149222 | } |
| 148886 | 149223 | pCteUse->eM10d = pCte->eM10d; |
| 148887 | 149224 | } |
| 148888 | | - pFrom->pTab = pTab; |
| 149225 | + pFrom->pSTab = pTab; |
| 148889 | 149226 | pTab->nTabRef = 1; |
| 148890 | 149227 | pTab->zName = sqlite3DbStrDup(db, pCte->zName); |
| 148891 | 149228 | pTab->iPKey = -1; |
| 148892 | 149229 | pTab->nRowLogEst = 200; assert( 200==sqlite3LogEst(1048576) ); |
| 148893 | 149230 | pTab->tabFlags |= TF_Ephemeral | TF_NoVisibleRowid; |
| 148894 | | - pFrom->pSelect = sqlite3SelectDup(db, pCte->pSelect, 0); |
| 149231 | + sqlite3SrcItemAttachSubquery(pParse, pFrom, pCte->pSelect, 1); |
| 148895 | 149232 | if( db->mallocFailed ) return 2; |
| 148896 | | - pFrom->pSelect->selFlags |= SF_CopyCte; |
| 148897 | | - assert( pFrom->pSelect ); |
| 149233 | + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); |
| 149234 | + pSel = pFrom->u4.pSubq->pSelect; |
| 149235 | + assert( pSel!=0 ); |
| 149236 | + pSel->selFlags |= SF_CopyCte; |
| 148898 | 149237 | if( pFrom->fg.isIndexedBy ){ |
| 148899 | 149238 | sqlite3ErrorMsg(pParse, "no such index: \"%s\"", pFrom->u1.zIndexedBy); |
| 148900 | 149239 | return 2; |
| 148901 | 149240 | } |
| 149241 | + assert( !pFrom->fg.isIndexedBy ); |
| 148902 | 149242 | pFrom->fg.isCte = 1; |
| 148903 | 149243 | pFrom->u2.pCteUse = pCteUse; |
| 148904 | 149244 | pCteUse->nUse++; |
| 148905 | 149245 | |
| 148906 | 149246 | /* Check if this is a recursive CTE. */ |
| 148907 | | - pRecTerm = pSel = pFrom->pSelect; |
| 149247 | + pRecTerm = pSel; |
| 148908 | 149248 | bMayRecursive = ( pSel->op==TK_ALL || pSel->op==TK_UNION ); |
| 148909 | 149249 | while( bMayRecursive && pRecTerm->op==pSel->op ){ |
| 148910 | 149250 | int i; |
| 148911 | 149251 | SrcList *pSrc = pRecTerm->pSrc; |
| 148912 | 149252 | assert( pRecTerm->pPrior!=0 ); |
| 148913 | 149253 | for(i=0; i<pSrc->nSrc; i++){ |
| 148914 | 149254 | SrcItem *pItem = &pSrc->a[i]; |
| 148915 | | - if( pItem->zDatabase==0 |
| 148916 | | - && pItem->zName!=0 |
| 149255 | + if( pItem->zName!=0 |
| 149256 | + && !pItem->fg.hadSchema |
| 149257 | + && ALWAYS( !pItem->fg.isSubquery ) |
| 149258 | + && (pItem->fg.fixedSchema || pItem->u4.zDatabase==0) |
| 148917 | 149259 | && 0==sqlite3StrICmp(pItem->zName, pCte->zName) |
| 148918 | 149260 | ){ |
| 148919 | | - pItem->pTab = pTab; |
| 149261 | + pItem->pSTab = pTab; |
| 148920 | 149262 | pTab->nTabRef++; |
| 148921 | 149263 | pItem->fg.isRecursive = 1; |
| 148922 | 149264 | if( pRecTerm->selFlags & SF_Recursive ){ |
| 148923 | 149265 | sqlite3ErrorMsg(pParse, |
| 148924 | 149266 | "multiple references to recursive table: %s", pCte->zName |
| | @@ -149016,15 +149358,18 @@ |
| 149016 | 149358 | ** allocates and populates the SrcItem.pTab object. If successful, |
| 149017 | 149359 | ** SQLITE_OK is returned. Otherwise, if an OOM error is encountered, |
| 149018 | 149360 | ** SQLITE_NOMEM. |
| 149019 | 149361 | */ |
| 149020 | 149362 | SQLITE_PRIVATE int sqlite3ExpandSubquery(Parse *pParse, SrcItem *pFrom){ |
| 149021 | | - Select *pSel = pFrom->pSelect; |
| 149363 | + Select *pSel; |
| 149022 | 149364 | Table *pTab; |
| 149023 | 149365 | |
| 149366 | + assert( pFrom->fg.isSubquery ); |
| 149367 | + assert( pFrom->u4.pSubq!=0 ); |
| 149368 | + pSel = pFrom->u4.pSubq->pSelect; |
| 149024 | 149369 | assert( pSel ); |
| 149025 | | - pFrom->pTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); |
| 149370 | + pFrom->pSTab = pTab = sqlite3DbMallocZero(pParse->db, sizeof(Table)); |
| 149026 | 149371 | if( pTab==0 ) return SQLITE_NOMEM; |
| 149027 | 149372 | pTab->nTabRef = 1; |
| 149028 | 149373 | if( pFrom->zAlias ){ |
| 149029 | 149374 | pTab->zName = sqlite3DbStrDup(pParse->db, pFrom->zAlias); |
| 149030 | 149375 | }else{ |
| | @@ -149140,37 +149485,39 @@ |
| 149140 | 149485 | ** an entry of the FROM clause is a subquery instead of a table or view, |
| 149141 | 149486 | ** then create a transient table structure to describe the subquery. |
| 149142 | 149487 | */ |
| 149143 | 149488 | for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ |
| 149144 | 149489 | Table *pTab; |
| 149145 | | - assert( pFrom->fg.isRecursive==0 || pFrom->pTab!=0 ); |
| 149146 | | - if( pFrom->pTab ) continue; |
| 149490 | + assert( pFrom->fg.isRecursive==0 || pFrom->pSTab!=0 ); |
| 149491 | + if( pFrom->pSTab ) continue; |
| 149147 | 149492 | assert( pFrom->fg.isRecursive==0 ); |
| 149148 | 149493 | if( pFrom->zName==0 ){ |
| 149149 | 149494 | #ifndef SQLITE_OMIT_SUBQUERY |
| 149150 | | - Select *pSel = pFrom->pSelect; |
| 149495 | + Select *pSel; |
| 149496 | + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq!=0 ); |
| 149497 | + pSel = pFrom->u4.pSubq->pSelect; |
| 149151 | 149498 | /* A sub-query in the FROM clause of a SELECT */ |
| 149152 | 149499 | assert( pSel!=0 ); |
| 149153 | | - assert( pFrom->pTab==0 ); |
| 149500 | + assert( pFrom->pSTab==0 ); |
| 149154 | 149501 | if( sqlite3WalkSelect(pWalker, pSel) ) return WRC_Abort; |
| 149155 | 149502 | if( sqlite3ExpandSubquery(pParse, pFrom) ) return WRC_Abort; |
| 149156 | 149503 | #endif |
| 149157 | 149504 | #ifndef SQLITE_OMIT_CTE |
| 149158 | 149505 | }else if( (rc = resolveFromTermToCte(pParse, pWalker, pFrom))!=0 ){ |
| 149159 | 149506 | if( rc>1 ) return WRC_Abort; |
| 149160 | | - pTab = pFrom->pTab; |
| 149507 | + pTab = pFrom->pSTab; |
| 149161 | 149508 | assert( pTab!=0 ); |
| 149162 | 149509 | #endif |
| 149163 | 149510 | }else{ |
| 149164 | 149511 | /* An ordinary table or view name in the FROM clause */ |
| 149165 | | - assert( pFrom->pTab==0 ); |
| 149166 | | - pFrom->pTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); |
| 149512 | + assert( pFrom->pSTab==0 ); |
| 149513 | + pFrom->pSTab = pTab = sqlite3LocateTableItem(pParse, 0, pFrom); |
| 149167 | 149514 | if( pTab==0 ) return WRC_Abort; |
| 149168 | 149515 | if( pTab->nTabRef>=0xffff ){ |
| 149169 | 149516 | sqlite3ErrorMsg(pParse, "too many references to \"%s\": max 65535", |
| 149170 | 149517 | pTab->zName); |
| 149171 | | - pFrom->pTab = 0; |
| 149518 | + pFrom->pSTab = 0; |
| 149172 | 149519 | return WRC_Abort; |
| 149173 | 149520 | } |
| 149174 | 149521 | pTab->nTabRef++; |
| 149175 | 149522 | if( !IsVirtual(pTab) && cannotBeFunction(pParse, pFrom) ){ |
| 149176 | 149523 | return WRC_Abort; |
| | @@ -149178,19 +149525,19 @@ |
| 149178 | 149525 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_VIRTUALTABLE) |
| 149179 | 149526 | if( !IsOrdinaryTable(pTab) ){ |
| 149180 | 149527 | i16 nCol; |
| 149181 | 149528 | u8 eCodeOrig = pWalker->eCode; |
| 149182 | 149529 | if( sqlite3ViewGetColumnNames(pParse, pTab) ) return WRC_Abort; |
| 149183 | | - assert( pFrom->pSelect==0 ); |
| 149530 | + assert( pFrom->fg.isSubquery==0 ); |
| 149184 | 149531 | if( IsView(pTab) ){ |
| 149185 | 149532 | if( (db->flags & SQLITE_EnableView)==0 |
| 149186 | 149533 | && pTab->pSchema!=db->aDb[1].pSchema |
| 149187 | 149534 | ){ |
| 149188 | 149535 | sqlite3ErrorMsg(pParse, "access to view \"%s\" prohibited", |
| 149189 | 149536 | pTab->zName); |
| 149190 | 149537 | } |
| 149191 | | - pFrom->pSelect = sqlite3SelectDup(db, pTab->u.view.pSelect, 0); |
| 149538 | + sqlite3SrcItemAttachSubquery(pParse, pFrom, pTab->u.view.pSelect, 1); |
| 149192 | 149539 | } |
| 149193 | 149540 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 149194 | 149541 | else if( ALWAYS(IsVirtual(pTab)) |
| 149195 | 149542 | && pFrom->fg.fromDDL |
| 149196 | 149543 | && ALWAYS(pTab->u.vtab.p!=0) |
| | @@ -149202,11 +149549,13 @@ |
| 149202 | 149549 | assert( SQLITE_VTABRISK_Normal==1 && SQLITE_VTABRISK_High==2 ); |
| 149203 | 149550 | #endif |
| 149204 | 149551 | nCol = pTab->nCol; |
| 149205 | 149552 | pTab->nCol = -1; |
| 149206 | 149553 | pWalker->eCode = 1; /* Turn on Select.selId renumbering */ |
| 149207 | | - sqlite3WalkSelect(pWalker, pFrom->pSelect); |
| 149554 | + if( pFrom->fg.isSubquery ){ |
| 149555 | + sqlite3WalkSelect(pWalker, pFrom->u4.pSubq->pSelect); |
| 149556 | + } |
| 149208 | 149557 | pWalker->eCode = eCodeOrig; |
| 149209 | 149558 | pTab->nCol = nCol; |
| 149210 | 149559 | } |
| 149211 | 149560 | #endif |
| 149212 | 149561 | } |
| | @@ -149289,11 +149638,11 @@ |
| 149289 | 149638 | assert( ExprUseWOfst(pE) ); |
| 149290 | 149639 | iErrOfst = pE->w.iOfst; |
| 149291 | 149640 | } |
| 149292 | 149641 | for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ |
| 149293 | 149642 | int nAdd; /* Number of cols including rowid */ |
| 149294 | | - Table *pTab = pFrom->pTab; /* Table for this data source */ |
| 149643 | + Table *pTab = pFrom->pSTab; /* Table for this data source */ |
| 149295 | 149644 | ExprList *pNestedFrom; /* Result-set of a nested FROM clause */ |
| 149296 | 149645 | char *zTabName; /* AS name for this data source */ |
| 149297 | 149646 | const char *zSchemaName = 0; /* Schema name for this data source */ |
| 149298 | 149647 | int iDb; /* Schema index for this data src */ |
| 149299 | 149648 | IdList *pUsing; /* USING clause for pFrom[1] */ |
| | @@ -149300,14 +149649,15 @@ |
| 149300 | 149649 | |
| 149301 | 149650 | if( (zTabName = pFrom->zAlias)==0 ){ |
| 149302 | 149651 | zTabName = pTab->zName; |
| 149303 | 149652 | } |
| 149304 | 149653 | if( db->mallocFailed ) break; |
| 149305 | | - assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom->pSelect) ); |
| 149654 | + assert( (int)pFrom->fg.isNestedFrom == IsNestedFrom(pFrom) ); |
| 149306 | 149655 | if( pFrom->fg.isNestedFrom ){ |
| 149307 | | - assert( pFrom->pSelect!=0 ); |
| 149308 | | - pNestedFrom = pFrom->pSelect->pEList; |
| 149656 | + assert( pFrom->fg.isSubquery && pFrom->u4.pSubq ); |
| 149657 | + assert( pFrom->u4.pSubq->pSelect!=0 ); |
| 149658 | + pNestedFrom = pFrom->u4.pSubq->pSelect->pEList; |
| 149309 | 149659 | assert( pNestedFrom!=0 ); |
| 149310 | 149660 | assert( pNestedFrom->nExpr==pTab->nCol ); |
| 149311 | 149661 | assert( VisibleRowid(pTab)==0 || ViewCanHaveRowid ); |
| 149312 | 149662 | }else{ |
| 149313 | 149663 | if( zTName && sqlite3StrICmp(zTName, zTabName)!=0 ){ |
| | @@ -149542,18 +149892,16 @@ |
| 149542 | 149892 | p->selFlags |= SF_HasTypeInfo; |
| 149543 | 149893 | pParse = pWalker->pParse; |
| 149544 | 149894 | assert( (p->selFlags & SF_Resolved) ); |
| 149545 | 149895 | pTabList = p->pSrc; |
| 149546 | 149896 | for(i=0, pFrom=pTabList->a; i<pTabList->nSrc; i++, pFrom++){ |
| 149547 | | - Table *pTab = pFrom->pTab; |
| 149897 | + Table *pTab = pFrom->pSTab; |
| 149548 | 149898 | assert( pTab!=0 ); |
| 149549 | | - if( (pTab->tabFlags & TF_Ephemeral)!=0 ){ |
| 149899 | + if( (pTab->tabFlags & TF_Ephemeral)!=0 && pFrom->fg.isSubquery ){ |
| 149550 | 149900 | /* A sub-query in the FROM clause of a SELECT */ |
| 149551 | | - Select *pSel = pFrom->pSelect; |
| 149552 | | - if( pSel ){ |
| 149553 | | - sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); |
| 149554 | | - } |
| 149901 | + Select *pSel = pFrom->u4.pSubq->pSelect; |
| 149902 | + sqlite3SubqueryColumnTypes(pParse, pTab, pSel, SQLITE_AFF_NONE); |
| 149555 | 149903 | } |
| 149556 | 149904 | } |
| 149557 | 149905 | } |
| 149558 | 149906 | #endif |
| 149559 | 149907 | |
| | @@ -149863,10 +150211,11 @@ |
| 149863 | 150211 | int i; |
| 149864 | 150212 | struct AggInfo_func *pF; |
| 149865 | 150213 | for(i=0, pF=pAggInfo->aFunc; i<pAggInfo->nFunc; i++, pF++){ |
| 149866 | 150214 | ExprList *pList; |
| 149867 | 150215 | assert( ExprUseXList(pF->pFExpr) ); |
| 150216 | + if( pParse->nErr ) return; |
| 149868 | 150217 | pList = pF->pFExpr->x.pList; |
| 149869 | 150218 | if( pF->iOBTab>=0 ){ |
| 149870 | 150219 | /* For an ORDER BY aggregate, calls to OP_AggStep were deferred. Inputs |
| 149871 | 150220 | ** were stored in emphermal table pF->iOBTab. Here, we extract those |
| 149872 | 150221 | ** inputs (in ORDER BY order) and make all calls to OP_AggStep |
| | @@ -150072,19 +150421,21 @@ |
| 150072 | 150421 | sqlite3ReleaseTempRange(pParse, regAgg, nArg); |
| 150073 | 150422 | } |
| 150074 | 150423 | if( addrNext ){ |
| 150075 | 150424 | sqlite3VdbeResolveLabel(v, addrNext); |
| 150076 | 150425 | } |
| 150426 | + if( pParse->nErr ) return; |
| 150077 | 150427 | } |
| 150078 | 150428 | if( regHit==0 && pAggInfo->nAccumulator ){ |
| 150079 | 150429 | regHit = regAcc; |
| 150080 | 150430 | } |
| 150081 | 150431 | if( regHit ){ |
| 150082 | 150432 | addrHitTest = sqlite3VdbeAddOp1(v, OP_If, regHit); VdbeCoverage(v); |
| 150083 | 150433 | } |
| 150084 | 150434 | for(i=0, pC=pAggInfo->aCol; i<pAggInfo->nAccumulator; i++, pC++){ |
| 150085 | 150435 | sqlite3ExprCode(pParse, pC->pCExpr, AggInfoColumnReg(pAggInfo,i)); |
| 150436 | + if( pParse->nErr ) return; |
| 150086 | 150437 | } |
| 150087 | 150438 | |
| 150088 | 150439 | pAggInfo->directMode = 0; |
| 150089 | 150440 | if( addrHitTest ){ |
| 150090 | 150441 | sqlite3VdbeJumpHereOrPopInst(v, addrHitTest); |
| | @@ -150196,29 +150547,32 @@ |
| 150196 | 150547 | SrcList *pTabList, /* Search for self-joins in this FROM clause */ |
| 150197 | 150548 | SrcItem *pThis, /* Search for prior reference to this subquery */ |
| 150198 | 150549 | int iFirst, int iEnd /* Range of FROM-clause entries to search. */ |
| 150199 | 150550 | ){ |
| 150200 | 150551 | SrcItem *pItem; |
| 150201 | | - assert( pThis->pSelect!=0 ); |
| 150202 | | - if( pThis->pSelect->selFlags & SF_PushDown ) return 0; |
| 150552 | + Select *pSel; |
| 150553 | + assert( pThis->fg.isSubquery ); |
| 150554 | + pSel = pThis->u4.pSubq->pSelect; |
| 150555 | + assert( pSel!=0 ); |
| 150556 | + if( pSel->selFlags & SF_PushDown ) return 0; |
| 150203 | 150557 | while( iFirst<iEnd ){ |
| 150204 | 150558 | Select *pS1; |
| 150205 | 150559 | pItem = &pTabList->a[iFirst++]; |
| 150206 | | - if( pItem->pSelect==0 ) continue; |
| 150560 | + if( !pItem->fg.isSubquery ) continue; |
| 150207 | 150561 | if( pItem->fg.viaCoroutine ) continue; |
| 150208 | 150562 | if( pItem->zName==0 ) continue; |
| 150209 | | - assert( pItem->pTab!=0 ); |
| 150210 | | - assert( pThis->pTab!=0 ); |
| 150211 | | - if( pItem->pTab->pSchema!=pThis->pTab->pSchema ) continue; |
| 150563 | + assert( pItem->pSTab!=0 ); |
| 150564 | + assert( pThis->pSTab!=0 ); |
| 150565 | + if( pItem->pSTab->pSchema!=pThis->pSTab->pSchema ) continue; |
| 150212 | 150566 | if( sqlite3_stricmp(pItem->zName, pThis->zName)!=0 ) continue; |
| 150213 | | - pS1 = pItem->pSelect; |
| 150214 | | - if( pItem->pTab->pSchema==0 && pThis->pSelect->selId!=pS1->selId ){ |
| 150567 | + pS1 = pItem->u4.pSubq->pSelect; |
| 150568 | + if( pItem->pSTab->pSchema==0 && pSel->selId!=pS1->selId ){ |
| 150215 | 150569 | /* The query flattener left two different CTE tables with identical |
| 150216 | 150570 | ** names in the same FROM clause. */ |
| 150217 | 150571 | continue; |
| 150218 | 150572 | } |
| 150219 | | - if( pItem->pSelect->selFlags & SF_PushDown ){ |
| 150573 | + if( pS1->selFlags & SF_PushDown ){ |
| 150220 | 150574 | /* The view was modified by some other optimization such as |
| 150221 | 150575 | ** pushDownWhereTerms() */ |
| 150222 | 150576 | continue; |
| 150223 | 150577 | } |
| 150224 | 150578 | return pItem; |
| | @@ -150258,10 +150612,11 @@ |
| 150258 | 150612 | static int countOfViewOptimization(Parse *pParse, Select *p){ |
| 150259 | 150613 | Select *pSub, *pPrior; |
| 150260 | 150614 | Expr *pExpr; |
| 150261 | 150615 | Expr *pCount; |
| 150262 | 150616 | sqlite3 *db; |
| 150617 | + SrcItem *pFrom; |
| 150263 | 150618 | if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */ |
| 150264 | 150619 | if( p->pEList->nExpr!=1 ) return 0; /* Single result column */ |
| 150265 | 150620 | if( p->pWhere ) return 0; |
| 150266 | 150621 | if( p->pHaving ) return 0; |
| 150267 | 150622 | if( p->pGroupBy ) return 0; |
| | @@ -150272,30 +150627,30 @@ |
| 150272 | 150627 | if( sqlite3_stricmp(pExpr->u.zToken,"count") ) return 0; /* Is count() */ |
| 150273 | 150628 | assert( ExprUseXList(pExpr) ); |
| 150274 | 150629 | if( pExpr->x.pList!=0 ) return 0; /* Must be count(*) */ |
| 150275 | 150630 | if( p->pSrc->nSrc!=1 ) return 0; /* One table in FROM */ |
| 150276 | 150631 | if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */ |
| 150277 | | - pSub = p->pSrc->a[0].pSelect; |
| 150278 | | - if( pSub==0 ) return 0; /* The FROM is a subquery */ |
| 150632 | + pFrom = p->pSrc->a; |
| 150633 | + if( pFrom->fg.isSubquery==0 ) return 0; /* FROM is a subquery */ |
| 150634 | + pSub = pFrom->u4.pSubq->pSelect; |
| 150279 | 150635 | if( pSub->pPrior==0 ) return 0; /* Must be a compound */ |
| 150280 | 150636 | if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */ |
| 150281 | 150637 | do{ |
| 150282 | 150638 | if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */ |
| 150283 | 150639 | if( pSub->pWhere ) return 0; /* No WHERE clause */ |
| 150284 | 150640 | if( pSub->pLimit ) return 0; /* No LIMIT clause */ |
| 150285 | 150641 | if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */ |
| 150286 | 150642 | assert( pSub->pHaving==0 ); /* Due to the previous */ |
| 150287 | | - pSub = pSub->pPrior; /* Repeat over compound */ |
| 150643 | + pSub = pSub->pPrior; /* Repeat over compound */ |
| 150288 | 150644 | }while( pSub ); |
| 150289 | 150645 | |
| 150290 | 150646 | /* If we reach this point then it is OK to perform the transformation */ |
| 150291 | 150647 | |
| 150292 | 150648 | db = pParse->db; |
| 150293 | 150649 | pCount = pExpr; |
| 150294 | 150650 | pExpr = 0; |
| 150295 | | - pSub = p->pSrc->a[0].pSelect; |
| 150296 | | - p->pSrc->a[0].pSelect = 0; |
| 150651 | + pSub = sqlite3SubqueryDetach(db, pFrom); |
| 150297 | 150652 | sqlite3SrcListDelete(db, p->pSrc); |
| 150298 | 150653 | p->pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*p->pSrc)); |
| 150299 | 150654 | while( pSub ){ |
| 150300 | 150655 | Expr *pTerm; |
| 150301 | 150656 | pPrior = pSub->pPrior; |
| | @@ -150336,16 +150691,16 @@ |
| 150336 | 150691 | static int sameSrcAlias(SrcItem *p0, SrcList *pSrc){ |
| 150337 | 150692 | int i; |
| 150338 | 150693 | for(i=0; i<pSrc->nSrc; i++){ |
| 150339 | 150694 | SrcItem *p1 = &pSrc->a[i]; |
| 150340 | 150695 | if( p1==p0 ) continue; |
| 150341 | | - if( p0->pTab==p1->pTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ |
| 150696 | + if( p0->pSTab==p1->pSTab && 0==sqlite3_stricmp(p0->zAlias, p1->zAlias) ){ |
| 150342 | 150697 | return 1; |
| 150343 | 150698 | } |
| 150344 | | - if( p1->pSelect |
| 150345 | | - && (p1->pSelect->selFlags & SF_NestedFrom)!=0 |
| 150346 | | - && sameSrcAlias(p0, p1->pSelect->pSrc) |
| 150699 | + if( p1->fg.isSubquery |
| 150700 | + && (p1->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 |
| 150701 | + && sameSrcAlias(p0, p1->u4.pSubq->pSelect->pSrc) |
| 150347 | 150702 | ){ |
| 150348 | 150703 | return 1; |
| 150349 | 150704 | } |
| 150350 | 150705 | } |
| 150351 | 150706 | return 0; |
| | @@ -150406,17 +150761,17 @@ |
| 150406 | 150761 | while( 1 /*exit-by-break*/ ){ |
| 150407 | 150762 | if( pItem->fg.jointype & (JT_OUTER|JT_CROSS) ) return 0; /* (1c-ii) */ |
| 150408 | 150763 | if( i==0 ) break; |
| 150409 | 150764 | i--; |
| 150410 | 150765 | pItem--; |
| 150411 | | - if( pItem->pSelect!=0 ) return 0; /* (1c-i) */ |
| 150766 | + if( pItem->fg.isSubquery ) return 0; /* (1c-i) */ |
| 150412 | 150767 | } |
| 150413 | 150768 | return 1; |
| 150414 | 150769 | } |
| 150415 | 150770 | |
| 150416 | 150771 | /* |
| 150417 | | -** Generate code for the SELECT statement given in the p argument. |
| 150772 | +** Generate byte-code for the SELECT statement given in the p argument. |
| 150418 | 150773 | ** |
| 150419 | 150774 | ** The results are returned according to the SelectDest structure. |
| 150420 | 150775 | ** See comments in sqliteInt.h for further information. |
| 150421 | 150776 | ** |
| 150422 | 150777 | ** This routine returns the number of errors. If any errors are |
| | @@ -150423,10 +150778,44 @@ |
| 150423 | 150778 | ** encountered, then an appropriate error message is left in |
| 150424 | 150779 | ** pParse->zErrMsg. |
| 150425 | 150780 | ** |
| 150426 | 150781 | ** This routine does NOT free the Select structure passed in. The |
| 150427 | 150782 | ** calling function needs to do that. |
| 150783 | +** |
| 150784 | +** This is a long function. The following is an outline of the processing |
| 150785 | +** steps, with tags referencing various milestones: |
| 150786 | +** |
| 150787 | +** * Resolve names and similar preparation tag-select-0100 |
| 150788 | +** * Scan of the FROM clause tag-select-0200 |
| 150789 | +** + OUTER JOIN strength reduction tag-select-0220 |
| 150790 | +** + Sub-query ORDER BY removal tag-select-0230 |
| 150791 | +** + Query flattening tag-select-0240 |
| 150792 | +** * Separate subroutine for compound-SELECT tag-select-0300 |
| 150793 | +** * WHERE-clause constant propagation tag-select-0330 |
| 150794 | +** * Count()-of-VIEW optimization tag-select-0350 |
| 150795 | +** * Scan of the FROM clause again tag-select-0400 |
| 150796 | +** + Authorize unreferenced tables tag-select-0410 |
| 150797 | +** + Predicate push-down optimization tag-select-0420 |
| 150798 | +** + Omit unused subquery columns optimization tag-select-0440 |
| 150799 | +** + Generate code to implement subqueries tag-select-0480 |
| 150800 | +** - Co-routines tag-select-0482 |
| 150801 | +** - Reuse previously computed CTE tag-select-0484 |
| 150802 | +** - REuse previously computed VIEW tag-select-0486 |
| 150803 | +** - Materialize a VIEW or CTE tag-select-0488 |
| 150804 | +** * DISTINCT ORDER BY -> GROUP BY optimization tag-select-0500 |
| 150805 | +** * Set up for ORDER BY tag-select-0600 |
| 150806 | +** * Create output table tag-select-0630 |
| 150807 | +** * Prepare registers for LIMIT tag-select-0650 |
| 150808 | +** * Setup for DISTINCT tag-select-0680 |
| 150809 | +** * Generate code for non-aggregate and non-GROUP BY tag-select-0700 |
| 150810 | +** * Generate code for aggregate and/or GROUP BY tag-select-0800 |
| 150811 | +** + GROUP BY queries tag-select-0810 |
| 150812 | +** + non-GROUP BY queries tag-select-0820 |
| 150813 | +** - Special case of count() w/o GROUP BY tag-select-0821 |
| 150814 | +** - General case of non-GROUP BY aggregates tag-select-0822 |
| 150815 | +** * Sort results, as needed tag-select-0900 |
| 150816 | +** * Internal self-checks tag-select-1000 |
| 150428 | 150817 | */ |
| 150429 | 150818 | SQLITE_PRIVATE int sqlite3Select( |
| 150430 | 150819 | Parse *pParse, /* The parser context */ |
| 150431 | 150820 | Select *p, /* The SELECT statement being coded. */ |
| 150432 | 150821 | SelectDest *pDest /* What to do with the query results */ |
| | @@ -150466,10 +150855,11 @@ |
| 150466 | 150855 | } |
| 150467 | 150856 | sqlite3ShowSelect(p); |
| 150468 | 150857 | } |
| 150469 | 150858 | #endif |
| 150470 | 150859 | |
| 150860 | + /* tag-select-0100 */ |
| 150471 | 150861 | assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); |
| 150472 | 150862 | assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); |
| 150473 | 150863 | assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistQueue ); |
| 150474 | 150864 | assert( p->pOrderBy==0 || pDest->eDest!=SRT_Queue ); |
| 150475 | 150865 | if( IgnorableDistinct(pDest) ){ |
| | @@ -150517,11 +150907,11 @@ |
| 150517 | 150907 | if( p->selFlags & SF_UFSrcCheck ){ |
| 150518 | 150908 | SrcItem *p0 = &p->pSrc->a[0]; |
| 150519 | 150909 | if( sameSrcAlias(p0, p->pSrc) ){ |
| 150520 | 150910 | sqlite3ErrorMsg(pParse, |
| 150521 | 150911 | "target object/alias may not appear in FROM clause: %s", |
| 150522 | | - p0->zAlias ? p0->zAlias : p0->pTab->zName |
| 150912 | + p0->zAlias ? p0->zAlias : p0->pSTab->zName |
| 150523 | 150913 | ); |
| 150524 | 150914 | goto select_end; |
| 150525 | 150915 | } |
| 150526 | 150916 | |
| 150527 | 150917 | /* Clear the SF_UFSrcCheck flag. The check has already been performed, |
| | @@ -150552,16 +150942,17 @@ |
| 150552 | 150942 | memset(&sSort, 0, sizeof(sSort)); |
| 150553 | 150943 | sSort.pOrderBy = p->pOrderBy; |
| 150554 | 150944 | |
| 150555 | 150945 | /* Try to do various optimizations (flattening subqueries, and strength |
| 150556 | 150946 | ** reduction of join operators) in the FROM clause up into the main query |
| 150947 | + ** tag-select-0200 |
| 150557 | 150948 | */ |
| 150558 | 150949 | #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) |
| 150559 | 150950 | for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ |
| 150560 | 150951 | SrcItem *pItem = &pTabList->a[i]; |
| 150561 | | - Select *pSub = pItem->pSelect; |
| 150562 | | - Table *pTab = pItem->pTab; |
| 150952 | + Select *pSub = pItem->fg.isSubquery ? pItem->u4.pSubq->pSelect : 0; |
| 150953 | + Table *pTab = pItem->pSTab; |
| 150563 | 150954 | |
| 150564 | 150955 | /* The expander should have already created transient Table objects |
| 150565 | 150956 | ** even for FROM clause elements such as subqueries that do not correspond |
| 150566 | 150957 | ** to a real table */ |
| 150567 | 150958 | assert( pTab!=0 ); |
| | @@ -150574,10 +150965,11 @@ |
| 150574 | 150965 | ** |
| 150575 | 150966 | ** If terms of the i-th table are used in the WHERE clause in such a |
| 150576 | 150967 | ** way that the i-th table cannot be the NULL row of a join, then |
| 150577 | 150968 | ** perform the appropriate simplification. This is called |
| 150578 | 150969 | ** "OUTER JOIN strength reduction" in the SQLite documentation. |
| 150970 | + ** tag-select-0220 |
| 150579 | 150971 | */ |
| 150580 | 150972 | if( (pItem->fg.jointype & (JT_LEFT|JT_LTORJ))!=0 |
| 150581 | 150973 | && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor, |
| 150582 | 150974 | pItem->fg.jointype & JT_LTORJ) |
| 150583 | 150975 | && OptimizationEnabled(db, SQLITE_SimplifyJoin) |
| | @@ -150644,11 +151036,12 @@ |
| 150644 | 151036 | ** flattening in that case. |
| 150645 | 151037 | */ |
| 150646 | 151038 | if( (pSub->selFlags & SF_Aggregate)!=0 ) continue; |
| 150647 | 151039 | assert( pSub->pGroupBy==0 ); |
| 150648 | 151040 | |
| 150649 | | - /* If a FROM-clause subquery has an ORDER BY clause that is not |
| 151041 | + /* tag-select-0230: |
| 151042 | + ** If a FROM-clause subquery has an ORDER BY clause that is not |
| 150650 | 151043 | ** really doing anything, then delete it now so that it does not |
| 150651 | 151044 | ** interfere with query flattening. See the discussion at |
| 150652 | 151045 | ** https://sqlite.org/forum/forumpost/2d76f2bcf65d256a |
| 150653 | 151046 | ** |
| 150654 | 151047 | ** Beware of these cases where the ORDER BY clause may not be safely |
| | @@ -150710,10 +151103,11 @@ |
| 150710 | 151103 | || (pTabList->a[1].fg.jointype&(JT_OUTER|JT_CROSS))!=0) |
| 150711 | 151104 | ){ |
| 150712 | 151105 | continue; |
| 150713 | 151106 | } |
| 150714 | 151107 | |
| 151108 | + /* tag-select-0240 */ |
| 150715 | 151109 | if( flattenSubquery(pParse, p, i, isAgg) ){ |
| 150716 | 151110 | if( pParse->nErr ) goto select_end; |
| 150717 | 151111 | /* This subquery can be absorbed into its parent. */ |
| 150718 | 151112 | i = -1; |
| 150719 | 151113 | } |
| | @@ -150725,11 +151119,11 @@ |
| 150725 | 151119 | } |
| 150726 | 151120 | #endif |
| 150727 | 151121 | |
| 150728 | 151122 | #ifndef SQLITE_OMIT_COMPOUND_SELECT |
| 150729 | 151123 | /* Handle compound SELECT statements using the separate multiSelect() |
| 150730 | | - ** procedure. |
| 151124 | + ** procedure. tag-select-0300 |
| 150731 | 151125 | */ |
| 150732 | 151126 | if( p->pPrior ){ |
| 150733 | 151127 | rc = multiSelect(pParse, p, pDest); |
| 150734 | 151128 | #if TREETRACE_ENABLED |
| 150735 | 151129 | TREETRACE(0x400,pParse,p,("end compound-select processing\n")); |
| | @@ -150741,13 +151135,13 @@ |
| 150741 | 151135 | return rc; |
| 150742 | 151136 | } |
| 150743 | 151137 | #endif |
| 150744 | 151138 | |
| 150745 | 151139 | /* Do the WHERE-clause constant propagation optimization if this is |
| 150746 | | - ** a join. No need to speed time on this operation for non-join queries |
| 151140 | + ** a join. No need to spend time on this operation for non-join queries |
| 150747 | 151141 | ** as the equivalent optimization will be handled by query planner in |
| 150748 | | - ** sqlite3WhereBegin(). |
| 151142 | + ** sqlite3WhereBegin(). tag-select-0330 |
| 150749 | 151143 | */ |
| 150750 | 151144 | if( p->pWhere!=0 |
| 150751 | 151145 | && p->pWhere->op==TK_AND |
| 150752 | 151146 | && OptimizationEnabled(db, SQLITE_PropagateConst) |
| 150753 | 151147 | && propagateConstants(pParse, p) |
| | @@ -150760,31 +151154,38 @@ |
| 150760 | 151154 | #endif |
| 150761 | 151155 | }else{ |
| 150762 | 151156 | TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n")); |
| 150763 | 151157 | } |
| 150764 | 151158 | |
| 151159 | + /* tag-select-0350 */ |
| 150765 | 151160 | if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView) |
| 150766 | 151161 | && countOfViewOptimization(pParse, p) |
| 150767 | 151162 | ){ |
| 150768 | 151163 | if( db->mallocFailed ) goto select_end; |
| 150769 | 151164 | pTabList = p->pSrc; |
| 150770 | 151165 | } |
| 150771 | 151166 | |
| 150772 | | - /* For each term in the FROM clause, do two things: |
| 150773 | | - ** (1) Authorized unreferenced tables |
| 150774 | | - ** (2) Generate code for all sub-queries |
| 151167 | + /* Loop over all terms in the FROM clause and do two things for each term: |
| 151168 | + ** |
| 151169 | + ** (1) Authorize unreferenced tables |
| 151170 | + ** (2) Generate code for all sub-queries |
| 151171 | + ** |
| 151172 | + ** tag-select-0400 |
| 150775 | 151173 | */ |
| 150776 | 151174 | for(i=0; i<pTabList->nSrc; i++){ |
| 150777 | 151175 | SrcItem *pItem = &pTabList->a[i]; |
| 150778 | 151176 | SrcItem *pPrior; |
| 150779 | 151177 | SelectDest dest; |
| 151178 | + Subquery *pSubq; |
| 150780 | 151179 | Select *pSub; |
| 150781 | 151180 | #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) |
| 150782 | 151181 | const char *zSavedAuthContext; |
| 150783 | 151182 | #endif |
| 150784 | 151183 | |
| 150785 | | - /* Issue SQLITE_READ authorizations with a fake column name for any |
| 151184 | + /* Authorized unreferenced tables. tag-select-0410 |
| 151185 | + ** |
| 151186 | + ** Issue SQLITE_READ authorizations with a fake column name for any |
| 150786 | 151187 | ** tables that are referenced but from which no values are extracted. |
| 150787 | 151188 | ** Examples of where these kinds of null SQLITE_READ authorizations |
| 150788 | 151189 | ** would occur: |
| 150789 | 151190 | ** |
| 150790 | 151191 | ** SELECT count(*) FROM t1; -- SQLITE_READ t1."" |
| | @@ -150797,21 +151198,32 @@ |
| 150797 | 151198 | ** which would be unambiguous. But legacy authorization callbacks might |
| 150798 | 151199 | ** assume the column name is non-NULL and segfault. The use of an empty |
| 150799 | 151200 | ** string for the fake column name seems safer. |
| 150800 | 151201 | */ |
| 150801 | 151202 | if( pItem->colUsed==0 && pItem->zName!=0 ){ |
| 150802 | | - sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", pItem->zDatabase); |
| 151203 | + const char *zDb; |
| 151204 | + if( pItem->fg.fixedSchema ){ |
| 151205 | + int iDb = sqlite3SchemaToIndex(pParse->db, pItem->u4.pSchema); |
| 151206 | + zDb = db->aDb[iDb].zDbSName; |
| 151207 | + }else if( pItem->fg.isSubquery ){ |
| 151208 | + zDb = 0; |
| 151209 | + }else{ |
| 151210 | + zDb = pItem->u4.zDatabase; |
| 151211 | + } |
| 151212 | + sqlite3AuthCheck(pParse, SQLITE_READ, pItem->zName, "", zDb); |
| 150803 | 151213 | } |
| 150804 | 151214 | |
| 150805 | 151215 | #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) |
| 150806 | 151216 | /* Generate code for all sub-queries in the FROM clause |
| 150807 | 151217 | */ |
| 150808 | | - pSub = pItem->pSelect; |
| 150809 | | - if( pSub==0 || pItem->addrFillSub!=0 ) continue; |
| 151218 | + if( pItem->fg.isSubquery==0 ) continue; |
| 151219 | + pSubq = pItem->u4.pSubq; |
| 151220 | + assert( pSubq!=0 ); |
| 151221 | + pSub = pSubq->pSelect; |
| 150810 | 151222 | |
| 150811 | 151223 | /* The code for a subquery should only be generated once. */ |
| 150812 | | - assert( pItem->addrFillSub==0 ); |
| 151224 | + if( pSubq->addrFillSub!=0 ) continue; |
| 150813 | 151225 | |
| 150814 | 151226 | /* Increment Parse.nHeight by the height of the largest expression |
| 150815 | 151227 | ** tree referred to by this, the parent select. The child select |
| 150816 | 151228 | ** may contain expression trees of at most |
| 150817 | 151229 | ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit |
| | @@ -150820,10 +151232,11 @@ |
| 150820 | 151232 | */ |
| 150821 | 151233 | pParse->nHeight += sqlite3SelectExprHeight(p); |
| 150822 | 151234 | |
| 150823 | 151235 | /* Make copies of constant WHERE-clause terms in the outer query down |
| 150824 | 151236 | ** inside the subquery. This can help the subquery to run more efficiently. |
| 151237 | + ** This is the "predicate push-down optimization". tag-select-0420 |
| 150825 | 151238 | */ |
| 150826 | 151239 | if( OptimizationEnabled(db, SQLITE_PushDown) |
| 150827 | 151240 | && (pItem->fg.isCte==0 |
| 150828 | 151241 | || (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2)) |
| 150829 | 151242 | && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i) |
| | @@ -150833,17 +151246,18 @@ |
| 150833 | 151246 | TREETRACE(0x4000,pParse,p, |
| 150834 | 151247 | ("After WHERE-clause push-down into subquery %d:\n", pSub->selId)); |
| 150835 | 151248 | sqlite3TreeViewSelect(0, p, 0); |
| 150836 | 151249 | } |
| 150837 | 151250 | #endif |
| 150838 | | - assert( pItem->pSelect && (pItem->pSelect->selFlags & SF_PushDown)!=0 ); |
| 151251 | + assert( pSubq->pSelect && (pSub->selFlags & SF_PushDown)!=0 ); |
| 150839 | 151252 | }else{ |
| 150840 | 151253 | TREETRACE(0x4000,pParse,p,("WHERE-lcause push-down not possible\n")); |
| 150841 | 151254 | } |
| 150842 | 151255 | |
| 150843 | 151256 | /* Convert unused result columns of the subquery into simple NULL |
| 150844 | 151257 | ** expressions, to avoid unneeded searching and computation. |
| 151258 | + ** tag-select-0440 |
| 150845 | 151259 | */ |
| 150846 | 151260 | if( OptimizationEnabled(db, SQLITE_NullUnusedCols) |
| 150847 | 151261 | && disableUnusedSubqueryResultColumns(pItem) |
| 150848 | 151262 | ){ |
| 150849 | 151263 | #if TREETRACE_ENABLED |
| | @@ -150857,64 +151271,70 @@ |
| 150857 | 151271 | } |
| 150858 | 151272 | |
| 150859 | 151273 | zSavedAuthContext = pParse->zAuthContext; |
| 150860 | 151274 | pParse->zAuthContext = pItem->zName; |
| 150861 | 151275 | |
| 150862 | | - /* Generate code to implement the subquery |
| 151276 | + /* Generate byte-code to implement the subquery tag-select-0480 |
| 150863 | 151277 | */ |
| 150864 | 151278 | if( fromClauseTermCanBeCoroutine(pParse, pTabList, i, p->selFlags) ){ |
| 150865 | 151279 | /* Implement a co-routine that will return a single row of the result |
| 150866 | | - ** set on each invocation. |
| 151280 | + ** set on each invocation. tag-select-0482 |
| 150867 | 151281 | */ |
| 150868 | 151282 | int addrTop = sqlite3VdbeCurrentAddr(v)+1; |
| 150869 | 151283 | |
| 150870 | | - pItem->regReturn = ++pParse->nMem; |
| 150871 | | - sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); |
| 151284 | + pSubq->regReturn = ++pParse->nMem; |
| 151285 | + sqlite3VdbeAddOp3(v, OP_InitCoroutine, pSubq->regReturn, 0, addrTop); |
| 150872 | 151286 | VdbeComment((v, "%!S", pItem)); |
| 150873 | | - pItem->addrFillSub = addrTop; |
| 150874 | | - sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); |
| 151287 | + pSubq->addrFillSub = addrTop; |
| 151288 | + sqlite3SelectDestInit(&dest, SRT_Coroutine, pSubq->regReturn); |
| 150875 | 151289 | ExplainQueryPlan((pParse, 1, "CO-ROUTINE %!S", pItem)); |
| 150876 | 151290 | sqlite3Select(pParse, pSub, &dest); |
| 150877 | | - pItem->pTab->nRowLogEst = pSub->nSelectRow; |
| 151291 | + pItem->pSTab->nRowLogEst = pSub->nSelectRow; |
| 150878 | 151292 | pItem->fg.viaCoroutine = 1; |
| 150879 | | - pItem->regResult = dest.iSdst; |
| 150880 | | - sqlite3VdbeEndCoroutine(v, pItem->regReturn); |
| 151293 | + pSubq->regResult = dest.iSdst; |
| 151294 | + sqlite3VdbeEndCoroutine(v, pSubq->regReturn); |
| 151295 | + VdbeComment((v, "end %!S", pItem)); |
| 150881 | 151296 | sqlite3VdbeJumpHere(v, addrTop-1); |
| 150882 | 151297 | sqlite3ClearTempRegCache(pParse); |
| 150883 | 151298 | }else if( pItem->fg.isCte && pItem->u2.pCteUse->addrM9e>0 ){ |
| 150884 | 151299 | /* This is a CTE for which materialization code has already been |
| 150885 | 151300 | ** generated. Invoke the subroutine to compute the materialization, |
| 150886 | | - ** the make the pItem->iCursor be a copy of the ephemeral table that |
| 150887 | | - ** holds the result of the materialization. */ |
| 151301 | + ** then make the pItem->iCursor be a copy of the ephemeral table that |
| 151302 | + ** holds the result of the materialization. tag-select-0484 */ |
| 150888 | 151303 | CteUse *pCteUse = pItem->u2.pCteUse; |
| 150889 | 151304 | sqlite3VdbeAddOp2(v, OP_Gosub, pCteUse->regRtn, pCteUse->addrM9e); |
| 150890 | 151305 | if( pItem->iCursor!=pCteUse->iCur ){ |
| 150891 | 151306 | sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pCteUse->iCur); |
| 150892 | 151307 | VdbeComment((v, "%!S", pItem)); |
| 150893 | 151308 | } |
| 150894 | 151309 | pSub->nSelectRow = pCteUse->nRowEst; |
| 150895 | 151310 | }else if( (pPrior = isSelfJoinView(pTabList, pItem, 0, i))!=0 ){ |
| 150896 | 151311 | /* This view has already been materialized by a prior entry in |
| 150897 | | - ** this same FROM clause. Reuse it. */ |
| 150898 | | - if( pPrior->addrFillSub ){ |
| 150899 | | - sqlite3VdbeAddOp2(v, OP_Gosub, pPrior->regReturn, pPrior->addrFillSub); |
| 151312 | + ** this same FROM clause. Reuse it. tag-select-0486 */ |
| 151313 | + Subquery *pPriorSubq; |
| 151314 | + assert( pPrior->fg.isSubquery ); |
| 151315 | + pPriorSubq = pPrior->u4.pSubq; |
| 151316 | + assert( pPriorSubq!=0 ); |
| 151317 | + if( pPriorSubq->addrFillSub ){ |
| 151318 | + sqlite3VdbeAddOp2(v, OP_Gosub, pPriorSubq->regReturn, |
| 151319 | + pPriorSubq->addrFillSub); |
| 150900 | 151320 | } |
| 150901 | 151321 | sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); |
| 150902 | | - pSub->nSelectRow = pPrior->pSelect->nSelectRow; |
| 151322 | + pSub->nSelectRow = pPriorSubq->pSelect->nSelectRow; |
| 150903 | 151323 | }else{ |
| 150904 | 151324 | /* Materialize the view. If the view is not correlated, generate a |
| 150905 | 151325 | ** subroutine to do the materialization so that subsequent uses of |
| 150906 | | - ** the same view can reuse the materialization. */ |
| 151326 | + ** the same view can reuse the materialization. tag-select-0488 */ |
| 150907 | 151327 | int topAddr; |
| 150908 | 151328 | int onceAddr = 0; |
| 150909 | 151329 | #ifdef SQLITE_ENABLE_STMT_SCANSTATUS |
| 150910 | 151330 | int addrExplain; |
| 150911 | 151331 | #endif |
| 150912 | 151332 | |
| 150913 | | - pItem->regReturn = ++pParse->nMem; |
| 151333 | + pSubq->regReturn = ++pParse->nMem; |
| 150914 | 151334 | topAddr = sqlite3VdbeAddOp0(v, OP_Goto); |
| 150915 | | - pItem->addrFillSub = topAddr+1; |
| 151335 | + pSubq->addrFillSub = topAddr+1; |
| 150916 | 151336 | pItem->fg.isMaterialized = 1; |
| 150917 | 151337 | if( pItem->fg.isCorrelated==0 ){ |
| 150918 | 151338 | /* If the subquery is not correlated and if we are not inside of |
| 150919 | 151339 | ** a trigger, then we only need to compute the value of the subquery |
| 150920 | 151340 | ** once. */ |
| | @@ -150925,21 +151345,21 @@ |
| 150925 | 151345 | } |
| 150926 | 151346 | sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); |
| 150927 | 151347 | |
| 150928 | 151348 | ExplainQueryPlan2(addrExplain, (pParse, 1, "MATERIALIZE %!S", pItem)); |
| 150929 | 151349 | sqlite3Select(pParse, pSub, &dest); |
| 150930 | | - pItem->pTab->nRowLogEst = pSub->nSelectRow; |
| 151350 | + pItem->pSTab->nRowLogEst = pSub->nSelectRow; |
| 150931 | 151351 | if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); |
| 150932 | | - sqlite3VdbeAddOp2(v, OP_Return, pItem->regReturn, topAddr+1); |
| 151352 | + sqlite3VdbeAddOp2(v, OP_Return, pSubq->regReturn, topAddr+1); |
| 150933 | 151353 | VdbeComment((v, "end %!S", pItem)); |
| 150934 | 151354 | sqlite3VdbeScanStatusRange(v, addrExplain, addrExplain, -1); |
| 150935 | 151355 | sqlite3VdbeJumpHere(v, topAddr); |
| 150936 | 151356 | sqlite3ClearTempRegCache(pParse); |
| 150937 | 151357 | if( pItem->fg.isCte && pItem->fg.isCorrelated==0 ){ |
| 150938 | 151358 | CteUse *pCteUse = pItem->u2.pCteUse; |
| 150939 | | - pCteUse->addrM9e = pItem->addrFillSub; |
| 150940 | | - pCteUse->regRtn = pItem->regReturn; |
| 151359 | + pCteUse->addrM9e = pSubq->addrFillSub; |
| 151360 | + pCteUse->regRtn = pSubq->regReturn; |
| 150941 | 151361 | pCteUse->iCur = pItem->iCursor; |
| 150942 | 151362 | pCteUse->nRowEst = pSub->nSelectRow; |
| 150943 | 151363 | } |
| 150944 | 151364 | } |
| 150945 | 151365 | if( db->mallocFailed ) goto select_end; |
| | @@ -150961,11 +151381,13 @@ |
| 150961 | 151381 | TREETRACE(0x8000,pParse,p,("After all FROM-clause analysis:\n")); |
| 150962 | 151382 | sqlite3TreeViewSelect(0, p, 0); |
| 150963 | 151383 | } |
| 150964 | 151384 | #endif |
| 150965 | 151385 | |
| 150966 | | - /* If the query is DISTINCT with an ORDER BY but is not an aggregate, and |
| 151386 | + /* tag-select-0500 |
| 151387 | + ** |
| 151388 | + ** If the query is DISTINCT with an ORDER BY but is not an aggregate, and |
| 150967 | 151389 | ** if the select-list is the same as the ORDER BY list, then this query |
| 150968 | 151390 | ** can be rewritten as a GROUP BY. In other words, this: |
| 150969 | 151391 | ** |
| 150970 | 151392 | ** SELECT DISTINCT xyz FROM ... ORDER BY xyz |
| 150971 | 151393 | ** |
| | @@ -151011,11 +151433,11 @@ |
| 151011 | 151433 | ** do the sorting. But this sorting ephemeral index might end up |
| 151012 | 151434 | ** being unused if the data can be extracted in pre-sorted order. |
| 151013 | 151435 | ** If that is the case, then the OP_OpenEphemeral instruction will be |
| 151014 | 151436 | ** changed to an OP_Noop once we figure out that the sorting index is |
| 151015 | 151437 | ** not needed. The sSort.addrSortIndex variable is used to facilitate |
| 151016 | | - ** that change. |
| 151438 | + ** that change. tag-select-0600 |
| 151017 | 151439 | */ |
| 151018 | 151440 | if( sSort.pOrderBy ){ |
| 151019 | 151441 | KeyInfo *pKeyInfo; |
| 151020 | 151442 | pKeyInfo = sqlite3KeyInfoFromExprList( |
| 151021 | 151443 | pParse, sSort.pOrderBy, 0, pEList->nExpr); |
| | @@ -151028,10 +151450,11 @@ |
| 151028 | 151450 | }else{ |
| 151029 | 151451 | sSort.addrSortIndex = -1; |
| 151030 | 151452 | } |
| 151031 | 151453 | |
| 151032 | 151454 | /* If the output is destined for a temporary table, open that table. |
| 151455 | + ** tag-select-0630 |
| 151033 | 151456 | */ |
| 151034 | 151457 | if( pDest->eDest==SRT_EphemTab ){ |
| 151035 | 151458 | sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pDest->iSDParm, pEList->nExpr); |
| 151036 | 151459 | if( p->selFlags & SF_NestedFrom ){ |
| 151037 | 151460 | /* Delete or NULL-out result columns that will never be used */ |
| | @@ -151045,11 +151468,11 @@ |
| 151045 | 151468 | if( pEList->a[ii].fg.bUsed==0 ) pEList->a[ii].pExpr->op = TK_NULL; |
| 151046 | 151469 | } |
| 151047 | 151470 | } |
| 151048 | 151471 | } |
| 151049 | 151472 | |
| 151050 | | - /* Set the limiter. |
| 151473 | + /* Set the limiter. tag-select-0650 |
| 151051 | 151474 | */ |
| 151052 | 151475 | iEnd = sqlite3VdbeMakeLabel(pParse); |
| 151053 | 151476 | if( (p->selFlags & SF_FixedLimit)==0 ){ |
| 151054 | 151477 | p->nSelectRow = 320; /* 4 billion rows */ |
| 151055 | 151478 | } |
| | @@ -151057,11 +151480,11 @@ |
| 151057 | 151480 | if( p->iLimit==0 && sSort.addrSortIndex>=0 ){ |
| 151058 | 151481 | sqlite3VdbeChangeOpcode(v, sSort.addrSortIndex, OP_SorterOpen); |
| 151059 | 151482 | sSort.sortFlags |= SORTFLAG_UseSorter; |
| 151060 | 151483 | } |
| 151061 | 151484 | |
| 151062 | | - /* Open an ephemeral index to use for the distinct set. |
| 151485 | + /* Open an ephemeral index to use for the distinct set. tag-select-0680 |
| 151063 | 151486 | */ |
| 151064 | 151487 | if( p->selFlags & SF_Distinct ){ |
| 151065 | 151488 | sDistinct.tabTnct = pParse->nTab++; |
| 151066 | 151489 | sDistinct.addrTnct = sqlite3VdbeAddOp4(v, OP_OpenEphemeral, |
| 151067 | 151490 | sDistinct.tabTnct, 0, 0, |
| | @@ -151072,11 +151495,11 @@ |
| 151072 | 151495 | }else{ |
| 151073 | 151496 | sDistinct.eTnctType = WHERE_DISTINCT_NOOP; |
| 151074 | 151497 | } |
| 151075 | 151498 | |
| 151076 | 151499 | if( !isAgg && pGroupBy==0 ){ |
| 151077 | | - /* No aggregate functions and no GROUP BY clause */ |
| 151500 | + /* No aggregate functions and no GROUP BY clause. tag-select-0700 */ |
| 151078 | 151501 | u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0) |
| 151079 | 151502 | | (p->selFlags & SF_FixedLimit); |
| 151080 | 151503 | #ifndef SQLITE_OMIT_WINDOWFUNC |
| 151081 | 151504 | Window *pWin = p->pWin; /* Main window object (or NULL) */ |
| 151082 | 151505 | if( pWin ){ |
| | @@ -151145,12 +151568,12 @@ |
| 151145 | 151568 | */ |
| 151146 | 151569 | TREETRACE(0x2,pParse,p,("WhereEnd\n")); |
| 151147 | 151570 | sqlite3WhereEnd(pWInfo); |
| 151148 | 151571 | } |
| 151149 | 151572 | }else{ |
| 151150 | | - /* This case when there exist aggregate functions or a GROUP BY clause |
| 151151 | | - ** or both */ |
| 151573 | + /* This case is for when there exist aggregate functions or a GROUP BY |
| 151574 | + ** clause or both. tag-select-0800 */ |
| 151152 | 151575 | NameContext sNC; /* Name context for processing aggregate information */ |
| 151153 | 151576 | int iAMem; /* First Mem address for storing current GROUP BY */ |
| 151154 | 151577 | int iBMem; /* First Mem address for previous GROUP BY */ |
| 151155 | 151578 | int iUseFlag; /* Mem address holding flag indicating that at least |
| 151156 | 151579 | ** one row of the input to the aggregator has been |
| | @@ -151265,11 +151688,11 @@ |
| 151265 | 151688 | } |
| 151266 | 151689 | #endif |
| 151267 | 151690 | |
| 151268 | 151691 | |
| 151269 | 151692 | /* Processing for aggregates with GROUP BY is very different and |
| 151270 | | - ** much more complex than aggregates without a GROUP BY. |
| 151693 | + ** much more complex than aggregates without a GROUP BY. tag-select-0810 |
| 151271 | 151694 | */ |
| 151272 | 151695 | if( pGroupBy ){ |
| 151273 | 151696 | KeyInfo *pKeyInfo; /* Keying information for the group by clause */ |
| 151274 | 151697 | int addr1; /* A-vs-B comparison jump */ |
| 151275 | 151698 | int addrOutputRow; /* Start of subroutine that outputs a result row */ |
| | @@ -151562,13 +151985,16 @@ |
| 151562 | 151985 | struct AggInfo_func *pF = &pAggInfo->aFunc[0]; |
| 151563 | 151986 | fixDistinctOpenEph(pParse, eDist, pF->iDistinct, pF->iDistAddr); |
| 151564 | 151987 | } |
| 151565 | 151988 | } /* endif pGroupBy. Begin aggregate queries without GROUP BY: */ |
| 151566 | 151989 | else { |
| 151990 | + /* Aggregate functions without GROUP BY. tag-select-0820 */ |
| 151567 | 151991 | Table *pTab; |
| 151568 | 151992 | if( (pTab = isSimpleCount(p, pAggInfo))!=0 ){ |
| 151569 | | - /* If isSimpleCount() returns a pointer to a Table structure, then |
| 151993 | + /* tag-select-0821 |
| 151994 | + ** |
| 151995 | + ** If isSimpleCount() returns a pointer to a Table structure, then |
| 151570 | 151996 | ** the SQL statement is of the form: |
| 151571 | 151997 | ** |
| 151572 | 151998 | ** SELECT count(*) FROM <tbl> |
| 151573 | 151999 | ** |
| 151574 | 152000 | ** where the Table structure returned represents table <tbl>. |
| | @@ -151623,10 +152049,12 @@ |
| 151623 | 152049 | assignAggregateRegisters(pParse, pAggInfo); |
| 151624 | 152050 | sqlite3VdbeAddOp2(v, OP_Count, iCsr, AggInfoFuncReg(pAggInfo,0)); |
| 151625 | 152051 | sqlite3VdbeAddOp1(v, OP_Close, iCsr); |
| 151626 | 152052 | explainSimpleCount(pParse, pTab, pBest); |
| 151627 | 152053 | }else{ |
| 152054 | + /* The general case of an aggregate query without GROUP BY |
| 152055 | + ** tag-select-0822 */ |
| 151628 | 152056 | int regAcc = 0; /* "populate accumulators" flag */ |
| 151629 | 152057 | ExprList *pDistinct = 0; |
| 151630 | 152058 | u16 distFlag = 0; |
| 151631 | 152059 | int eDist; |
| 151632 | 152060 | |
| | @@ -151711,11 +152139,11 @@ |
| 151711 | 152139 | if( sDistinct.eTnctType==WHERE_DISTINCT_UNORDERED ){ |
| 151712 | 152140 | explainTempTable(pParse, "DISTINCT"); |
| 151713 | 152141 | } |
| 151714 | 152142 | |
| 151715 | 152143 | /* If there is an ORDER BY clause, then we need to sort the results |
| 151716 | | - ** and send them to the callback one by one. |
| 152144 | + ** and send them to the callback one by one. tag-select-0900 |
| 151717 | 152145 | */ |
| 151718 | 152146 | if( sSort.pOrderBy ){ |
| 151719 | 152147 | assert( p->pEList==pEList ); |
| 151720 | 152148 | generateSortTail(pParse, p, &sSort, pEList->nExpr, pDest); |
| 151721 | 152149 | } |
| | @@ -151734,10 +152162,11 @@ |
| 151734 | 152162 | select_end: |
| 151735 | 152163 | assert( db->mallocFailed==0 || db->mallocFailed==1 ); |
| 151736 | 152164 | assert( db->mallocFailed==0 || pParse->nErr!=0 ); |
| 151737 | 152165 | sqlite3ExprListDelete(db, pMinMaxOrderBy); |
| 151738 | 152166 | #ifdef SQLITE_DEBUG |
| 152167 | + /* Internal self-checks. tag-select-1000 */ |
| 151739 | 152168 | if( pAggInfo && !db->mallocFailed ){ |
| 151740 | 152169 | #if TREETRACE_ENABLED |
| 151741 | 152170 | if( sqlite3TreeTrace & 0x20 ){ |
| 151742 | 152171 | TREETRACE(0x20,pParse,p,("Finished with AggInfo\n")); |
| 151743 | 152172 | printAggInfo(pAggInfo); |
| | @@ -152123,12 +152552,14 @@ |
| 152123 | 152552 | ** |
| 152124 | 152553 | ** To maintain backwards compatibility, ignore the database |
| 152125 | 152554 | ** name on pTableName if we are reparsing out of the schema table |
| 152126 | 152555 | */ |
| 152127 | 152556 | if( db->init.busy && iDb!=1 ){ |
| 152128 | | - sqlite3DbFree(db, pTableName->a[0].zDatabase); |
| 152129 | | - pTableName->a[0].zDatabase = 0; |
| 152557 | + assert( pTableName->a[0].fg.fixedSchema==0 ); |
| 152558 | + assert( pTableName->a[0].fg.isSubquery==0 ); |
| 152559 | + sqlite3DbFree(db, pTableName->a[0].u4.zDatabase); |
| 152560 | + pTableName->a[0].u4.zDatabase = 0; |
| 152130 | 152561 | } |
| 152131 | 152562 | |
| 152132 | 152563 | /* If the trigger name was unqualified, and the table is a temp table, |
| 152133 | 152564 | ** then set iDb to 1 to create the trigger in the temporary database. |
| 152134 | 152565 | ** If sqlite3SrcListLookup() returns 0, indicating the table does not |
| | @@ -152602,11 +153033,12 @@ |
| 152602 | 153033 | if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ |
| 152603 | 153034 | goto drop_trigger_cleanup; |
| 152604 | 153035 | } |
| 152605 | 153036 | |
| 152606 | 153037 | assert( pName->nSrc==1 ); |
| 152607 | | - zDb = pName->a[0].zDatabase; |
| 153038 | + assert( pName->a[0].fg.fixedSchema==0 && pName->a[0].fg.isSubquery==0 ); |
| 153039 | + zDb = pName->a[0].u4.zDatabase; |
| 152608 | 153040 | zName = pName->a[0].zName; |
| 152609 | 153041 | assert( zDb!=0 || sqlite3BtreeHoldsAllMutexes(db) ); |
| 152610 | 153042 | for(i=OMIT_TEMPDB; i<db->nDb; i++){ |
| 152611 | 153043 | int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ |
| 152612 | 153044 | if( zDb && sqlite3DbIsNamed(db, j, zDb)==0 ) continue; |
| | @@ -152839,11 +153271,13 @@ |
| 152839 | 153271 | assert( zName || pSrc==0 ); |
| 152840 | 153272 | if( pSrc ){ |
| 152841 | 153273 | Schema *pSchema = pStep->pTrig->pSchema; |
| 152842 | 153274 | pSrc->a[0].zName = zName; |
| 152843 | 153275 | if( pSchema!=db->aDb[1].pSchema ){ |
| 152844 | | - pSrc->a[0].pSchema = pSchema; |
| 153276 | + assert( pSrc->a[0].fg.fixedSchema || pSrc->a[0].u4.zDatabase==0 ); |
| 153277 | + pSrc->a[0].u4.pSchema = pSchema; |
| 153278 | + pSrc->a[0].fg.fixedSchema = 1; |
| 152845 | 153279 | } |
| 152846 | 153280 | if( pStep->pFrom ){ |
| 152847 | 153281 | SrcList *pDup = sqlite3SrcListDup(db, pStep->pFrom, 0); |
| 152848 | 153282 | if( pDup && pDup->nSrc>1 && !IN_RENAME_OBJECT ){ |
| 152849 | 153283 | Select *pSubquery; |
| | @@ -152952,11 +153386,11 @@ |
| 152952 | 153386 | SrcList *pSrc; |
| 152953 | 153387 | assert( pSelect!=0 ); |
| 152954 | 153388 | pSrc = pSelect->pSrc; |
| 152955 | 153389 | assert( pSrc!=0 ); |
| 152956 | 153390 | for(i=0; i<pSrc->nSrc; i++){ |
| 152957 | | - if( pSrc->a[i].pTab==pWalker->u.pTab ){ |
| 153391 | + if( pSrc->a[i].pSTab==pWalker->u.pTab ){ |
| 152958 | 153392 | testcase( pSelect->selFlags & SF_Correlated ); |
| 152959 | 153393 | pSelect->selFlags |= SF_Correlated; |
| 152960 | 153394 | pWalker->eCode = 1; |
| 152961 | 153395 | break; |
| 152962 | 153396 | } |
| | @@ -153023,11 +153457,11 @@ |
| 153023 | 153457 | memset(&sSelect, 0, sizeof(sSelect)); |
| 153024 | 153458 | memset(&sFrom, 0, sizeof(sFrom)); |
| 153025 | 153459 | sSelect.pEList = sqlite3ExprListDup(db, pReturning->pReturnEL, 0); |
| 153026 | 153460 | sSelect.pSrc = &sFrom; |
| 153027 | 153461 | sFrom.nSrc = 1; |
| 153028 | | - sFrom.a[0].pTab = pTab; |
| 153462 | + sFrom.a[0].pSTab = pTab; |
| 153029 | 153463 | sFrom.a[0].zName = pTab->zName; /* tag-20240424-1 */ |
| 153030 | 153464 | sFrom.a[0].iCursor = -1; |
| 153031 | 153465 | sqlite3SelectPrep(pParse, &sSelect, 0); |
| 153032 | 153466 | if( pParse->nErr==0 ){ |
| 153033 | 153467 | assert( db->mallocFailed==0 ); |
| | @@ -153734,11 +154168,11 @@ |
| 153734 | 154168 | ExprList *pList = 0; |
| 153735 | 154169 | ExprList *pGrp = 0; |
| 153736 | 154170 | Expr *pLimit2 = 0; |
| 153737 | 154171 | ExprList *pOrderBy2 = 0; |
| 153738 | 154172 | sqlite3 *db = pParse->db; |
| 153739 | | - Table *pTab = pTabList->a[0].pTab; |
| 154173 | + Table *pTab = pTabList->a[0].pSTab; |
| 153740 | 154174 | SrcList *pSrc; |
| 153741 | 154175 | Expr *pWhere2; |
| 153742 | 154176 | int eDest; |
| 153743 | 154177 | |
| 153744 | 154178 | #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT |
| | @@ -153758,12 +154192,12 @@ |
| 153758 | 154192 | |
| 153759 | 154193 | assert( pTabList->nSrc>1 ); |
| 153760 | 154194 | if( pSrc ){ |
| 153761 | 154195 | assert( pSrc->a[0].fg.notCte ); |
| 153762 | 154196 | pSrc->a[0].iCursor = -1; |
| 153763 | | - pSrc->a[0].pTab->nTabRef--; |
| 153764 | | - pSrc->a[0].pTab = 0; |
| 154197 | + pSrc->a[0].pSTab->nTabRef--; |
| 154198 | + pSrc->a[0].pSTab = 0; |
| 153765 | 154199 | } |
| 153766 | 154200 | if( pPk ){ |
| 153767 | 154201 | for(i=0; i<pPk->nKeyCol; i++){ |
| 153768 | 154202 | Expr *pNew = exprRowColumn(pParse, pPk->aiColumn[i]); |
| 153769 | 154203 | #ifdef SQLITE_ENABLE_UPDATE_DELETE_LIMIT |
| | @@ -155007,11 +155441,11 @@ |
| 155007 | 155441 | NameContext sNC; /* Context for resolving symbolic names */ |
| 155008 | 155442 | Expr sCol[2]; /* Index column converted into an Expr */ |
| 155009 | 155443 | int nClause = 0; /* Counter of ON CONFLICT clauses */ |
| 155010 | 155444 | |
| 155011 | 155445 | assert( pTabList->nSrc==1 ); |
| 155012 | | - assert( pTabList->a[0].pTab!=0 ); |
| 155446 | + assert( pTabList->a[0].pSTab!=0 ); |
| 155013 | 155447 | assert( pUpsert!=0 ); |
| 155014 | 155448 | assert( pUpsert->pUpsertTarget!=0 ); |
| 155015 | 155449 | |
| 155016 | 155450 | /* Resolve all symbolic names in the conflict-target clause, which |
| 155017 | 155451 | ** includes both the list of columns and the optional partial-index |
| | @@ -155026,11 +155460,11 @@ |
| 155026 | 155460 | if( rc ) return rc; |
| 155027 | 155461 | rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere); |
| 155028 | 155462 | if( rc ) return rc; |
| 155029 | 155463 | |
| 155030 | 155464 | /* Check to see if the conflict target matches the rowid. */ |
| 155031 | | - pTab = pTabList->a[0].pTab; |
| 155465 | + pTab = pTabList->a[0].pSTab; |
| 155032 | 155466 | pTarget = pUpsert->pUpsertTarget; |
| 155033 | 155467 | iCursor = pTabList->a[0].iCursor; |
| 155034 | 155468 | if( HasRowid(pTab) |
| 155035 | 155469 | && pTarget->nExpr==1 |
| 155036 | 155470 | && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN |
| | @@ -157198,10 +157632,11 @@ |
| 157198 | 157632 | } btree; |
| 157199 | 157633 | struct { /* Information for virtual tables */ |
| 157200 | 157634 | int idxNum; /* Index number */ |
| 157201 | 157635 | u32 needFree : 1; /* True if sqlite3_free(idxStr) is needed */ |
| 157202 | 157636 | u32 bOmitOffset : 1; /* True to let virtual table handle offset */ |
| 157637 | + u32 bIdxNumHex : 1; /* Show idxNum as hex in EXPLAIN QUERY PLAN */ |
| 157203 | 157638 | i8 isOrdered; /* True if satisfies ORDER BY */ |
| 157204 | 157639 | u16 omitMask; /* Terms that may be omitted */ |
| 157205 | 157640 | char *idxStr; /* Index identifier string */ |
| 157206 | 157641 | u32 mHandleIn; /* Terms to handle as IN(...) instead of == */ |
| 157207 | 157642 | } vtab; |
| | @@ -157832,11 +158267,11 @@ |
| 157832 | 158267 | Index *pIdx; |
| 157833 | 158268 | |
| 157834 | 158269 | assert( pLoop->u.btree.pIndex!=0 ); |
| 157835 | 158270 | pIdx = pLoop->u.btree.pIndex; |
| 157836 | 158271 | assert( !(flags&WHERE_AUTO_INDEX) || (flags&WHERE_IDX_ONLY) ); |
| 157837 | | - if( !HasRowid(pItem->pTab) && IsPrimaryKeyIndex(pIdx) ){ |
| 158272 | + if( !HasRowid(pItem->pSTab) && IsPrimaryKeyIndex(pIdx) ){ |
| 157838 | 158273 | if( isSearch ){ |
| 157839 | 158274 | zFmt = "PRIMARY KEY"; |
| 157840 | 158275 | } |
| 157841 | 158276 | }else if( flags & WHERE_PARTIALIDX ){ |
| 157842 | 158277 | zFmt = "AUTOMATIC PARTIAL COVERING INDEX"; |
| | @@ -157875,11 +158310,13 @@ |
| 157875 | 158310 | } |
| 157876 | 158311 | sqlite3_str_appendf(&str, "%c?)", cRangeOp); |
| 157877 | 158312 | } |
| 157878 | 158313 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 157879 | 158314 | else if( (flags & WHERE_VIRTUALTABLE)!=0 ){ |
| 157880 | | - sqlite3_str_appendf(&str, " VIRTUAL TABLE INDEX %d:%s", |
| 158315 | + sqlite3_str_appendall(&str, " VIRTUAL TABLE INDEX "); |
| 158316 | + sqlite3_str_appendf(&str, |
| 158317 | + pLoop->u.vtab.bIdxNumHex ? "0x%x:%s" : "%d:%s", |
| 157881 | 158318 | pLoop->u.vtab.idxNum, pLoop->u.vtab.idxStr); |
| 157882 | 158319 | } |
| 157883 | 158320 | #endif |
| 157884 | 158321 | if( pItem->fg.jointype & JT_LEFT ){ |
| 157885 | 158322 | sqlite3_str_appendf(&str, " LEFT-JOIN"); |
| | @@ -157929,11 +158366,11 @@ |
| 157929 | 158366 | sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); |
| 157930 | 158367 | str.printfFlags = SQLITE_PRINTF_INTERNAL; |
| 157931 | 158368 | sqlite3_str_appendf(&str, "BLOOM FILTER ON %S (", pItem); |
| 157932 | 158369 | pLoop = pLevel->pWLoop; |
| 157933 | 158370 | if( pLoop->wsFlags & WHERE_IPK ){ |
| 157934 | | - const Table *pTab = pItem->pTab; |
| 158371 | + const Table *pTab = pItem->pSTab; |
| 157935 | 158372 | if( pTab->iPKey>=0 ){ |
| 157936 | 158373 | sqlite3_str_appendf(&str, "%s=?", pTab->aCol[pTab->iPKey].zCnName); |
| 157937 | 158374 | }else{ |
| 157938 | 158375 | sqlite3_str_appendf(&str, "rowid=?"); |
| 157939 | 158376 | } |
| | @@ -157992,11 +158429,13 @@ |
| 157992 | 158429 | } |
| 157993 | 158430 | if( wsFlags & WHERE_INDEXED ){ |
| 157994 | 158431 | sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur); |
| 157995 | 158432 | } |
| 157996 | 158433 | }else{ |
| 157997 | | - int addr = pSrclist->a[pLvl->iFrom].addrFillSub; |
| 158434 | + int addr; |
| 158435 | + assert( pSrclist->a[pLvl->iFrom].fg.isSubquery ); |
| 158436 | + addr = pSrclist->a[pLvl->iFrom].u4.pSubq->addrFillSub; |
| 157998 | 158437 | VdbeOp *pOp = sqlite3VdbeGetOp(v, addr-1); |
| 157999 | 158438 | assert( sqlite3VdbeDb(v)->mallocFailed || pOp->opcode==OP_InitCoroutine ); |
| 158000 | 158439 | assert( sqlite3VdbeDb(v)->mallocFailed || pOp->p2>addr ); |
| 158001 | 158440 | sqlite3VdbeScanStatusRange(v, addrExplain, addr, pOp->p2-1); |
| 158002 | 158441 | } |
| | @@ -159129,11 +159568,12 @@ |
| 159129 | 159568 | pLoop = pLevel->pWLoop; |
| 159130 | 159569 | pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; |
| 159131 | 159570 | iCur = pTabItem->iCursor; |
| 159132 | 159571 | pLevel->notReady = notReady & ~sqlite3WhereGetMask(&pWInfo->sMaskSet, iCur); |
| 159133 | 159572 | bRev = (pWInfo->revMask>>iLevel)&1; |
| 159134 | | - VdbeModuleComment((v, "Begin WHERE-loop%d: %s",iLevel,pTabItem->pTab->zName)); |
| 159573 | + VdbeModuleComment((v, "Begin WHERE-loop%d: %s", |
| 159574 | + iLevel, pTabItem->pSTab->zName)); |
| 159135 | 159575 | #if WHERETRACE_ENABLED /* 0x4001 */ |
| 159136 | 159576 | if( sqlite3WhereTrace & 0x1 ){ |
| 159137 | 159577 | sqlite3DebugPrintf("Coding level %d of %d: notReady=%llx iFrom=%d\n", |
| 159138 | 159578 | iLevel, pWInfo->nLevel, (u64)notReady, pLevel->iFrom); |
| 159139 | 159579 | if( sqlite3WhereTrace & 0x1000 ){ |
| | @@ -159184,15 +159624,19 @@ |
| 159184 | 159624 | } |
| 159185 | 159625 | addrHalt = pWInfo->a[j].addrBrk; |
| 159186 | 159626 | |
| 159187 | 159627 | /* Special case of a FROM clause subquery implemented as a co-routine */ |
| 159188 | 159628 | if( pTabItem->fg.viaCoroutine ){ |
| 159189 | | - int regYield = pTabItem->regReturn; |
| 159190 | | - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub); |
| 159629 | + int regYield; |
| 159630 | + Subquery *pSubq; |
| 159631 | + assert( pTabItem->fg.isSubquery && pTabItem->u4.pSubq!=0 ); |
| 159632 | + pSubq = pTabItem->u4.pSubq; |
| 159633 | + regYield = pSubq->regReturn; |
| 159634 | + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); |
| 159191 | 159635 | pLevel->p2 = sqlite3VdbeAddOp2(v, OP_Yield, regYield, addrBrk); |
| 159192 | 159636 | VdbeCoverage(v); |
| 159193 | | - VdbeComment((v, "next row of %s", pTabItem->pTab->zName)); |
| 159637 | + VdbeComment((v, "next row of %s", pTabItem->pSTab->zName)); |
| 159194 | 159638 | pLevel->op = OP_Goto; |
| 159195 | 159639 | }else |
| 159196 | 159640 | |
| 159197 | 159641 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 159198 | 159642 | if( (pLoop->wsFlags & WHERE_VIRTUALTABLE)!=0 ){ |
| | @@ -159917,11 +160361,11 @@ |
| 159917 | 160361 | int iLoopBody = sqlite3VdbeMakeLabel(pParse);/* Start of loop body */ |
| 159918 | 160362 | int iRetInit; /* Address of regReturn init */ |
| 159919 | 160363 | int untestedTerms = 0; /* Some terms not completely tested */ |
| 159920 | 160364 | int ii; /* Loop counter */ |
| 159921 | 160365 | Expr *pAndExpr = 0; /* An ".. AND (...)" expression */ |
| 159922 | | - Table *pTab = pTabItem->pTab; |
| 160366 | + Table *pTab = pTabItem->pSTab; |
| 159923 | 160367 | |
| 159924 | 160368 | pTerm = pLoop->aLTerm[0]; |
| 159925 | 160369 | assert( pTerm!=0 ); |
| 159926 | 160370 | assert( pTerm->eOperator & WO_OR ); |
| 159927 | 160371 | assert( (pTerm->wtFlags & TERM_ORINFO)!=0 ); |
| | @@ -160376,11 +160820,11 @@ |
| 160376 | 160820 | /* pTab is the right-hand table of the RIGHT JOIN. Generate code that |
| 160377 | 160821 | ** will record that the current row of that table has been matched at |
| 160378 | 160822 | ** least once. This is accomplished by storing the PK for the row in |
| 160379 | 160823 | ** both the iMatch index and the regBloom Bloom filter. |
| 160380 | 160824 | */ |
| 160381 | | - pTab = pWInfo->pTabList->a[pLevel->iFrom].pTab; |
| 160825 | + pTab = pWInfo->pTabList->a[pLevel->iFrom].pSTab; |
| 160382 | 160826 | if( HasRowid(pTab) ){ |
| 160383 | 160827 | r = sqlite3GetTempRange(pParse, 2); |
| 160384 | 160828 | sqlite3ExprCodeGetColumnOfTable(v, pTab, pLevel->iTabCur, -1, r+1); |
| 160385 | 160829 | nPk = 1; |
| 160386 | 160830 | }else{ |
| | @@ -160483,23 +160927,27 @@ |
| 160483 | 160927 | SrcItem *pTabItem = &pWInfo->pTabList->a[pLevel->iFrom]; |
| 160484 | 160928 | SrcList sFrom; |
| 160485 | 160929 | Bitmask mAll = 0; |
| 160486 | 160930 | int k; |
| 160487 | 160931 | |
| 160488 | | - ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pTab->zName)); |
| 160932 | + ExplainQueryPlan((pParse, 1, "RIGHT-JOIN %s", pTabItem->pSTab->zName)); |
| 160489 | 160933 | sqlite3VdbeNoJumpsOutsideSubrtn(v, pRJ->addrSubrtn, pRJ->endSubrtn, |
| 160490 | 160934 | pRJ->regReturn); |
| 160491 | 160935 | for(k=0; k<iLevel; k++){ |
| 160492 | 160936 | int iIdxCur; |
| 160493 | 160937 | SrcItem *pRight; |
| 160494 | 160938 | assert( pWInfo->a[k].pWLoop->iTab == pWInfo->a[k].iFrom ); |
| 160495 | 160939 | pRight = &pWInfo->pTabList->a[pWInfo->a[k].iFrom]; |
| 160496 | 160940 | mAll |= pWInfo->a[k].pWLoop->maskSelf; |
| 160497 | 160941 | if( pRight->fg.viaCoroutine ){ |
| 160942 | + Subquery *pSubq; |
| 160943 | + assert( pRight->fg.isSubquery && pRight->u4.pSubq!=0 ); |
| 160944 | + pSubq = pRight->u4.pSubq; |
| 160945 | + assert( pSubq->pSelect!=0 && pSubq->pSelect->pEList!=0 ); |
| 160498 | 160946 | sqlite3VdbeAddOp3( |
| 160499 | | - v, OP_Null, 0, pRight->regResult, |
| 160500 | | - pRight->regResult + pRight->pSelect->pEList->nExpr-1 |
| 160947 | + v, OP_Null, 0, pSubq->regResult, |
| 160948 | + pSubq->regResult + pSubq->pSelect->pEList->nExpr-1 |
| 160501 | 160949 | ); |
| 160502 | 160950 | } |
| 160503 | 160951 | sqlite3VdbeAddOp1(v, OP_NullRow, pWInfo->a[k].iTabCur); |
| 160504 | 160952 | iIdxCur = pWInfo->a[k].iIdxCur; |
| 160505 | 160953 | if( iIdxCur ){ |
| | @@ -160533,11 +160981,11 @@ |
| 160533 | 160981 | int iCur = pLevel->iTabCur; |
| 160534 | 160982 | int r = ++pParse->nMem; |
| 160535 | 160983 | int nPk; |
| 160536 | 160984 | int jmp; |
| 160537 | 160985 | int addrCont = sqlite3WhereContinueLabel(pSubWInfo); |
| 160538 | | - Table *pTab = pTabItem->pTab; |
| 160986 | + Table *pTab = pTabItem->pSTab; |
| 160539 | 160987 | if( HasRowid(pTab) ){ |
| 160540 | 160988 | sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, -1, r); |
| 160541 | 160989 | nPk = 1; |
| 160542 | 160990 | }else{ |
| 160543 | 160991 | int iPk; |
| | @@ -160785,15 +161233,24 @@ |
| 160785 | 161233 | assert( !ExprHasProperty(pRight, EP_IntValue) ); |
| 160786 | 161234 | z = (u8*)pRight->u.zToken; |
| 160787 | 161235 | } |
| 160788 | 161236 | if( z ){ |
| 160789 | 161237 | |
| 160790 | | - /* Count the number of prefix characters prior to the first wildcard */ |
| 161238 | + /* Count the number of prefix characters prior to the first wildcard. |
| 161239 | + ** If the underlying database has a UTF16LE encoding, then only consider |
| 161240 | + ** ASCII characters. Note that the encoding of z[] is UTF8 - we are |
| 161241 | + ** dealing with only UTF8 here in this code, but the database engine |
| 161242 | + ** itself might be processing content using a different encoding. */ |
| 160791 | 161243 | cnt = 0; |
| 160792 | 161244 | while( (c=z[cnt])!=0 && c!=wc[0] && c!=wc[1] && c!=wc[2] ){ |
| 160793 | 161245 | cnt++; |
| 160794 | | - if( c==wc[3] && z[cnt]!=0 ) cnt++; |
| 161246 | + if( c==wc[3] && z[cnt]!=0 ){ |
| 161247 | + cnt++; |
| 161248 | + }else if( c>=0x80 && ENC(db)==SQLITE_UTF16LE ){ |
| 161249 | + cnt--; |
| 161250 | + break; |
| 161251 | + } |
| 160795 | 161252 | } |
| 160796 | 161253 | |
| 160797 | 161254 | /* The optimization is possible only if (1) the pattern does not begin |
| 160798 | 161255 | ** with a wildcard and if (2) the non-wildcard prefix does not end with |
| 160799 | 161256 | ** an (illegal 0xff) character, or (3) the pattern does not consist of |
| | @@ -160804,11 +161261,11 @@ |
| 160804 | 161261 | ** removed. */ |
| 160805 | 161262 | if( (cnt>1 || (cnt>0 && z[0]!=wc[3])) && 255!=(u8)z[cnt-1] ){ |
| 160806 | 161263 | Expr *pPrefix; |
| 160807 | 161264 | |
| 160808 | 161265 | /* A "complete" match if the pattern ends with "*" or "%" */ |
| 160809 | | - *pisComplete = c==wc[0] && z[cnt+1]==0; |
| 161266 | + *pisComplete = c==wc[0] && z[cnt+1]==0 && ENC(db)!=SQLITE_UTF16LE; |
| 160810 | 161267 | |
| 160811 | 161268 | /* Get the pattern prefix. Remove all escapes from the prefix. */ |
| 160812 | 161269 | pPrefix = sqlite3Expr(db, TK_STRING, (char*)z); |
| 160813 | 161270 | if( pPrefix ){ |
| 160814 | 161271 | int iFrom, iTo; |
| | @@ -161523,11 +161980,13 @@ |
| 161523 | 161980 | mask |= sqlite3WhereExprUsage(pMaskSet, pS->pWhere); |
| 161524 | 161981 | mask |= sqlite3WhereExprUsage(pMaskSet, pS->pHaving); |
| 161525 | 161982 | if( ALWAYS(pSrc!=0) ){ |
| 161526 | 161983 | int i; |
| 161527 | 161984 | for(i=0; i<pSrc->nSrc; i++){ |
| 161528 | | - mask |= exprSelectUsage(pMaskSet, pSrc->a[i].pSelect); |
| 161985 | + if( pSrc->a[i].fg.isSubquery ){ |
| 161986 | + mask |= exprSelectUsage(pMaskSet, pSrc->a[i].u4.pSubq->pSelect); |
| 161987 | + } |
| 161529 | 161988 | if( pSrc->a[i].fg.isUsing==0 ){ |
| 161530 | 161989 | mask |= sqlite3WhereExprUsage(pMaskSet, pSrc->a[i].u3.pOn); |
| 161531 | 161990 | } |
| 161532 | 161991 | if( pSrc->a[i].fg.isTabFunc ){ |
| 161533 | 161992 | mask |= sqlite3WhereExprListUsage(pMaskSet, pSrc->a[i].u1.pFuncArg); |
| | @@ -161561,11 +162020,11 @@ |
| 161561 | 162020 | Index *pIdx; |
| 161562 | 162021 | int i; |
| 161563 | 162022 | int iCur; |
| 161564 | 162023 | do{ |
| 161565 | 162024 | iCur = pFrom->a[j].iCursor; |
| 161566 | | - for(pIdx=pFrom->a[j].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 162025 | + for(pIdx=pFrom->a[j].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 161567 | 162026 | if( pIdx->aColExpr==0 ) continue; |
| 161568 | 162027 | for(i=0; i<pIdx->nKeyCol; i++){ |
| 161569 | 162028 | if( pIdx->aiColumn[i]!=XN_EXPR ) continue; |
| 161570 | 162029 | assert( pIdx->bHasExpr ); |
| 161571 | 162030 | if( sqlite3ExprCompareSkip(pExpr,pIdx->aColExpr->a[i].pExpr,iCur)==0 |
| | @@ -161605,11 +162064,11 @@ |
| 161605 | 162064 | return 1; |
| 161606 | 162065 | } |
| 161607 | 162066 | |
| 161608 | 162067 | for(i=0; i<pFrom->nSrc; i++){ |
| 161609 | 162068 | Index *pIdx; |
| 161610 | | - for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 162069 | + for(pIdx=pFrom->a[i].pSTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 161611 | 162070 | if( pIdx->aColExpr ){ |
| 161612 | 162071 | return exprMightBeIndexed2(pFrom,aiCurCol,pExpr,i); |
| 161613 | 162072 | } |
| 161614 | 162073 | } |
| 161615 | 162074 | } |
| | @@ -162193,11 +162652,11 @@ |
| 162193 | 162652 | */ |
| 162194 | 162653 | SQLITE_PRIVATE void SQLITE_NOINLINE sqlite3WhereAddLimit(WhereClause *pWC, Select *p){ |
| 162195 | 162654 | assert( p!=0 && p->pLimit!=0 ); /* 1 -- checked by caller */ |
| 162196 | 162655 | if( p->pGroupBy==0 |
| 162197 | 162656 | && (p->selFlags & (SF_Distinct|SF_Aggregate))==0 /* 2 */ |
| 162198 | | - && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pTab)) /* 3 */ |
| 162657 | + && (p->pSrc->nSrc==1 && IsVirtual(p->pSrc->a[0].pSTab)) /* 3 */ |
| 162199 | 162658 | ){ |
| 162200 | 162659 | ExprList *pOrderBy = p->pOrderBy; |
| 162201 | 162660 | int iCsr = p->pSrc->a[0].iCursor; |
| 162202 | 162661 | int ii; |
| 162203 | 162662 | |
| | @@ -162414,11 +162873,11 @@ |
| 162414 | 162873 | int j, k; |
| 162415 | 162874 | ExprList *pArgs; |
| 162416 | 162875 | Expr *pColRef; |
| 162417 | 162876 | Expr *pTerm; |
| 162418 | 162877 | if( pItem->fg.isTabFunc==0 ) return; |
| 162419 | | - pTab = pItem->pTab; |
| 162878 | + pTab = pItem->pSTab; |
| 162420 | 162879 | assert( pTab!=0 ); |
| 162421 | 162880 | pArgs = pItem->u1.pFuncArg; |
| 162422 | 162881 | if( pArgs==0 ) return; |
| 162423 | 162882 | for(j=k=0; j<pArgs->nExpr; j++){ |
| 162424 | 162883 | Expr *pRhs; |
| | @@ -163098,11 +163557,11 @@ |
| 163098 | 163557 | /* If there is more than one table or sub-select in the FROM clause of |
| 163099 | 163558 | ** this query, then it will not be possible to show that the DISTINCT |
| 163100 | 163559 | ** clause is redundant. */ |
| 163101 | 163560 | if( pTabList->nSrc!=1 ) return 0; |
| 163102 | 163561 | iBase = pTabList->a[0].iCursor; |
| 163103 | | - pTab = pTabList->a[0].pTab; |
| 163562 | + pTab = pTabList->a[0].pSTab; |
| 163104 | 163563 | |
| 163105 | 163564 | /* If any of the expressions is an IPK column on table iBase, then return |
| 163106 | 163565 | ** true. Note: The (p->iTable==iBase) part of this test may be false if the |
| 163107 | 163566 | ** current SELECT is a correlated sub-query. |
| 163108 | 163567 | */ |
| | @@ -163362,14 +163821,14 @@ |
| 163362 | 163821 | } |
| 163363 | 163822 | if( (pTerm->prereqRight & notReady)!=0 ) return 0; |
| 163364 | 163823 | assert( (pTerm->eOperator & (WO_OR|WO_AND))==0 ); |
| 163365 | 163824 | leftCol = pTerm->u.x.leftColumn; |
| 163366 | 163825 | if( leftCol<0 ) return 0; |
| 163367 | | - aff = pSrc->pTab->aCol[leftCol].affinity; |
| 163826 | + aff = pSrc->pSTab->aCol[leftCol].affinity; |
| 163368 | 163827 | if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; |
| 163369 | 163828 | testcase( pTerm->pExpr->op==TK_IS ); |
| 163370 | | - return columnIsGoodIndexCandidate(pSrc->pTab, leftCol); |
| 163829 | + return columnIsGoodIndexCandidate(pSrc->pSTab, leftCol); |
| 163371 | 163830 | } |
| 163372 | 163831 | #endif |
| 163373 | 163832 | |
| 163374 | 163833 | |
| 163375 | 163834 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX |
| | @@ -163473,11 +163932,11 @@ |
| 163473 | 163932 | /* Count the number of columns that will be added to the index |
| 163474 | 163933 | ** and used to match WHERE clause constraints */ |
| 163475 | 163934 | nKeyCol = 0; |
| 163476 | 163935 | pTabList = pWC->pWInfo->pTabList; |
| 163477 | 163936 | pSrc = &pTabList->a[pLevel->iFrom]; |
| 163478 | | - pTable = pSrc->pTab; |
| 163937 | + pTable = pSrc->pSTab; |
| 163479 | 163938 | pWCEnd = &pWC->a[pWC->nTerm]; |
| 163480 | 163939 | pLoop = pLevel->pWLoop; |
| 163481 | 163940 | idxCols = 0; |
| 163482 | 163941 | for(pTerm=pWC->a; pTerm<pWCEnd; pTerm++){ |
| 163483 | 163942 | Expr *pExpr = pTerm->pExpr; |
| | @@ -163615,16 +164074,21 @@ |
| 163615 | 164074 | } |
| 163616 | 164075 | |
| 163617 | 164076 | /* Fill the automatic index with content */ |
| 163618 | 164077 | assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] ); |
| 163619 | 164078 | if( pSrc->fg.viaCoroutine ){ |
| 163620 | | - int regYield = pSrc->regReturn; |
| 164079 | + int regYield; |
| 164080 | + Subquery *pSubq; |
| 164081 | + assert( pSrc->fg.isSubquery ); |
| 164082 | + pSubq = pSrc->u4.pSubq; |
| 164083 | + assert( pSubq!=0 ); |
| 164084 | + regYield = pSubq->regReturn; |
| 163621 | 164085 | addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0); |
| 163622 | | - sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub); |
| 164086 | + sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSubq->addrFillSub); |
| 163623 | 164087 | addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield); |
| 163624 | 164088 | VdbeCoverage(v); |
| 163625 | | - VdbeComment((v, "next row of %s", pSrc->pTab->zName)); |
| 164089 | + VdbeComment((v, "next row of %s", pSrc->pSTab->zName)); |
| 163626 | 164090 | }else{ |
| 163627 | 164091 | addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v); |
| 163628 | 164092 | } |
| 163629 | 164093 | if( pPartial ){ |
| 163630 | 164094 | iContinue = sqlite3VdbeMakeLabel(pParse); |
| | @@ -163642,15 +164106,16 @@ |
| 163642 | 164106 | sqlite3VdbeScanStatusCounters(v, addrExp, addrExp, sqlite3VdbeCurrentAddr(v)); |
| 163643 | 164107 | sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord); |
| 163644 | 164108 | sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT); |
| 163645 | 164109 | if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue); |
| 163646 | 164110 | if( pSrc->fg.viaCoroutine ){ |
| 164111 | + assert( pSrc->fg.isSubquery && pSrc->u4.pSubq!=0 ); |
| 163647 | 164112 | sqlite3VdbeChangeP2(v, addrCounter, regBase+n); |
| 163648 | 164113 | testcase( pParse->db->mallocFailed ); |
| 163649 | 164114 | assert( pLevel->iIdxCur>0 ); |
| 163650 | 164115 | translateColumnToCopy(pParse, addrTop, pLevel->iTabCur, |
| 163651 | | - pSrc->regResult, pLevel->iIdxCur); |
| 164116 | + pSrc->u4.pSubq->regResult, pLevel->iIdxCur); |
| 163652 | 164117 | sqlite3VdbeGoto(v, addrTop); |
| 163653 | 164118 | pSrc->fg.viaCoroutine = 0; |
| 163654 | 164119 | }else{ |
| 163655 | 164120 | sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v); |
| 163656 | 164121 | sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX); |
| | @@ -163737,11 +164202,11 @@ |
| 163737 | 164202 | */ |
| 163738 | 164203 | pTabList = pWInfo->pTabList; |
| 163739 | 164204 | iSrc = pLevel->iFrom; |
| 163740 | 164205 | pItem = &pTabList->a[iSrc]; |
| 163741 | 164206 | assert( pItem!=0 ); |
| 163742 | | - pTab = pItem->pTab; |
| 164207 | + pTab = pItem->pSTab; |
| 163743 | 164208 | assert( pTab!=0 ); |
| 163744 | 164209 | sz = sqlite3LogEstToInt(pTab->nRowLogEst); |
| 163745 | 164210 | if( sz<10000 ){ |
| 163746 | 164211 | sz = 10000; |
| 163747 | 164212 | }else if( sz>10000000 ){ |
| | @@ -163768,11 +164233,11 @@ |
| 163768 | 164233 | Index *pIdx = pLoop->u.btree.pIndex; |
| 163769 | 164234 | int n = pLoop->u.btree.nEq; |
| 163770 | 164235 | int r1 = sqlite3GetTempRange(pParse, n); |
| 163771 | 164236 | int jj; |
| 163772 | 164237 | for(jj=0; jj<n; jj++){ |
| 163773 | | - assert( pIdx->pTable==pItem->pTab ); |
| 164238 | + assert( pIdx->pTable==pItem->pSTab ); |
| 163774 | 164239 | sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj); |
| 163775 | 164240 | } |
| 163776 | 164241 | sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n); |
| 163777 | 164242 | sqlite3ReleaseTempRange(pParse, r1, n); |
| 163778 | 164243 | } |
| | @@ -163849,11 +164314,11 @@ |
| 163849 | 164314 | int eDistinct = 0; |
| 163850 | 164315 | ExprList *pOrderBy = pWInfo->pOrderBy; |
| 163851 | 164316 | WhereClause *p; |
| 163852 | 164317 | |
| 163853 | 164318 | assert( pSrc!=0 ); |
| 163854 | | - pTab = pSrc->pTab; |
| 164319 | + pTab = pSrc->pSTab; |
| 163855 | 164320 | assert( pTab!=0 ); |
| 163856 | 164321 | assert( IsVirtual(pTab) ); |
| 163857 | 164322 | |
| 163858 | 164323 | /* Find all WHERE clause constraints referring to this virtual table. |
| 163859 | 164324 | ** Mark each term with the TERM_OK flag. Set nTerm to the number of |
| | @@ -164857,11 +165322,11 @@ |
| 164857 | 165322 | SQLITE_PRIVATE void sqlite3WhereLoopPrint(const WhereLoop *p, const WhereClause *pWC){ |
| 164858 | 165323 | if( pWC ){ |
| 164859 | 165324 | WhereInfo *pWInfo = pWC->pWInfo; |
| 164860 | 165325 | int nb = 1+(pWInfo->pTabList->nSrc+3)/4; |
| 164861 | 165326 | SrcItem *pItem = pWInfo->pTabList->a + p->iTab; |
| 164862 | | - Table *pTab = pItem->pTab; |
| 165327 | + Table *pTab = pItem->pSTab; |
| 164863 | 165328 | Bitmask mAll = (((Bitmask)1)<<(nb*4)) - 1; |
| 164864 | 165329 | sqlite3DebugPrintf("%c%2d.%0*llx.%0*llx", p->cId, |
| 164865 | 165330 | p->iTab, nb, p->maskSelf, nb, p->prereq & mAll); |
| 164866 | 165331 | sqlite3DebugPrintf(" %12s", |
| 164867 | 165332 | pItem->zAlias ? pItem->zAlias : pTab->zName); |
| | @@ -165845,19 +166310,19 @@ |
| 165845 | 166310 | ** 1. The cost of doing one search-by-key to find the first matching |
| 165846 | 166311 | ** entry |
| 165847 | 166312 | ** 2. Stepping forward in the index pNew->nOut times to find all |
| 165848 | 166313 | ** additional matching entries. |
| 165849 | 166314 | */ |
| 165850 | | - assert( pSrc->pTab->szTabRow>0 ); |
| 166315 | + assert( pSrc->pSTab->szTabRow>0 ); |
| 165851 | 166316 | if( pProbe->idxType==SQLITE_IDXTYPE_IPK ){ |
| 165852 | 166317 | /* The pProbe->szIdxRow is low for an IPK table since the interior |
| 165853 | 166318 | ** pages are small. Thus szIdxRow gives a good estimate of seek cost. |
| 165854 | 166319 | ** But the leaf pages are full-size, so pProbe->szIdxRow would badly |
| 165855 | 166320 | ** under-estimate the scanning cost. */ |
| 165856 | 166321 | rCostIdx = pNew->nOut + 16; |
| 165857 | 166322 | }else{ |
| 165858 | | - rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pTab->szTabRow; |
| 166323 | + rCostIdx = pNew->nOut + 1 + (15*pProbe->szIdxRow)/pSrc->pSTab->szTabRow; |
| 165859 | 166324 | } |
| 165860 | 166325 | rCostIdx = sqlite3LogEstAdd(rLogSize, rCostIdx); |
| 165861 | 166326 | |
| 165862 | 166327 | /* Estimate the cost of running the loop. If all data is coming |
| 165863 | 166328 | ** from the index, then this is just the cost of doing the index |
| | @@ -166318,13 +166783,13 @@ |
| 166318 | 166783 | |
| 166319 | 166784 | pNew = pBuilder->pNew; |
| 166320 | 166785 | pWInfo = pBuilder->pWInfo; |
| 166321 | 166786 | pTabList = pWInfo->pTabList; |
| 166322 | 166787 | pSrc = pTabList->a + pNew->iTab; |
| 166323 | | - pTab = pSrc->pTab; |
| 166788 | + pTab = pSrc->pSTab; |
| 166324 | 166789 | pWC = pBuilder->pWC; |
| 166325 | | - assert( !IsVirtual(pSrc->pTab) ); |
| 166790 | + assert( !IsVirtual(pSrc->pSTab) ); |
| 166326 | 166791 | |
| 166327 | 166792 | if( pSrc->fg.isIndexedBy ){ |
| 166328 | 166793 | assert( pSrc->fg.isCte==0 ); |
| 166329 | 166794 | /* An INDEXED BY clause specifies a particular index to use */ |
| 166330 | 166795 | pProbe = pSrc->u2.pIBIndex; |
| | @@ -166345,11 +166810,11 @@ |
| 166345 | 166810 | sPk.pTable = pTab; |
| 166346 | 166811 | sPk.szIdxRow = 3; /* TUNING: Interior rows of IPK table are very small */ |
| 166347 | 166812 | sPk.idxType = SQLITE_IDXTYPE_IPK; |
| 166348 | 166813 | aiRowEstPk[0] = pTab->nRowLogEst; |
| 166349 | 166814 | aiRowEstPk[1] = 0; |
| 166350 | | - pFirst = pSrc->pTab->pIndex; |
| 166815 | + pFirst = pSrc->pSTab->pIndex; |
| 166351 | 166816 | if( pSrc->fg.notIndexed==0 ){ |
| 166352 | 166817 | /* The real indices of the table are only considered if the |
| 166353 | 166818 | ** NOT INDEXED qualifier is omitted from the FROM clause */ |
| 166354 | 166819 | sPk.pNext = pFirst; |
| 166355 | 166820 | } |
| | @@ -166464,13 +166929,13 @@ |
| 166464 | 166929 | #else |
| 166465 | 166930 | pNew->rRun = rSize + 16; |
| 166466 | 166931 | #endif |
| 166467 | 166932 | ApplyCostMultiplier(pNew->rRun, pTab->costMult); |
| 166468 | 166933 | whereLoopOutputAdjust(pWC, pNew, rSize); |
| 166469 | | - if( pSrc->pSelect ){ |
| 166934 | + if( pSrc->fg.isSubquery ){ |
| 166470 | 166935 | if( pSrc->fg.viaCoroutine ) pNew->wsFlags |= WHERE_COROUTINE; |
| 166471 | | - pNew->u.btree.pOrderBy = pSrc->pSelect->pOrderBy; |
| 166936 | + pNew->u.btree.pOrderBy = pSrc->u4.pSubq->pSelect->pOrderBy; |
| 166472 | 166937 | } |
| 166473 | 166938 | rc = whereLoopInsert(pBuilder, pNew); |
| 166474 | 166939 | pNew->nOut = rSize; |
| 166475 | 166940 | if( rc ) break; |
| 166476 | 166941 | }else{ |
| | @@ -166692,11 +167157,11 @@ |
| 166692 | 167157 | pIdxInfo->estimatedRows = 25; |
| 166693 | 167158 | pIdxInfo->idxFlags = 0; |
| 166694 | 167159 | pHidden->mHandleIn = 0; |
| 166695 | 167160 | |
| 166696 | 167161 | /* Invoke the virtual table xBestIndex() method */ |
| 166697 | | - rc = vtabBestIndex(pParse, pSrc->pTab, pIdxInfo); |
| 167162 | + rc = vtabBestIndex(pParse, pSrc->pSTab, pIdxInfo); |
| 166698 | 167163 | if( rc ){ |
| 166699 | 167164 | if( rc==SQLITE_CONSTRAINT ){ |
| 166700 | 167165 | /* If the xBestIndex method returns SQLITE_CONSTRAINT, that means |
| 166701 | 167166 | ** that the particular combination of parameters provided is unusable. |
| 166702 | 167167 | ** Make no entries in the loop table. |
| | @@ -166722,11 +167187,11 @@ |
| 166722 | 167187 | || j<0 |
| 166723 | 167188 | || (pTerm = termFromWhereClause(pWC, j))==0 |
| 166724 | 167189 | || pNew->aLTerm[iTerm]!=0 |
| 166725 | 167190 | || pIdxCons->usable==0 |
| 166726 | 167191 | ){ |
| 166727 | | - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); |
| 167192 | + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); |
| 166728 | 167193 | freeIdxStr(pIdxInfo); |
| 166729 | 167194 | return SQLITE_ERROR; |
| 166730 | 167195 | } |
| 166731 | 167196 | testcase( iTerm==nConstraint-1 ); |
| 166732 | 167197 | testcase( j==0 ); |
| | @@ -166785,11 +167250,11 @@ |
| 166785 | 167250 | pNew->nLTerm = mxTerm+1; |
| 166786 | 167251 | for(i=0; i<=mxTerm; i++){ |
| 166787 | 167252 | if( pNew->aLTerm[i]==0 ){ |
| 166788 | 167253 | /* The non-zero argvIdx values must be contiguous. Raise an |
| 166789 | 167254 | ** error if they are not */ |
| 166790 | | - sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pTab->zName); |
| 167255 | + sqlite3ErrorMsg(pParse,"%s.xBestIndex malfunction",pSrc->pSTab->zName); |
| 166791 | 167256 | freeIdxStr(pIdxInfo); |
| 166792 | 167257 | return SQLITE_ERROR; |
| 166793 | 167258 | } |
| 166794 | 167259 | } |
| 166795 | 167260 | assert( pNew->nLTerm<=pNew->nLSlot ); |
| | @@ -166797,10 +167262,11 @@ |
| 166797 | 167262 | pNew->u.vtab.needFree = pIdxInfo->needToFreeIdxStr; |
| 166798 | 167263 | pIdxInfo->needToFreeIdxStr = 0; |
| 166799 | 167264 | pNew->u.vtab.idxStr = pIdxInfo->idxStr; |
| 166800 | 167265 | pNew->u.vtab.isOrdered = (i8)(pIdxInfo->orderByConsumed ? |
| 166801 | 167266 | pIdxInfo->nOrderBy : 0); |
| 167267 | + pNew->u.vtab.bIdxNumHex = (pIdxInfo->idxFlags&SQLITE_INDEX_SCAN_HEX)!=0; |
| 166802 | 167268 | pNew->rSetup = 0; |
| 166803 | 167269 | pNew->rRun = sqlite3LogEstFromDouble(pIdxInfo->estimatedCost); |
| 166804 | 167270 | pNew->nOut = sqlite3LogEst(pIdxInfo->estimatedRows); |
| 166805 | 167271 | |
| 166806 | 167272 | /* Set the WHERE_ONEROW flag if the xBestIndex() method indicated |
| | @@ -166987,11 +167453,11 @@ |
| 166987 | 167453 | pWInfo = pBuilder->pWInfo; |
| 166988 | 167454 | pParse = pWInfo->pParse; |
| 166989 | 167455 | pWC = pBuilder->pWC; |
| 166990 | 167456 | pNew = pBuilder->pNew; |
| 166991 | 167457 | pSrc = &pWInfo->pTabList->a[pNew->iTab]; |
| 166992 | | - assert( IsVirtual(pSrc->pTab) ); |
| 167458 | + assert( IsVirtual(pSrc->pSTab) ); |
| 166993 | 167459 | p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); |
| 166994 | 167460 | if( p==0 ) return SQLITE_NOMEM_BKPT; |
| 166995 | 167461 | pNew->rSetup = 0; |
| 166996 | 167462 | pNew->wsFlags = WHERE_VIRTUALTABLE; |
| 166997 | 167463 | pNew->nLTerm = 0; |
| | @@ -167001,11 +167467,11 @@ |
| 167001 | 167467 | freeIndexInfo(pParse->db, p); |
| 167002 | 167468 | return SQLITE_NOMEM_BKPT; |
| 167003 | 167469 | } |
| 167004 | 167470 | |
| 167005 | 167471 | /* First call xBestIndex() with all constraints usable. */ |
| 167006 | | - WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pTab->zName)); |
| 167472 | + WHERETRACE(0x800, ("BEGIN %s.addVirtual()\n", pSrc->pSTab->zName)); |
| 167007 | 167473 | WHERETRACE(0x800, (" VirtualOne: all usable\n")); |
| 167008 | 167474 | rc = whereLoopAddVirtualOne( |
| 167009 | 167475 | pBuilder, mPrereq, ALLBITS, 0, p, mNoOmit, &bIn, &bRetry |
| 167010 | 167476 | ); |
| 167011 | 167477 | if( bRetry ){ |
| | @@ -167083,11 +167549,11 @@ |
| 167083 | 167549 | pBuilder, mPrereq, mPrereq, WO_IN, p, mNoOmit, &bIn, 0); |
| 167084 | 167550 | } |
| 167085 | 167551 | } |
| 167086 | 167552 | |
| 167087 | 167553 | freeIndexInfo(pParse->db, p); |
| 167088 | | - WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); |
| 167554 | + WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pSTab->zName, rc)); |
| 167089 | 167555 | return rc; |
| 167090 | 167556 | } |
| 167091 | 167557 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 167092 | 167558 | |
| 167093 | 167559 | /* |
| | @@ -167155,11 +167621,11 @@ |
| 167155 | 167621 | if( sqlite3WhereTrace & 0x20000 ){ |
| 167156 | 167622 | sqlite3WhereClausePrint(sSubBuild.pWC); |
| 167157 | 167623 | } |
| 167158 | 167624 | #endif |
| 167159 | 167625 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 167160 | | - if( IsVirtual(pItem->pTab) ){ |
| 167626 | + if( IsVirtual(pItem->pSTab) ){ |
| 167161 | 167627 | rc = whereLoopAddVirtual(&sSubBuild, mPrereq, mUnusable); |
| 167162 | 167628 | }else |
| 167163 | 167629 | #endif |
| 167164 | 167630 | { |
| 167165 | 167631 | rc = whereLoopAddBtree(&sSubBuild, mPrereq); |
| | @@ -167269,11 +167735,11 @@ |
| 167269 | 167735 | bFirstPastRJ = (pItem->fg.jointype & JT_RIGHT)!=0; |
| 167270 | 167736 | }else if( !hasRightJoin ){ |
| 167271 | 167737 | mPrereq = 0; |
| 167272 | 167738 | } |
| 167273 | 167739 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 167274 | | - if( IsVirtual(pItem->pTab) ){ |
| 167740 | + if( IsVirtual(pItem->pSTab) ){ |
| 167275 | 167741 | SrcItem *p; |
| 167276 | 167742 | for(p=&pItem[1]; p<pEnd; p++){ |
| 167277 | 167743 | if( mUnusable || (p->fg.jointype & (JT_OUTER|JT_CROSS)) ){ |
| 167278 | 167744 | mUnusable |= sqlite3WhereGetMask(&pWInfo->sMaskSet, p->iCursor); |
| 167279 | 167745 | } |
| | @@ -167905,11 +168371,11 @@ |
| 167905 | 168371 | rDelta = 15*(nDep-3); |
| 167906 | 168372 | #ifdef WHERETRACE_ENABLED /* 0x4 */ |
| 167907 | 168373 | if( sqlite3WhereTrace&0x4 ){ |
| 167908 | 168374 | SrcItem *pItem = pWInfo->pTabList->a + iLoop; |
| 167909 | 168375 | sqlite3DebugPrintf("Fact-table %s: %d dimensions, cost reduced %d\n", |
| 167910 | | - pItem->zAlias ? pItem->zAlias : pItem->pTab->zName, |
| 168376 | + pItem->zAlias ? pItem->zAlias : pItem->pSTab->zName, |
| 167911 | 168377 | nDep, rDelta); |
| 167912 | 168378 | } |
| 167913 | 168379 | #endif |
| 167914 | 168380 | if( pWInfo->nOutStarDelta==0 ){ |
| 167915 | 168381 | for(pWLoop=pWInfo->pLoops; pWLoop; pWLoop=pWLoop->pNextLoop){ |
| | @@ -168455,11 +168921,11 @@ |
| 168455 | 168921 | |
| 168456 | 168922 | pWInfo = pBuilder->pWInfo; |
| 168457 | 168923 | if( pWInfo->wctrlFlags & WHERE_OR_SUBCLAUSE ) return 0; |
| 168458 | 168924 | assert( pWInfo->pTabList->nSrc>=1 ); |
| 168459 | 168925 | pItem = pWInfo->pTabList->a; |
| 168460 | | - pTab = pItem->pTab; |
| 168926 | + pTab = pItem->pSTab; |
| 168461 | 168927 | if( IsVirtual(pTab) ) return 0; |
| 168462 | 168928 | if( pItem->fg.isIndexedBy || pItem->fg.notIndexed ){ |
| 168463 | 168929 | testcase( pItem->fg.isIndexedBy ); |
| 168464 | 168930 | testcase( pItem->fg.notIndexed ); |
| 168465 | 168931 | return 0; |
| | @@ -168718,11 +169184,11 @@ |
| 168718 | 169184 | assert( OptimizationEnabled(pWInfo->pParse->db, SQLITE_BloomFilter) ); |
| 168719 | 169185 | for(i=0; i<pWInfo->nLevel; i++){ |
| 168720 | 169186 | WhereLoop *pLoop = pWInfo->a[i].pWLoop; |
| 168721 | 169187 | const unsigned int reqFlags = (WHERE_SELFCULL|WHERE_COLUMN_EQ); |
| 168722 | 169188 | SrcItem *pItem = &pWInfo->pTabList->a[pLoop->iTab]; |
| 168723 | | - Table *pTab = pItem->pTab; |
| 169189 | + Table *pTab = pItem->pSTab; |
| 168724 | 169190 | if( (pTab->tabFlags & TF_HasStat1)==0 ) break; |
| 168725 | 169191 | pTab->tabFlags |= TF_MaybeReanalyze; |
| 168726 | 169192 | if( i>=1 |
| 168727 | 169193 | && (pLoop->wsFlags & reqFlags)==reqFlags |
| 168728 | 169194 | /* vvvvvv--- Always the case if WHERE_COLUMN_EQ is defined */ |
| | @@ -168875,12 +169341,12 @@ |
| 168875 | 169341 | int ii; |
| 168876 | 169342 | for(ii=0; ii<pWInfo->pTabList->nSrc; ii++){ |
| 168877 | 169343 | SrcItem *pItem = &pWInfo->pTabList->a[ii]; |
| 168878 | 169344 | if( !pItem->fg.isCte |
| 168879 | 169345 | || pItem->u2.pCteUse->eM10d!=M10d_Yes |
| 168880 | | - || NEVER(pItem->pSelect==0) |
| 168881 | | - || pItem->pSelect->pOrderBy==0 |
| 169346 | + || NEVER(pItem->fg.isSubquery==0) |
| 169347 | + || pItem->u4.pSubq->pSelect->pOrderBy==0 |
| 168882 | 169348 | ){ |
| 168883 | 169349 | pWInfo->revMask |= MASKBIT(ii); |
| 168884 | 169350 | } |
| 168885 | 169351 | } |
| 168886 | 169352 | } |
| | @@ -169366,19 +169832,19 @@ |
| 169366 | 169832 | */ |
| 169367 | 169833 | assert( (wctrlFlags & WHERE_ONEPASS_DESIRED)==0 || pWInfo->nLevel==1 ); |
| 169368 | 169834 | if( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 ){ |
| 169369 | 169835 | int wsFlags = pWInfo->a[0].pWLoop->wsFlags; |
| 169370 | 169836 | int bOnerow = (wsFlags & WHERE_ONEROW)!=0; |
| 169371 | | - assert( !(wsFlags & WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pTab) ); |
| 169837 | + assert( !(wsFlags&WHERE_VIRTUALTABLE) || IsVirtual(pTabList->a[0].pSTab) ); |
| 169372 | 169838 | if( bOnerow || ( |
| 169373 | 169839 | 0!=(wctrlFlags & WHERE_ONEPASS_MULTIROW) |
| 169374 | | - && !IsVirtual(pTabList->a[0].pTab) |
| 169840 | + && !IsVirtual(pTabList->a[0].pSTab) |
| 169375 | 169841 | && (0==(wsFlags & WHERE_MULTI_OR) || (wctrlFlags & WHERE_DUPLICATES_OK)) |
| 169376 | 169842 | && OptimizationEnabled(db, SQLITE_OnePass) |
| 169377 | 169843 | )){ |
| 169378 | 169844 | pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; |
| 169379 | | - if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ |
| 169845 | + if( HasRowid(pTabList->a[0].pSTab) && (wsFlags & WHERE_IDX_ONLY) ){ |
| 169380 | 169846 | if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ |
| 169381 | 169847 | bFordelete = OPFLAG_FORDELETE; |
| 169382 | 169848 | } |
| 169383 | 169849 | pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY); |
| 169384 | 169850 | } |
| | @@ -169392,11 +169858,11 @@ |
| 169392 | 169858 | Table *pTab; /* Table to open */ |
| 169393 | 169859 | int iDb; /* Index of database containing table/index */ |
| 169394 | 169860 | SrcItem *pTabItem; |
| 169395 | 169861 | |
| 169396 | 169862 | pTabItem = &pTabList->a[pLevel->iFrom]; |
| 169397 | | - pTab = pTabItem->pTab; |
| 169863 | + pTab = pTabItem->pSTab; |
| 169398 | 169864 | iDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| 169399 | 169865 | pLoop = pLevel->pWLoop; |
| 169400 | 169866 | if( (pTab->tabFlags & TF_Ephemeral)!=0 || IsView(pTab) ){ |
| 169401 | 169867 | /* Do nothing */ |
| 169402 | 169868 | }else |
| | @@ -169463,11 +169929,11 @@ |
| 169463 | 169929 | /* This is one term of an OR-optimization using the PRIMARY KEY of a |
| 169464 | 169930 | ** WITHOUT ROWID table. No need for a separate index */ |
| 169465 | 169931 | iIndexCur = pLevel->iTabCur; |
| 169466 | 169932 | op = 0; |
| 169467 | 169933 | }else if( pWInfo->eOnePass!=ONEPASS_OFF ){ |
| 169468 | | - Index *pJ = pTabItem->pTab->pIndex; |
| 169934 | + Index *pJ = pTabItem->pSTab->pIndex; |
| 169469 | 169935 | iIndexCur = iAuxArg; |
| 169470 | 169936 | assert( wctrlFlags & WHERE_ONEPASS_DESIRED ); |
| 169471 | 169937 | while( ALWAYS(pJ) && pJ!=pIx ){ |
| 169472 | 169938 | iIndexCur++; |
| 169473 | 169939 | pJ = pJ->pNext; |
| | @@ -169530,11 +169996,11 @@ |
| 169530 | 169996 | pRJ->iMatch = pParse->nTab++; |
| 169531 | 169997 | pRJ->regBloom = ++pParse->nMem; |
| 169532 | 169998 | sqlite3VdbeAddOp2(v, OP_Blob, 65536, pRJ->regBloom); |
| 169533 | 169999 | pRJ->regReturn = ++pParse->nMem; |
| 169534 | 170000 | sqlite3VdbeAddOp2(v, OP_Null, 0, pRJ->regReturn); |
| 169535 | | - assert( pTab==pTabItem->pTab ); |
| 170001 | + assert( pTab==pTabItem->pSTab ); |
| 169536 | 170002 | if( HasRowid(pTab) ){ |
| 169537 | 170003 | KeyInfo *pInfo; |
| 169538 | 170004 | sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pRJ->iMatch, 1); |
| 169539 | 170005 | pInfo = sqlite3KeyInfoAlloc(pParse->db, 1, 0); |
| 169540 | 170006 | if( pInfo ){ |
| | @@ -169569,17 +170035,22 @@ |
| 169569 | 170035 | if( pParse->nErr ) goto whereBeginError; |
| 169570 | 170036 | pLevel = &pWInfo->a[ii]; |
| 169571 | 170037 | wsFlags = pLevel->pWLoop->wsFlags; |
| 169572 | 170038 | pSrc = &pTabList->a[pLevel->iFrom]; |
| 169573 | 170039 | if( pSrc->fg.isMaterialized ){ |
| 169574 | | - if( pSrc->fg.isCorrelated ){ |
| 169575 | | - sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); |
| 170040 | + Subquery *pSubq; |
| 170041 | + int iOnce = 0; |
| 170042 | + assert( pSrc->fg.isSubquery ); |
| 170043 | + pSubq = pSrc->u4.pSubq; |
| 170044 | + if( pSrc->fg.isCorrelated==0 ){ |
| 170045 | + iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); |
| 169576 | 170046 | }else{ |
| 169577 | | - int iOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); |
| 169578 | | - sqlite3VdbeAddOp2(v, OP_Gosub, pSrc->regReturn, pSrc->addrFillSub); |
| 169579 | | - sqlite3VdbeJumpHere(v, iOnce); |
| 170047 | + iOnce = 0; |
| 169580 | 170048 | } |
| 170049 | + sqlite3VdbeAddOp2(v, OP_Gosub, pSubq->regReturn, pSubq->addrFillSub); |
| 170050 | + VdbeComment((v, "materialize %!S", pSrc)); |
| 170051 | + if( iOnce ) sqlite3VdbeJumpHere(v, iOnce); |
| 169581 | 170052 | } |
| 169582 | 170053 | assert( pTabList == pWInfo->pTabList ); |
| 169583 | 170054 | if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){ |
| 169584 | 170055 | if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){ |
| 169585 | 170056 | #ifndef SQLITE_OMIT_AUTOMATIC_INDEX |
| | @@ -169788,13 +170259,14 @@ |
| 169788 | 170259 | if( (ws & WHERE_IDX_ONLY)==0 ){ |
| 169789 | 170260 | SrcItem *pSrc = &pTabList->a[pLevel->iFrom]; |
| 169790 | 170261 | assert( pLevel->iTabCur==pSrc->iCursor ); |
| 169791 | 170262 | if( pSrc->fg.viaCoroutine ){ |
| 169792 | 170263 | int m, n; |
| 169793 | | - n = pSrc->regResult; |
| 169794 | | - assert( pSrc->pTab!=0 ); |
| 169795 | | - m = pSrc->pTab->nCol; |
| 170264 | + assert( pSrc->fg.isSubquery ); |
| 170265 | + n = pSrc->u4.pSubq->regResult; |
| 170266 | + assert( pSrc->pSTab!=0 ); |
| 170267 | + m = pSrc->pSTab->nCol; |
| 169796 | 170268 | sqlite3VdbeAddOp3(v, OP_Null, 0, n, n+m-1); |
| 169797 | 170269 | } |
| 169798 | 170270 | sqlite3VdbeAddOp1(v, OP_NullRow, pLevel->iTabCur); |
| 169799 | 170271 | } |
| 169800 | 170272 | if( (ws & WHERE_INDEXED) |
| | @@ -169814,20 +170286,20 @@ |
| 169814 | 170286 | sqlite3VdbeGoto(v, pLevel->addrFirst); |
| 169815 | 170287 | } |
| 169816 | 170288 | sqlite3VdbeJumpHere(v, addr); |
| 169817 | 170289 | } |
| 169818 | 170290 | VdbeModuleComment((v, "End WHERE-loop%d: %s", i, |
| 169819 | | - pWInfo->pTabList->a[pLevel->iFrom].pTab->zName)); |
| 170291 | + pWInfo->pTabList->a[pLevel->iFrom].pSTab->zName)); |
| 169820 | 170292 | } |
| 169821 | 170293 | |
| 169822 | 170294 | assert( pWInfo->nLevel<=pTabList->nSrc ); |
| 169823 | 170295 | for(i=0, pLevel=pWInfo->a; i<pWInfo->nLevel; i++, pLevel++){ |
| 169824 | 170296 | int k, last; |
| 169825 | 170297 | VdbeOp *pOp, *pLastOp; |
| 169826 | 170298 | Index *pIdx = 0; |
| 169827 | 170299 | SrcItem *pTabItem = &pTabList->a[pLevel->iFrom]; |
| 169828 | | - Table *pTab = pTabItem->pTab; |
| 170300 | + Table *pTab = pTabItem->pSTab; |
| 169829 | 170301 | assert( pTab!=0 ); |
| 169830 | 170302 | pLoop = pLevel->pWLoop; |
| 169831 | 170303 | |
| 169832 | 170304 | /* Do RIGHT JOIN processing. Generate code that will output the |
| 169833 | 170305 | ** unmatched rows of the right operand of the RIGHT JOIN with |
| | @@ -169842,13 +170314,14 @@ |
| 169842 | 170314 | ** the co-routine into OP_Copy of result contained in a register. |
| 169843 | 170315 | ** OP_Rowid becomes OP_Null. |
| 169844 | 170316 | */ |
| 169845 | 170317 | if( pTabItem->fg.viaCoroutine ){ |
| 169846 | 170318 | testcase( pParse->db->mallocFailed ); |
| 169847 | | - assert( pTabItem->regResult>=0 ); |
| 170319 | + assert( pTabItem->fg.isSubquery ); |
| 170320 | + assert( pTabItem->u4.pSubq->regResult>=0 ); |
| 169848 | 170321 | translateColumnToCopy(pParse, pLevel->addrBody, pLevel->iTabCur, |
| 169849 | | - pTabItem->regResult, 0); |
| 170322 | + pTabItem->u4.pSubq->regResult, 0); |
| 169850 | 170323 | continue; |
| 169851 | 170324 | } |
| 169852 | 170325 | |
| 169853 | 170326 | /* If this scan uses an index, make VDBE code substitutions to read data |
| 169854 | 170327 | ** from the index instead of from the table where possible. In some cases |
| | @@ -171054,13 +171527,14 @@ |
| 171054 | 171527 | p->selId, p)); |
| 171055 | 171528 | p->pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0); |
| 171056 | 171529 | assert( pSub!=0 || p->pSrc==0 ); /* Due to db->mallocFailed test inside |
| 171057 | 171530 | ** of sqlite3DbMallocRawNN() called from |
| 171058 | 171531 | ** sqlite3SrcListAppend() */ |
| 171059 | | - if( p->pSrc ){ |
| 171532 | + if( p->pSrc==0 ){ |
| 171533 | + sqlite3SelectDelete(db, pSub); |
| 171534 | + }else if( sqlite3SrcItemAttachSubquery(pParse, &p->pSrc->a[0], pSub, 0) ){ |
| 171060 | 171535 | Table *pTab2; |
| 171061 | | - p->pSrc->a[0].pSelect = pSub; |
| 171062 | 171536 | p->pSrc->a[0].fg.isCorrelated = 1; |
| 171063 | 171537 | sqlite3SrcListAssignCursors(pParse, p->pSrc); |
| 171064 | 171538 | pSub->selFlags |= SF_Expanded|SF_OrderByReqd; |
| 171065 | 171539 | pTab2 = sqlite3ResultSetOfSelect(pParse, pSub, SQLITE_AFF_NONE); |
| 171066 | 171540 | pSub->selFlags |= (selFlags & SF_Aggregate); |
| | @@ -171070,20 +171544,18 @@ |
| 171070 | 171544 | ** the correct error message regardless. */ |
| 171071 | 171545 | rc = SQLITE_NOMEM; |
| 171072 | 171546 | }else{ |
| 171073 | 171547 | memcpy(pTab, pTab2, sizeof(Table)); |
| 171074 | 171548 | pTab->tabFlags |= TF_Ephemeral; |
| 171075 | | - p->pSrc->a[0].pTab = pTab; |
| 171549 | + p->pSrc->a[0].pSTab = pTab; |
| 171076 | 171550 | pTab = pTab2; |
| 171077 | 171551 | memset(&w, 0, sizeof(w)); |
| 171078 | 171552 | w.xExprCallback = sqlite3WindowExtraAggFuncDepth; |
| 171079 | 171553 | w.xSelectCallback = sqlite3WalkerDepthIncrease; |
| 171080 | 171554 | w.xSelectCallback2 = sqlite3WalkerDepthDecrease; |
| 171081 | 171555 | sqlite3WalkSelect(&w, pSub); |
| 171082 | 171556 | } |
| 171083 | | - }else{ |
| 171084 | | - sqlite3SelectDelete(db, pSub); |
| 171085 | 171557 | } |
| 171086 | 171558 | if( db->mallocFailed ) rc = SQLITE_NOMEM; |
| 171087 | 171559 | |
| 171088 | 171560 | /* Defer deleting the temporary table pTab because if an error occurred, |
| 171089 | 171561 | ** there could still be references to that table embedded in the |
| | @@ -171366,14 +171838,19 @@ |
| 171366 | 171838 | ** This is called by code in select.c before it calls sqlite3WhereBegin() |
| 171367 | 171839 | ** to begin iterating through the sub-query results. It is used to allocate |
| 171368 | 171840 | ** and initialize registers and cursors used by sqlite3WindowCodeStep(). |
| 171369 | 171841 | */ |
| 171370 | 171842 | SQLITE_PRIVATE void sqlite3WindowCodeInit(Parse *pParse, Select *pSelect){ |
| 171371 | | - int nEphExpr = pSelect->pSrc->a[0].pSelect->pEList->nExpr; |
| 171372 | | - Window *pMWin = pSelect->pWin; |
| 171373 | 171843 | Window *pWin; |
| 171374 | | - Vdbe *v = sqlite3GetVdbe(pParse); |
| 171844 | + int nEphExpr; |
| 171845 | + Window *pMWin; |
| 171846 | + Vdbe *v; |
| 171847 | + |
| 171848 | + assert( pSelect->pSrc->a[0].fg.isSubquery ); |
| 171849 | + nEphExpr = pSelect->pSrc->a[0].u4.pSubq->pSelect->pEList->nExpr; |
| 171850 | + pMWin = pSelect->pWin; |
| 171851 | + v = sqlite3GetVdbe(pParse); |
| 171375 | 171852 | |
| 171376 | 171853 | sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pMWin->iEphCsr, nEphExpr); |
| 171377 | 171854 | sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+1, pMWin->iEphCsr); |
| 171378 | 171855 | sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+2, pMWin->iEphCsr); |
| 171379 | 171856 | sqlite3VdbeAddOp2(v, OP_OpenDup, pMWin->iEphCsr+3, pMWin->iEphCsr); |
| | @@ -172766,11 +173243,11 @@ |
| 172766 | 173243 | Window *pMWin = p->pWin; |
| 172767 | 173244 | ExprList *pOrderBy = pMWin->pOrderBy; |
| 172768 | 173245 | Vdbe *v = sqlite3GetVdbe(pParse); |
| 172769 | 173246 | int csrWrite; /* Cursor used to write to eph. table */ |
| 172770 | 173247 | int csrInput = p->pSrc->a[0].iCursor; /* Cursor of sub-select */ |
| 172771 | | - int nInput = p->pSrc->a[0].pTab->nCol; /* Number of cols returned by sub */ |
| 173248 | + int nInput = p->pSrc->a[0].pSTab->nCol; /* Number of cols returned by sub */ |
| 172772 | 173249 | int iInput; /* To iterate through sub cols */ |
| 172773 | 173250 | int addrNe; /* Address of OP_Ne */ |
| 172774 | 173251 | int addrGosubFlush = 0; /* Address of OP_Gosub to flush: */ |
| 172775 | 173252 | int addrInteger = 0; /* Address of OP_Integer */ |
| 172776 | 173253 | int addrEmpty; /* Address of OP_Rewind in flush: */ |
| | @@ -177217,24 +177694,33 @@ |
| 177217 | 177694 | }else if( ALWAYS(yymsp[-3].minor.yy203!=0) && yymsp[-3].minor.yy203->nSrc==1 ){ |
| 177218 | 177695 | yymsp[-5].minor.yy203 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy203,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy269); |
| 177219 | 177696 | if( yymsp[-5].minor.yy203 ){ |
| 177220 | 177697 | SrcItem *pNew = &yymsp[-5].minor.yy203->a[yymsp[-5].minor.yy203->nSrc-1]; |
| 177221 | 177698 | SrcItem *pOld = yymsp[-3].minor.yy203->a; |
| 177699 | + assert( pOld->fg.fixedSchema==0 ); |
| 177222 | 177700 | pNew->zName = pOld->zName; |
| 177223 | | - pNew->zDatabase = pOld->zDatabase; |
| 177224 | | - pNew->pSelect = pOld->pSelect; |
| 177225 | | - if( pNew->pSelect && (pNew->pSelect->selFlags & SF_NestedFrom)!=0 ){ |
| 177226 | | - pNew->fg.isNestedFrom = 1; |
| 177701 | + assert( pOld->fg.fixedSchema==0 ); |
| 177702 | + if( pOld->fg.isSubquery ){ |
| 177703 | + pNew->fg.isSubquery = 1; |
| 177704 | + pNew->u4.pSubq = pOld->u4.pSubq; |
| 177705 | + pOld->u4.pSubq = 0; |
| 177706 | + pOld->fg.isSubquery = 0; |
| 177707 | + assert( pNew->u4.pSubq!=0 && pNew->u4.pSubq->pSelect!=0 ); |
| 177708 | + if( (pNew->u4.pSubq->pSelect->selFlags & SF_NestedFrom)!=0 ){ |
| 177709 | + pNew->fg.isNestedFrom = 1; |
| 177710 | + } |
| 177711 | + }else{ |
| 177712 | + pNew->u4.zDatabase = pOld->u4.zDatabase; |
| 177713 | + pOld->u4.zDatabase = 0; |
| 177227 | 177714 | } |
| 177228 | 177715 | if( pOld->fg.isTabFunc ){ |
| 177229 | 177716 | pNew->u1.pFuncArg = pOld->u1.pFuncArg; |
| 177230 | 177717 | pOld->u1.pFuncArg = 0; |
| 177231 | 177718 | pOld->fg.isTabFunc = 0; |
| 177232 | 177719 | pNew->fg.isTabFunc = 1; |
| 177233 | 177720 | } |
| 177234 | | - pOld->zName = pOld->zDatabase = 0; |
| 177235 | | - pOld->pSelect = 0; |
| 177721 | + pOld->zName = 0; |
| 177236 | 177722 | } |
| 177237 | 177723 | sqlite3SrcListDelete(pParse->db, yymsp[-3].minor.yy203); |
| 177238 | 177724 | }else{ |
| 177239 | 177725 | Select *pSubquery; |
| 177240 | 177726 | sqlite3SrcListShiftJoinType(pParse,yymsp[-3].minor.yy203); |
| | @@ -184790,10 +185276,22 @@ |
| 184790 | 185276 | case SQLITE_TESTCTRL_OPTIMIZATIONS: { |
| 184791 | 185277 | sqlite3 *db = va_arg(ap, sqlite3*); |
| 184792 | 185278 | db->dbOptFlags = va_arg(ap, u32); |
| 184793 | 185279 | break; |
| 184794 | 185280 | } |
| 185281 | + |
| 185282 | + /* sqlite3_test_control(SQLITE_TESTCTRL_GETOPT, sqlite3 *db, int *N) |
| 185283 | + ** |
| 185284 | + ** Write the current optimization settings into *N. A zero bit means that |
| 185285 | + ** the optimization is on, and a 1 bit means that the optimization is off. |
| 185286 | + */ |
| 185287 | + case SQLITE_TESTCTRL_GETOPT: { |
| 185288 | + sqlite3 *db = va_arg(ap, sqlite3*); |
| 185289 | + int *pN = va_arg(ap, int*); |
| 185290 | + *pN = db->dbOptFlags; |
| 185291 | + break; |
| 185292 | + } |
| 184795 | 185293 | |
| 184796 | 185294 | /* sqlite3_test_control(SQLITE_TESTCTRL_LOCALTIME_FAULT, onoff, xAlt); |
| 184797 | 185295 | ** |
| 184798 | 185296 | ** If parameter onoff is 1, subsequent calls to localtime() fail. |
| 184799 | 185297 | ** If 2, then invoke xAlt() instead of localtime(). If 0, normal |
| | @@ -224464,10 +224962,11 @@ |
| 224464 | 224962 | ) |
| 224465 | 224963 | ){ |
| 224466 | 224964 | pIdxInfo->orderByConsumed = 1; |
| 224467 | 224965 | pIdxInfo->idxNum |= 0x08; |
| 224468 | 224966 | } |
| 224967 | + pIdxInfo->idxFlags |= SQLITE_INDEX_SCAN_HEX; |
| 224469 | 224968 | |
| 224470 | 224969 | return SQLITE_OK; |
| 224471 | 224970 | } |
| 224472 | 224971 | |
| 224473 | 224972 | /* |
| | @@ -232374,13 +232873,36 @@ |
| 232374 | 232873 | ** It is the output of the tokenizer module. For tokendata=1 tables, this |
| 232375 | 232874 | ** includes any embedded 0x00 and trailing data. |
| 232376 | 232875 | ** |
| 232377 | 232876 | ** This API can be quite slow if used with an FTS5 table created with the |
| 232378 | 232877 | ** "detail=none" or "detail=column" option. |
| 232878 | +** |
| 232879 | +** xColumnLocale(pFts5, iIdx, pzLocale, pnLocale) |
| 232880 | +** If parameter iCol is less than zero, or greater than or equal to the |
| 232881 | +** number of columns in the table, SQLITE_RANGE is returned. |
| 232882 | +** |
| 232883 | +** Otherwise, this function attempts to retrieve the locale associated |
| 232884 | +** with column iCol of the current row. Usually, there is no associated |
| 232885 | +** locale, and output parameters (*pzLocale) and (*pnLocale) are set |
| 232886 | +** to NULL and 0, respectively. However, if the fts5_locale() function |
| 232887 | +** was used to associate a locale with the value when it was inserted |
| 232888 | +** into the fts5 table, then (*pzLocale) is set to point to a nul-terminated |
| 232889 | +** buffer containing the name of the locale in utf-8 encoding. (*pnLocale) |
| 232890 | +** is set to the size in bytes of the buffer, not including the |
| 232891 | +** nul-terminator. |
| 232892 | +** |
| 232893 | +** If successful, SQLITE_OK is returned. Or, if an error occurs, an |
| 232894 | +** SQLite error code is returned. The final value of the output parameters |
| 232895 | +** is undefined in this case. |
| 232896 | +** |
| 232897 | +** xTokenize_v2: |
| 232898 | +** Tokenize text using the tokenizer belonging to the FTS5 table. This |
| 232899 | +** API is the same as the xTokenize() API, except that it allows a tokenizer |
| 232900 | +** locale to be specified. |
| 232379 | 232901 | */ |
| 232380 | 232902 | struct Fts5ExtensionApi { |
| 232381 | | - int iVersion; /* Currently always set to 3 */ |
| 232903 | + int iVersion; /* Currently always set to 4 */ |
| 232382 | 232904 | |
| 232383 | 232905 | void *(*xUserData)(Fts5Context*); |
| 232384 | 232906 | |
| 232385 | 232907 | int (*xColumnCount)(Fts5Context*); |
| 232386 | 232908 | int (*xRowCount)(Fts5Context*, sqlite3_int64 *pnRow); |
| | @@ -232418,10 +232940,19 @@ |
| 232418 | 232940 | int (*xQueryToken)(Fts5Context*, |
| 232419 | 232941 | int iPhrase, int iToken, |
| 232420 | 232942 | const char **ppToken, int *pnToken |
| 232421 | 232943 | ); |
| 232422 | 232944 | int (*xInstToken)(Fts5Context*, int iIdx, int iToken, const char**, int*); |
| 232945 | + |
| 232946 | + /* Below this point are iVersion>=4 only */ |
| 232947 | + int (*xColumnLocale)(Fts5Context*, int iCol, const char **pz, int *pn); |
| 232948 | + int (*xTokenize_v2)(Fts5Context*, |
| 232949 | + const char *pText, int nText, /* Text to tokenize */ |
| 232950 | + const char *pLocale, int nLocale, /* Locale to pass to tokenizer */ |
| 232951 | + void *pCtx, /* Context passed to xToken() */ |
| 232952 | + int (*xToken)(void*, int, const char*, int, int, int) /* Callback */ |
| 232953 | + ); |
| 232423 | 232954 | }; |
| 232424 | 232955 | |
| 232425 | 232956 | /* |
| 232426 | 232957 | ** CUSTOM AUXILIARY FUNCTIONS |
| 232427 | 232958 | *************************************************************************/ |
| | @@ -232430,19 +232961,20 @@ |
| 232430 | 232961 | ** CUSTOM TOKENIZERS |
| 232431 | 232962 | ** |
| 232432 | 232963 | ** Applications may also register custom tokenizer types. A tokenizer |
| 232433 | 232964 | ** is registered by providing fts5 with a populated instance of the |
| 232434 | 232965 | ** following structure. All structure methods must be defined, setting |
| 232966 | +** |
| 232435 | 232967 | ** any member of the fts5_tokenizer struct to NULL leads to undefined |
| 232436 | 232968 | ** behaviour. The structure methods are expected to function as follows: |
| 232437 | 232969 | ** |
| 232438 | 232970 | ** xCreate: |
| 232439 | 232971 | ** This function is used to allocate and initialize a tokenizer instance. |
| 232440 | 232972 | ** A tokenizer instance is required to actually tokenize text. |
| 232441 | 232973 | ** |
| 232442 | 232974 | ** The first argument passed to this function is a copy of the (void*) |
| 232443 | | -** pointer provided by the application when the fts5_tokenizer object |
| 232975 | +** pointer provided by the application when the fts5_tokenizer_v2 object |
| 232444 | 232976 | ** was registered with FTS5 (the third argument to xCreateTokenizer()). |
| 232445 | 232977 | ** The second and third arguments are an array of nul-terminated strings |
| 232446 | 232978 | ** containing the tokenizer arguments, if any, specified following the |
| 232447 | 232979 | ** tokenizer name as part of the CREATE VIRTUAL TABLE statement used |
| 232448 | 232980 | ** to create the FTS5 table. |
| | @@ -232462,11 +232994,11 @@ |
| 232462 | 232994 | ** This function is expected to tokenize the nText byte string indicated |
| 232463 | 232995 | ** by argument pText. pText may or may not be nul-terminated. The first |
| 232464 | 232996 | ** argument passed to this function is a pointer to an Fts5Tokenizer object |
| 232465 | 232997 | ** returned by an earlier call to xCreate(). |
| 232466 | 232998 | ** |
| 232467 | | -** The second argument indicates the reason that FTS5 is requesting |
| 232999 | +** The third argument indicates the reason that FTS5 is requesting |
| 232468 | 233000 | ** tokenization of the supplied text. This is always one of the following |
| 232469 | 233001 | ** four values: |
| 232470 | 233002 | ** |
| 232471 | 233003 | ** <ul><li> <b>FTS5_TOKENIZE_DOCUMENT</b> - A document is being inserted into |
| 232472 | 233004 | ** or removed from the FTS table. The tokenizer is being invoked to |
| | @@ -232485,10 +233017,17 @@ |
| 232485 | 233017 | ** <li> <b>FTS5_TOKENIZE_AUX</b> - The tokenizer is being invoked to |
| 232486 | 233018 | ** satisfy an fts5_api.xTokenize() request made by an auxiliary |
| 232487 | 233019 | ** function. Or an fts5_api.xColumnSize() request made by the same |
| 232488 | 233020 | ** on a columnsize=0 database. |
| 232489 | 233021 | ** </ul> |
| 233022 | +** |
| 233023 | +** The sixth and seventh arguments passed to xTokenize() - pLocale and |
| 233024 | +** nLocale - are a pointer to a buffer containing the locale to use for |
| 233025 | +** tokenization (e.g. "en_US") and its size in bytes, respectively. The |
| 233026 | +** pLocale buffer is not nul-terminated. pLocale may be passed NULL (in |
| 233027 | +** which case nLocale is always 0) to indicate that the tokenizer should |
| 233028 | +** use its default locale. |
| 232490 | 233029 | ** |
| 232491 | 233030 | ** For each token in the input string, the supplied callback xToken() must |
| 232492 | 233031 | ** be invoked. The first argument to it should be a copy of the pointer |
| 232493 | 233032 | ** passed as the second argument to xTokenize(). The third and fourth |
| 232494 | 233033 | ** arguments are a pointer to a buffer containing the token text, and the |
| | @@ -232508,10 +233047,33 @@ |
| 232508 | 233047 | ** immediately return a copy of the xToken() return value. Or, if the |
| 232509 | 233048 | ** input buffer is exhausted, xTokenize() should return SQLITE_OK. Finally, |
| 232510 | 233049 | ** if an error occurs with the xTokenize() implementation itself, it |
| 232511 | 233050 | ** may abandon the tokenization and return any error code other than |
| 232512 | 233051 | ** SQLITE_OK or SQLITE_DONE. |
| 233052 | +** |
| 233053 | +** If the tokenizer is registered using an fts5_tokenizer_v2 object, |
| 233054 | +** then the xTokenize() method has two additional arguments - pLocale |
| 233055 | +** and nLocale. These specify the locale that the tokenizer should use |
| 233056 | +** for the current request. If pLocale and nLocale are both 0, then the |
| 233057 | +** tokenizer should use its default locale. Otherwise, pLocale points to |
| 233058 | +** an nLocale byte buffer containing the name of the locale to use as utf-8 |
| 233059 | +** text. pLocale is not nul-terminated. |
| 233060 | +** |
| 233061 | +** FTS5_TOKENIZER |
| 233062 | +** |
| 233063 | +** There is also an fts5_tokenizer object. This is an older version of |
| 233064 | +** fts5_tokenizer_v2. It is similar except that: |
| 233065 | +** |
| 233066 | +** <ul> |
| 233067 | +** <li> There is no "iVersion" field, and |
| 233068 | +** <li> The xTokenize() method does not take a locale argument. |
| 233069 | +** </ul> |
| 233070 | +** |
| 233071 | +** fts5_tokenizer tokenizers should be registered with the xCreateTokenizer() |
| 233072 | +** function, instead of xCreateTokenizer_v2(). Tokenizers implementations |
| 233073 | +** registered using either API may be retrieved using both xFindTokenizer() |
| 233074 | +** and xFindTokenizer_v2(). |
| 232513 | 233075 | ** |
| 232514 | 233076 | ** SYNONYM SUPPORT |
| 232515 | 233077 | ** |
| 232516 | 233078 | ** Custom tokenizers may also support synonyms. Consider a case in which a |
| 232517 | 233079 | ** user wishes to query for a phrase such as "first place". Using the |
| | @@ -232617,10 +233179,37 @@ |
| 232617 | 233179 | ** provide synonyms when tokenizing document text (method (3)) or query |
| 232618 | 233180 | ** text (method (2)), not both. Doing so will not cause any errors, but is |
| 232619 | 233181 | ** inefficient. |
| 232620 | 233182 | */ |
| 232621 | 233183 | typedef struct Fts5Tokenizer Fts5Tokenizer; |
| 233184 | +typedef struct fts5_tokenizer_v2 fts5_tokenizer_v2; |
| 233185 | +struct fts5_tokenizer_v2 { |
| 233186 | + int iVersion; /* Currently always 2 */ |
| 233187 | + |
| 233188 | + int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); |
| 233189 | + void (*xDelete)(Fts5Tokenizer*); |
| 233190 | + int (*xTokenize)(Fts5Tokenizer*, |
| 233191 | + void *pCtx, |
| 233192 | + int flags, /* Mask of FTS5_TOKENIZE_* flags */ |
| 233193 | + const char *pText, int nText, |
| 233194 | + const char *pLocale, int nLocale, |
| 233195 | + int (*xToken)( |
| 233196 | + void *pCtx, /* Copy of 2nd argument to xTokenize() */ |
| 233197 | + int tflags, /* Mask of FTS5_TOKEN_* flags */ |
| 233198 | + const char *pToken, /* Pointer to buffer containing token */ |
| 233199 | + int nToken, /* Size of token in bytes */ |
| 233200 | + int iStart, /* Byte offset of token within input text */ |
| 233201 | + int iEnd /* Byte offset of end of token within input text */ |
| 233202 | + ) |
| 233203 | + ); |
| 233204 | +}; |
| 233205 | + |
| 233206 | +/* |
| 233207 | +** New code should use the fts5_tokenizer_v2 type to define tokenizer |
| 233208 | +** implementations. The following type is included for legacy applications |
| 233209 | +** that still use it. |
| 233210 | +*/ |
| 232622 | 233211 | typedef struct fts5_tokenizer fts5_tokenizer; |
| 232623 | 233212 | struct fts5_tokenizer { |
| 232624 | 233213 | int (*xCreate)(void*, const char **azArg, int nArg, Fts5Tokenizer **ppOut); |
| 232625 | 233214 | void (*xDelete)(Fts5Tokenizer*); |
| 232626 | 233215 | int (*xTokenize)(Fts5Tokenizer*, |
| | @@ -232635,10 +233224,11 @@ |
| 232635 | 233224 | int iStart, /* Byte offset of token within input text */ |
| 232636 | 233225 | int iEnd /* Byte offset of end of token within input text */ |
| 232637 | 233226 | ) |
| 232638 | 233227 | ); |
| 232639 | 233228 | }; |
| 233229 | + |
| 232640 | 233230 | |
| 232641 | 233231 | /* Flags that may be passed as the third argument to xTokenize() */ |
| 232642 | 233232 | #define FTS5_TOKENIZE_QUERY 0x0001 |
| 232643 | 233233 | #define FTS5_TOKENIZE_PREFIX 0x0002 |
| 232644 | 233234 | #define FTS5_TOKENIZE_DOCUMENT 0x0004 |
| | @@ -232655,11 +233245,11 @@ |
| 232655 | 233245 | /************************************************************************* |
| 232656 | 233246 | ** FTS5 EXTENSION REGISTRATION API |
| 232657 | 233247 | */ |
| 232658 | 233248 | typedef struct fts5_api fts5_api; |
| 232659 | 233249 | struct fts5_api { |
| 232660 | | - int iVersion; /* Currently always set to 2 */ |
| 233250 | + int iVersion; /* Currently always set to 3 */ |
| 232661 | 233251 | |
| 232662 | 233252 | /* Create a new tokenizer */ |
| 232663 | 233253 | int (*xCreateTokenizer)( |
| 232664 | 233254 | fts5_api *pApi, |
| 232665 | 233255 | const char *zName, |
| | @@ -232682,10 +233272,29 @@ |
| 232682 | 233272 | const char *zName, |
| 232683 | 233273 | void *pUserData, |
| 232684 | 233274 | fts5_extension_function xFunction, |
| 232685 | 233275 | void (*xDestroy)(void*) |
| 232686 | 233276 | ); |
| 233277 | + |
| 233278 | + /* APIs below this point are only available if iVersion>=3 */ |
| 233279 | + |
| 233280 | + /* Create a new tokenizer */ |
| 233281 | + int (*xCreateTokenizer_v2)( |
| 233282 | + fts5_api *pApi, |
| 233283 | + const char *zName, |
| 233284 | + void *pUserData, |
| 233285 | + fts5_tokenizer_v2 *pTokenizer, |
| 233286 | + void (*xDestroy)(void*) |
| 233287 | + ); |
| 233288 | + |
| 233289 | + /* Find an existing tokenizer */ |
| 233290 | + int (*xFindTokenizer_v2)( |
| 233291 | + fts5_api *pApi, |
| 233292 | + const char *zName, |
| 233293 | + void **ppUserData, |
| 233294 | + fts5_tokenizer_v2 **ppTokenizer |
| 233295 | + ); |
| 232687 | 233296 | }; |
| 232688 | 233297 | |
| 232689 | 233298 | /* |
| 232690 | 233299 | ** END OF REGISTRATION API |
| 232691 | 233300 | *************************************************************************/ |
| | @@ -232858,14 +233467,17 @@ |
| 232858 | 233467 | typedef struct Fts5Config Fts5Config; |
| 232859 | 233468 | typedef struct Fts5TokenizerConfig Fts5TokenizerConfig; |
| 232860 | 233469 | |
| 232861 | 233470 | struct Fts5TokenizerConfig { |
| 232862 | 233471 | Fts5Tokenizer *pTok; |
| 232863 | | - fts5_tokenizer *pTokApi; |
| 233472 | + fts5_tokenizer_v2 *pApi2; |
| 233473 | + fts5_tokenizer *pApi1; |
| 232864 | 233474 | const char **azArg; |
| 232865 | 233475 | int nArg; |
| 232866 | 233476 | int ePattern; /* FTS_PATTERN_XXX constant */ |
| 233477 | + const char *pLocale; /* Current locale to use */ |
| 233478 | + int nLocale; /* Size of pLocale in bytes */ |
| 232867 | 233479 | }; |
| 232868 | 233480 | |
| 232869 | 233481 | /* |
| 232870 | 233482 | ** An instance of the following structure encodes all information that can |
| 232871 | 233483 | ** be gleaned from the CREATE VIRTUAL TABLE statement. |
| | @@ -232902,10 +233514,12 @@ |
| 232902 | 233514 | ** This is only used for debugging. If set to false, any prefix indexes |
| 232903 | 233515 | ** are ignored. This value is configured using: |
| 232904 | 233516 | ** |
| 232905 | 233517 | ** INSERT INTO tbl(tbl, rank) VALUES('prefix-index', $bPrefixIndex); |
| 232906 | 233518 | ** |
| 233519 | +** bLocale: |
| 233520 | +** Set to true if locale=1 was specified when the table was created. |
| 232907 | 233521 | */ |
| 232908 | 233522 | struct Fts5Config { |
| 232909 | 233523 | sqlite3 *db; /* Database handle */ |
| 232910 | 233524 | Fts5Global *pGlobal; /* Global fts5 object for handle db */ |
| 232911 | 233525 | char *zDb; /* Database holding FTS index (e.g. "main") */ |
| | @@ -232919,14 +233533,16 @@ |
| 232919 | 233533 | int bContentlessDelete; /* "contentless_delete=" option (dflt==0) */ |
| 232920 | 233534 | char *zContent; /* content table */ |
| 232921 | 233535 | char *zContentRowid; /* "content_rowid=" option value */ |
| 232922 | 233536 | int bColumnsize; /* "columnsize=" option value (dflt==1) */ |
| 232923 | 233537 | int bTokendata; /* "tokendata=" option value (dflt==0) */ |
| 233538 | + int bLocale; /* "locale=" option value (dflt==0) */ |
| 232924 | 233539 | int eDetail; /* FTS5_DETAIL_XXX value */ |
| 232925 | 233540 | char *zContentExprlist; |
| 232926 | 233541 | Fts5TokenizerConfig t; |
| 232927 | 233542 | int bLock; /* True when table is preparing statement */ |
| 233543 | + |
| 232928 | 233544 | |
| 232929 | 233545 | /* Values loaded from the %_config table */ |
| 232930 | 233546 | int iVersion; /* fts5 file format 'version' */ |
| 232931 | 233547 | int iCookie; /* Incremented when %_config is modified */ |
| 232932 | 233548 | int pgsz; /* Approximate page size used in %_data */ |
| | @@ -232988,10 +233604,12 @@ |
| 232988 | 233604 | /* Set the value of a single config attribute */ |
| 232989 | 233605 | static int sqlite3Fts5ConfigSetValue(Fts5Config*, const char*, sqlite3_value*, int*); |
| 232990 | 233606 | |
| 232991 | 233607 | static int sqlite3Fts5ConfigParseRank(const char*, char**, char**); |
| 232992 | 233608 | |
| 233609 | +static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...); |
| 233610 | + |
| 232993 | 233611 | /* |
| 232994 | 233612 | ** End of interface to code in fts5_config.c. |
| 232995 | 233613 | **************************************************************************/ |
| 232996 | 233614 | |
| 232997 | 233615 | /************************************************************************** |
| | @@ -233032,11 +233650,11 @@ |
| 233032 | 233650 | |
| 233033 | 233651 | /* Write and decode big-endian 32-bit integer values */ |
| 233034 | 233652 | static void sqlite3Fts5Put32(u8*, int); |
| 233035 | 233653 | static int sqlite3Fts5Get32(const u8*); |
| 233036 | 233654 | |
| 233037 | | -#define FTS5_POS2COLUMN(iPos) (int)(iPos >> 32) |
| 233655 | +#define FTS5_POS2COLUMN(iPos) (int)((iPos >> 32) & 0x7FFFFFFF) |
| 233038 | 233656 | #define FTS5_POS2OFFSET(iPos) (int)(iPos & 0x7FFFFFFF) |
| 233039 | 233657 | |
| 233040 | 233658 | typedef struct Fts5PoslistReader Fts5PoslistReader; |
| 233041 | 233659 | struct Fts5PoslistReader { |
| 233042 | 233660 | /* Variables used only by sqlite3Fts5PoslistIterXXX() functions. */ |
| | @@ -233323,10 +233941,21 @@ |
| 233323 | 233941 | |
| 233324 | 233942 | static Fts5Table *sqlite3Fts5TableFromCsrid(Fts5Global*, i64); |
| 233325 | 233943 | |
| 233326 | 233944 | static int sqlite3Fts5FlushToDisk(Fts5Table*); |
| 233327 | 233945 | |
| 233946 | +static int sqlite3Fts5ExtractText( |
| 233947 | + Fts5Config *pConfig, |
| 233948 | + sqlite3_value *pVal, /* Value to extract text from */ |
| 233949 | + int bContent, /* Loaded from content table */ |
| 233950 | + int *pbResetTokenizer, /* OUT: True if ClearLocale() required */ |
| 233951 | + const char **ppText, /* OUT: Pointer to text buffer */ |
| 233952 | + int *pnText /* OUT: Size of (*ppText) in bytes */ |
| 233953 | +); |
| 233954 | + |
| 233955 | +static void sqlite3Fts5ClearLocale(Fts5Config *pConfig); |
| 233956 | + |
| 233328 | 233957 | /* |
| 233329 | 233958 | ** End of interface to code in fts5.c. |
| 233330 | 233959 | **************************************************************************/ |
| 233331 | 233960 | |
| 233332 | 233961 | /************************************************************************** |
| | @@ -233402,11 +234031,11 @@ |
| 233402 | 234031 | static int sqlite3Fts5StorageRename(Fts5Storage*, const char *zName); |
| 233403 | 234032 | |
| 233404 | 234033 | static int sqlite3Fts5DropAll(Fts5Config*); |
| 233405 | 234034 | static int sqlite3Fts5CreateTable(Fts5Config*, const char*, const char*, int, char **); |
| 233406 | 234035 | |
| 233407 | | -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**); |
| 234036 | +static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64, sqlite3_value**, int); |
| 233408 | 234037 | static int sqlite3Fts5StorageContentInsert(Fts5Storage *p, sqlite3_value**, i64*); |
| 233409 | 234038 | static int sqlite3Fts5StorageIndexInsert(Fts5Storage *p, sqlite3_value**, i64); |
| 233410 | 234039 | |
| 233411 | 234040 | static int sqlite3Fts5StorageIntegrity(Fts5Storage *p, int iArg); |
| 233412 | 234041 | |
| | @@ -233428,10 +234057,13 @@ |
| 233428 | 234057 | static int sqlite3Fts5StorageRebuild(Fts5Storage *p); |
| 233429 | 234058 | static int sqlite3Fts5StorageOptimize(Fts5Storage *p); |
| 233430 | 234059 | static int sqlite3Fts5StorageMerge(Fts5Storage *p, int nMerge); |
| 233431 | 234060 | static int sqlite3Fts5StorageReset(Fts5Storage *p); |
| 233432 | 234061 | |
| 234062 | +static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage*); |
| 234063 | +static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel); |
| 234064 | + |
| 233433 | 234065 | /* |
| 233434 | 234066 | ** End of interface to code in fts5_storage.c. |
| 233435 | 234067 | **************************************************************************/ |
| 233436 | 234068 | |
| 233437 | 234069 | |
| | @@ -235357,10 +235989,11 @@ |
| 235357 | 235989 | p->iOff = iEndOff; |
| 235358 | 235990 | } |
| 235359 | 235991 | |
| 235360 | 235992 | return rc; |
| 235361 | 235993 | } |
| 235994 | + |
| 235362 | 235995 | |
| 235363 | 235996 | /* |
| 235364 | 235997 | ** Implementation of highlight() function. |
| 235365 | 235998 | */ |
| 235366 | 235999 | static void fts5HighlightFunction( |
| | @@ -235388,16 +236021,23 @@ |
| 235388 | 236021 | rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); |
| 235389 | 236022 | if( rc==SQLITE_RANGE ){ |
| 235390 | 236023 | sqlite3_result_text(pCtx, "", -1, SQLITE_STATIC); |
| 235391 | 236024 | rc = SQLITE_OK; |
| 235392 | 236025 | }else if( ctx.zIn ){ |
| 236026 | + const char *pLoc = 0; /* Locale of column iCol */ |
| 236027 | + int nLoc = 0; /* Size of pLoc in bytes */ |
| 235393 | 236028 | if( rc==SQLITE_OK ){ |
| 235394 | 236029 | rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); |
| 235395 | 236030 | } |
| 235396 | 236031 | |
| 235397 | 236032 | if( rc==SQLITE_OK ){ |
| 235398 | | - rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); |
| 236033 | + rc = pApi->xColumnLocale(pFts, iCol, &pLoc, &nLoc); |
| 236034 | + } |
| 236035 | + if( rc==SQLITE_OK ){ |
| 236036 | + rc = pApi->xTokenize_v2( |
| 236037 | + pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx, fts5HighlightCb |
| 236038 | + ); |
| 235399 | 236039 | } |
| 235400 | 236040 | if( ctx.bOpen ){ |
| 235401 | 236041 | fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); |
| 235402 | 236042 | } |
| 235403 | 236043 | fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); |
| | @@ -235590,19 +236230,23 @@ |
| 235590 | 236230 | } |
| 235591 | 236231 | |
| 235592 | 236232 | memset(&sFinder, 0, sizeof(Fts5SFinder)); |
| 235593 | 236233 | for(i=0; i<nCol; i++){ |
| 235594 | 236234 | if( iCol<0 || iCol==i ){ |
| 236235 | + const char *pLoc = 0; /* Locale of column iCol */ |
| 236236 | + int nLoc = 0; /* Size of pLoc in bytes */ |
| 235595 | 236237 | int nDoc; |
| 235596 | 236238 | int nDocsize; |
| 235597 | 236239 | int ii; |
| 235598 | 236240 | sFinder.iPos = 0; |
| 235599 | 236241 | sFinder.nFirst = 0; |
| 235600 | 236242 | rc = pApi->xColumnText(pFts, i, &sFinder.zDoc, &nDoc); |
| 235601 | 236243 | if( rc!=SQLITE_OK ) break; |
| 235602 | | - rc = pApi->xTokenize(pFts, |
| 235603 | | - sFinder.zDoc, nDoc, (void*)&sFinder,fts5SentenceFinderCb |
| 236244 | + rc = pApi->xColumnLocale(pFts, i, &pLoc, &nLoc); |
| 236245 | + if( rc!=SQLITE_OK ) break; |
| 236246 | + rc = pApi->xTokenize_v2(pFts, |
| 236247 | + sFinder.zDoc, nDoc, pLoc, nLoc, (void*)&sFinder, fts5SentenceFinderCb |
| 235604 | 236248 | ); |
| 235605 | 236249 | if( rc!=SQLITE_OK ) break; |
| 235606 | 236250 | rc = pApi->xColumnSize(pFts, i, &nDocsize); |
| 235607 | 236251 | if( rc!=SQLITE_OK ) break; |
| 235608 | 236252 | |
| | @@ -235656,10 +236300,13 @@ |
| 235656 | 236300 | } |
| 235657 | 236301 | if( rc==SQLITE_OK && nColSize==0 ){ |
| 235658 | 236302 | rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); |
| 235659 | 236303 | } |
| 235660 | 236304 | if( ctx.zIn ){ |
| 236305 | + const char *pLoc = 0; /* Locale of column iBestCol */ |
| 236306 | + int nLoc = 0; /* Bytes in pLoc */ |
| 236307 | + |
| 235661 | 236308 | if( rc==SQLITE_OK ){ |
| 235662 | 236309 | rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); |
| 235663 | 236310 | } |
| 235664 | 236311 | |
| 235665 | 236312 | ctx.iRangeStart = iBestStart; |
| | @@ -235674,11 +236321,16 @@ |
| 235674 | 236321 | while( ctx.iter.iStart>=0 && ctx.iter.iStart<iBestStart && rc==SQLITE_OK ){ |
| 235675 | 236322 | rc = fts5CInstIterNext(&ctx.iter); |
| 235676 | 236323 | } |
| 235677 | 236324 | |
| 235678 | 236325 | if( rc==SQLITE_OK ){ |
| 235679 | | - rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); |
| 236326 | + rc = pApi->xColumnLocale(pFts, iBestCol, &pLoc, &nLoc); |
| 236327 | + } |
| 236328 | + if( rc==SQLITE_OK ){ |
| 236329 | + rc = pApi->xTokenize_v2( |
| 236330 | + pFts, ctx.zIn, ctx.nIn, pLoc, nLoc, (void*)&ctx,fts5HighlightCb |
| 236331 | + ); |
| 235680 | 236332 | } |
| 235681 | 236333 | if( ctx.bOpen ){ |
| 235682 | 236334 | fts5HighlightAppend(&rc, &ctx, ctx.zClose, -1); |
| 235683 | 236335 | } |
| 235684 | 236336 | if( ctx.iRangeEnd>=(nColSize-1) ){ |
| | @@ -235857,21 +236509,69 @@ |
| 235857 | 236509 | sqlite3_result_double(pCtx, -1.0 * score); |
| 235858 | 236510 | }else{ |
| 235859 | 236511 | sqlite3_result_error_code(pCtx, rc); |
| 235860 | 236512 | } |
| 235861 | 236513 | } |
| 236514 | + |
| 236515 | +/* |
| 236516 | +** Implementation of fts5_get_locale() function. |
| 236517 | +*/ |
| 236518 | +static void fts5GetLocaleFunction( |
| 236519 | + const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ |
| 236520 | + Fts5Context *pFts, /* First arg to pass to pApi functions */ |
| 236521 | + sqlite3_context *pCtx, /* Context for returning result/error */ |
| 236522 | + int nVal, /* Number of values in apVal[] array */ |
| 236523 | + sqlite3_value **apVal /* Array of trailing arguments */ |
| 236524 | +){ |
| 236525 | + int iCol = 0; |
| 236526 | + int eType = 0; |
| 236527 | + int rc = SQLITE_OK; |
| 236528 | + const char *zLocale = 0; |
| 236529 | + int nLocale = 0; |
| 236530 | + |
| 236531 | + /* xColumnLocale() must be available */ |
| 236532 | + assert( pApi->iVersion>=4 ); |
| 236533 | + |
| 236534 | + if( nVal!=1 ){ |
| 236535 | + const char *z = "wrong number of arguments to function fts5_get_locale()"; |
| 236536 | + sqlite3_result_error(pCtx, z, -1); |
| 236537 | + return; |
| 236538 | + } |
| 236539 | + |
| 236540 | + eType = sqlite3_value_numeric_type(apVal[0]); |
| 236541 | + if( eType!=SQLITE_INTEGER ){ |
| 236542 | + const char *z = "non-integer argument passed to function fts5_get_locale()"; |
| 236543 | + sqlite3_result_error(pCtx, z, -1); |
| 236544 | + return; |
| 236545 | + } |
| 236546 | + |
| 236547 | + iCol = sqlite3_value_int(apVal[0]); |
| 236548 | + if( iCol<0 || iCol>=pApi->xColumnCount(pFts) ){ |
| 236549 | + sqlite3_result_error_code(pCtx, SQLITE_RANGE); |
| 236550 | + return; |
| 236551 | + } |
| 236552 | + |
| 236553 | + rc = pApi->xColumnLocale(pFts, iCol, &zLocale, &nLocale); |
| 236554 | + if( rc!=SQLITE_OK ){ |
| 236555 | + sqlite3_result_error_code(pCtx, rc); |
| 236556 | + return; |
| 236557 | + } |
| 236558 | + |
| 236559 | + sqlite3_result_text(pCtx, zLocale, nLocale, SQLITE_TRANSIENT); |
| 236560 | +} |
| 235862 | 236561 | |
| 235863 | 236562 | static int sqlite3Fts5AuxInit(fts5_api *pApi){ |
| 235864 | 236563 | struct Builtin { |
| 235865 | 236564 | const char *zFunc; /* Function name (nul-terminated) */ |
| 235866 | 236565 | void *pUserData; /* User-data pointer */ |
| 235867 | 236566 | fts5_extension_function xFunc;/* Callback function */ |
| 235868 | 236567 | void (*xDestroy)(void*); /* Destructor function */ |
| 235869 | 236568 | } aBuiltin [] = { |
| 235870 | | - { "snippet", 0, fts5SnippetFunction, 0 }, |
| 235871 | | - { "highlight", 0, fts5HighlightFunction, 0 }, |
| 235872 | | - { "bm25", 0, fts5Bm25Function, 0 }, |
| 236569 | + { "snippet", 0, fts5SnippetFunction, 0 }, |
| 236570 | + { "highlight", 0, fts5HighlightFunction, 0 }, |
| 236571 | + { "bm25", 0, fts5Bm25Function, 0 }, |
| 236572 | + { "fts5_get_locale", 0, fts5GetLocaleFunction, 0 }, |
| 235873 | 236573 | }; |
| 235874 | 236574 | int rc = SQLITE_OK; /* Return code */ |
| 235875 | 236575 | int i; /* To iterate through builtin functions */ |
| 235876 | 236576 | |
| 235877 | 236577 | for(i=0; rc==SQLITE_OK && i<ArraySize(aBuiltin); i++){ |
| | @@ -236677,10 +237377,20 @@ |
| 236677 | 237377 | }else{ |
| 236678 | 237378 | pConfig->bColumnsize = (zArg[0]=='1'); |
| 236679 | 237379 | } |
| 236680 | 237380 | return rc; |
| 236681 | 237381 | } |
| 237382 | + |
| 237383 | + if( sqlite3_strnicmp("locale", zCmd, nCmd)==0 ){ |
| 237384 | + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1]!='\0' ){ |
| 237385 | + *pzErr = sqlite3_mprintf("malformed locale=... directive"); |
| 237386 | + rc = SQLITE_ERROR; |
| 237387 | + }else{ |
| 237388 | + pConfig->bLocale = (zArg[0]=='1'); |
| 237389 | + } |
| 237390 | + return rc; |
| 237391 | + } |
| 236682 | 237392 | |
| 236683 | 237393 | if( sqlite3_strnicmp("detail", zCmd, nCmd)==0 ){ |
| 236684 | 237394 | const Fts5Enum aDetail[] = { |
| 236685 | 237395 | { "none", FTS5_DETAIL_NONE }, |
| 236686 | 237396 | { "full", FTS5_DETAIL_FULL }, |
| | @@ -236967,11 +237677,15 @@ |
| 236967 | 237677 | */ |
| 236968 | 237678 | static void sqlite3Fts5ConfigFree(Fts5Config *pConfig){ |
| 236969 | 237679 | if( pConfig ){ |
| 236970 | 237680 | int i; |
| 236971 | 237681 | if( pConfig->t.pTok ){ |
| 236972 | | - pConfig->t.pTokApi->xDelete(pConfig->t.pTok); |
| 237682 | + if( pConfig->t.pApi1 ){ |
| 237683 | + pConfig->t.pApi1->xDelete(pConfig->t.pTok); |
| 237684 | + }else{ |
| 237685 | + pConfig->t.pApi2->xDelete(pConfig->t.pTok); |
| 237686 | + } |
| 236973 | 237687 | } |
| 236974 | 237688 | sqlite3_free((char*)pConfig->t.azArg); |
| 236975 | 237689 | sqlite3_free(pConfig->zDb); |
| 236976 | 237690 | sqlite3_free(pConfig->zName); |
| 236977 | 237691 | for(i=0; i<pConfig->nCol; i++){ |
| | @@ -237050,13 +237764,19 @@ |
| 237050 | 237764 | if( pText ){ |
| 237051 | 237765 | if( pConfig->t.pTok==0 ){ |
| 237052 | 237766 | rc = sqlite3Fts5LoadTokenizer(pConfig); |
| 237053 | 237767 | } |
| 237054 | 237768 | if( rc==SQLITE_OK ){ |
| 237055 | | - rc = pConfig->t.pTokApi->xTokenize( |
| 237056 | | - pConfig->t.pTok, pCtx, flags, pText, nText, xToken |
| 237057 | | - ); |
| 237769 | + if( pConfig->t.pApi1 ){ |
| 237770 | + rc = pConfig->t.pApi1->xTokenize( |
| 237771 | + pConfig->t.pTok, pCtx, flags, pText, nText, xToken |
| 237772 | + ); |
| 237773 | + }else{ |
| 237774 | + rc = pConfig->t.pApi2->xTokenize(pConfig->t.pTok, pCtx, flags, |
| 237775 | + pText, nText, pConfig->t.pLocale, pConfig->t.nLocale, xToken |
| 237776 | + ); |
| 237777 | + } |
| 237058 | 237778 | } |
| 237059 | 237779 | } |
| 237060 | 237780 | return rc; |
| 237061 | 237781 | } |
| 237062 | 237782 | |
| | @@ -237309,26 +238029,46 @@ |
| 237309 | 238029 | if( rc==SQLITE_OK |
| 237310 | 238030 | && iVersion!=FTS5_CURRENT_VERSION |
| 237311 | 238031 | && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE |
| 237312 | 238032 | ){ |
| 237313 | 238033 | rc = SQLITE_ERROR; |
| 237314 | | - if( pConfig->pzErrmsg ){ |
| 237315 | | - assert( 0==*pConfig->pzErrmsg ); |
| 237316 | | - *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format " |
| 237317 | | - "(found %d, expected %d or %d) - run 'rebuild'", |
| 237318 | | - iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE |
| 237319 | | - ); |
| 237320 | | - } |
| 238034 | + sqlite3Fts5ConfigErrmsg(pConfig, "invalid fts5 file format " |
| 238035 | + "(found %d, expected %d or %d) - run 'rebuild'", |
| 238036 | + iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE |
| 238037 | + ); |
| 237321 | 238038 | }else{ |
| 237322 | 238039 | pConfig->iVersion = iVersion; |
| 237323 | 238040 | } |
| 237324 | 238041 | |
| 237325 | 238042 | if( rc==SQLITE_OK ){ |
| 237326 | 238043 | pConfig->iCookie = iCookie; |
| 237327 | 238044 | } |
| 237328 | 238045 | return rc; |
| 237329 | 238046 | } |
| 238047 | + |
| 238048 | +/* |
| 238049 | +** Set (*pConfig->pzErrmsg) to point to an sqlite3_malloc()ed buffer |
| 238050 | +** containing the error message created using printf() style formatting |
| 238051 | +** string zFmt and its trailing arguments. |
| 238052 | +*/ |
| 238053 | +static void sqlite3Fts5ConfigErrmsg(Fts5Config *pConfig, const char *zFmt, ...){ |
| 238054 | + va_list ap; /* ... printf arguments */ |
| 238055 | + char *zMsg = 0; |
| 238056 | + |
| 238057 | + va_start(ap, zFmt); |
| 238058 | + zMsg = sqlite3_vmprintf(zFmt, ap); |
| 238059 | + if( pConfig->pzErrmsg ){ |
| 238060 | + assert( *pConfig->pzErrmsg==0 ); |
| 238061 | + *pConfig->pzErrmsg = zMsg; |
| 238062 | + }else{ |
| 238063 | + sqlite3_free(zMsg); |
| 238064 | + } |
| 238065 | + |
| 238066 | + va_end(ap); |
| 238067 | +} |
| 238068 | + |
| 238069 | + |
| 237330 | 238070 | |
| 237331 | 238071 | /* |
| 237332 | 238072 | ** 2014 May 31 |
| 237333 | 238073 | ** |
| 237334 | 238074 | ** The author disclaims copyright to this source code. In place of |
| | @@ -237614,15 +238354,16 @@ |
| 237614 | 238354 | t = fts5ExprGetToken(&sParse, &z, &token); |
| 237615 | 238355 | sqlite3Fts5Parser(pEngine, t, token, &sParse); |
| 237616 | 238356 | }while( sParse.rc==SQLITE_OK && t!=FTS5_EOF ); |
| 237617 | 238357 | sqlite3Fts5ParserFree(pEngine, fts5ParseFree); |
| 237618 | 238358 | |
| 238359 | + assert( sParse.pExpr || sParse.rc!=SQLITE_OK ); |
| 237619 | 238360 | assert_expr_depth_ok(sParse.rc, sParse.pExpr); |
| 237620 | 238361 | |
| 237621 | 238362 | /* If the LHS of the MATCH expression was a user column, apply the |
| 237622 | 238363 | ** implicit column-filter. */ |
| 237623 | | - if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){ |
| 238364 | + if( sParse.rc==SQLITE_OK && iCol<pConfig->nCol ){ |
| 237624 | 238365 | int n = sizeof(Fts5Colset); |
| 237625 | 238366 | Fts5Colset *pColset = (Fts5Colset*)sqlite3Fts5MallocZero(&sParse.rc, n); |
| 237626 | 238367 | if( pColset ){ |
| 237627 | 238368 | pColset->nCol = 1; |
| 237628 | 238369 | pColset->aiCol[0] = iCol; |
| | @@ -237635,19 +238376,11 @@ |
| 237635 | 238376 | *ppNew = pNew = sqlite3_malloc(sizeof(Fts5Expr)); |
| 237636 | 238377 | if( pNew==0 ){ |
| 237637 | 238378 | sParse.rc = SQLITE_NOMEM; |
| 237638 | 238379 | sqlite3Fts5ParseNodeFree(sParse.pExpr); |
| 237639 | 238380 | }else{ |
| 237640 | | - if( !sParse.pExpr ){ |
| 237641 | | - const int nByte = sizeof(Fts5ExprNode); |
| 237642 | | - pNew->pRoot = (Fts5ExprNode*)sqlite3Fts5MallocZero(&sParse.rc, nByte); |
| 237643 | | - if( pNew->pRoot ){ |
| 237644 | | - pNew->pRoot->bEof = 1; |
| 237645 | | - } |
| 237646 | | - }else{ |
| 237647 | | - pNew->pRoot = sParse.pExpr; |
| 237648 | | - } |
| 238381 | + pNew->pRoot = sParse.pExpr; |
| 237649 | 238382 | pNew->pIndex = 0; |
| 237650 | 238383 | pNew->pConfig = pConfig; |
| 237651 | 238384 | pNew->apExprPhrase = sParse.apPhrase; |
| 237652 | 238385 | pNew->nPhrase = sParse.nPhrase; |
| 237653 | 238386 | pNew->bDesc = 0; |
| | @@ -238461,11 +239194,11 @@ |
| 238461 | 239194 | pNode->bEof = 1; |
| 238462 | 239195 | return rc; |
| 238463 | 239196 | } |
| 238464 | 239197 | }else{ |
| 238465 | 239198 | Fts5IndexIter *pIter = pPhrase->aTerm[j].pIter; |
| 238466 | | - if( pIter->iRowid==iLast || pIter->bEof ) continue; |
| 239199 | + if( pIter->iRowid==iLast ) continue; |
| 238467 | 239200 | bMatch = 0; |
| 238468 | 239201 | if( fts5ExprAdvanceto(pIter, bDesc, &iLast, &rc, &pNode->bEof) ){ |
| 238469 | 239202 | return rc; |
| 238470 | 239203 | } |
| 238471 | 239204 | } |
| | @@ -238983,13 +239716,10 @@ |
| 238983 | 239716 | ){ |
| 238984 | 239717 | const int SZALLOC = 8; |
| 238985 | 239718 | Fts5ExprNearset *pRet = 0; |
| 238986 | 239719 | |
| 238987 | 239720 | if( pParse->rc==SQLITE_OK ){ |
| 238988 | | - if( pPhrase==0 ){ |
| 238989 | | - return pNear; |
| 238990 | | - } |
| 238991 | 239721 | if( pNear==0 ){ |
| 238992 | 239722 | sqlite3_int64 nByte; |
| 238993 | 239723 | nByte = sizeof(Fts5ExprNearset) + SZALLOC * sizeof(Fts5ExprPhrase*); |
| 238994 | 239724 | pRet = sqlite3_malloc64(nByte); |
| 238995 | 239725 | if( pRet==0 ){ |
| | @@ -250372,15 +251102,32 @@ |
| 250372 | 251102 | |
| 250373 | 251103 | /* |
| 250374 | 251104 | ** Each tokenizer module registered with the FTS5 module is represented |
| 250375 | 251105 | ** by an object of the following type. All such objects are stored as part |
| 250376 | 251106 | ** of the Fts5Global.pTok list. |
| 251107 | +** |
| 251108 | +** bV2Native: |
| 251109 | +** True if the tokenizer was registered using xCreateTokenizer_v2(), false |
| 251110 | +** for xCreateTokenizer(). If this variable is true, then x2 is populated |
| 251111 | +** with the routines as supplied by the caller and x1 contains synthesized |
| 251112 | +** wrapper routines. In this case the user-data pointer passed to |
| 251113 | +** x1.xCreate should be a pointer to the Fts5TokenizerModule structure, |
| 251114 | +** not a copy of pUserData. |
| 251115 | +** |
| 251116 | +** Of course, if bV2Native is false, then x1 contains the real routines and |
| 251117 | +** x2 the synthesized ones. In this case a pointer to the Fts5TokenizerModule |
| 251118 | +** object should be passed to x2.xCreate. |
| 251119 | +** |
| 251120 | +** The synthesized wrapper routines are necessary for xFindTokenizer(_v2) |
| 251121 | +** calls. |
| 250377 | 251122 | */ |
| 250378 | 251123 | struct Fts5TokenizerModule { |
| 250379 | 251124 | char *zName; /* Name of tokenizer */ |
| 250380 | 251125 | void *pUserData; /* User pointer passed to xCreate() */ |
| 250381 | | - fts5_tokenizer x; /* Tokenizer functions */ |
| 251126 | + int bV2Native; /* True if v2 native tokenizer */ |
| 251127 | + fts5_tokenizer x1; /* Tokenizer functions */ |
| 251128 | + fts5_tokenizer_v2 x2; /* V2 tokenizer functions */ |
| 250382 | 251129 | void (*xDestroy)(void*); /* Destructor function */ |
| 250383 | 251130 | Fts5TokenizerModule *pNext; /* Next registered tokenizer module */ |
| 250384 | 251131 | }; |
| 250385 | 251132 | |
| 250386 | 251133 | struct Fts5FullTable { |
| | @@ -250464,11 +251211,11 @@ |
| 250464 | 251211 | |
| 250465 | 251212 | /* Auxiliary data storage */ |
| 250466 | 251213 | Fts5Auxiliary *pAux; /* Currently executing extension function */ |
| 250467 | 251214 | Fts5Auxdata *pAuxdata; /* First in linked list of saved aux-data */ |
| 250468 | 251215 | |
| 250469 | | - /* Cache used by auxiliary functions xInst() and xInstCount() */ |
| 251216 | + /* Cache used by auxiliary API functions xInst() and xInstCount() */ |
| 250470 | 251217 | Fts5PoslistReader *aInstIter; /* One for each phrase */ |
| 250471 | 251218 | int nInstAlloc; /* Size of aInst[] array (entries / 3) */ |
| 250472 | 251219 | int nInstCount; /* Number of phrase instances */ |
| 250473 | 251220 | int *aInst; /* 3 integers per phrase instance */ |
| 250474 | 251221 | }; |
| | @@ -250499,10 +251246,16 @@ |
| 250499 | 251246 | #define FTS5CSR_REQUIRE_POSLIST 0x40 |
| 250500 | 251247 | |
| 250501 | 251248 | #define BitFlagAllTest(x,y) (((x) & (y))==(y)) |
| 250502 | 251249 | #define BitFlagTest(x,y) (((x) & (y))!=0) |
| 250503 | 251250 | |
| 251251 | +/* |
| 251252 | +** The subtype value and header bytes used by fts5_locale(). |
| 251253 | +*/ |
| 251254 | +#define FTS5_LOCALE_SUBTYPE ((unsigned int)'L') |
| 251255 | +#define FTS5_LOCALE_HEADER "\x00\xE0\xB2\xEB" |
| 251256 | + |
| 250504 | 251257 | |
| 250505 | 251258 | /* |
| 250506 | 251259 | ** Macros to Set(), Clear() and Test() cursor flags. |
| 250507 | 251260 | */ |
| 250508 | 251261 | #define CsrFlagSet(pCsr, flag) ((pCsr)->csrflags |= (flag)) |
| | @@ -250876,11 +251629,11 @@ |
| 250876 | 251629 | }else{ |
| 250877 | 251630 | if( iCol==nCol+1 ){ |
| 250878 | 251631 | if( bSeenRank ) continue; |
| 250879 | 251632 | idxStr[iIdxStr++] = 'r'; |
| 250880 | 251633 | bSeenRank = 1; |
| 250881 | | - }else if( iCol>=0 ){ |
| 251634 | + }else{ |
| 250882 | 251635 | nSeenMatch++; |
| 250883 | 251636 | idxStr[iIdxStr++] = 'M'; |
| 250884 | 251637 | sqlite3_snprintf(6, &idxStr[iIdxStr], "%d", iCol); |
| 250885 | 251638 | idxStr += strlen(&idxStr[iIdxStr]); |
| 250886 | 251639 | assert( idxStr[iIdxStr]=='\0' ); |
| | @@ -251262,11 +252015,11 @@ |
| 251262 | 252015 | rc = SQLITE_NOMEM; |
| 251263 | 252016 | }else{ |
| 251264 | 252017 | rc = sqlite3_prepare_v3(pConfig->db, zSql, -1, |
| 251265 | 252018 | SQLITE_PREPARE_PERSISTENT, &pRet, 0); |
| 251266 | 252019 | if( rc!=SQLITE_OK ){ |
| 251267 | | - *pConfig->pzErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(pConfig->db)); |
| 252020 | + sqlite3Fts5ConfigErrmsg(pConfig, "%s", sqlite3_errmsg(pConfig->db)); |
| 251268 | 252021 | } |
| 251269 | 252022 | sqlite3_free(zSql); |
| 251270 | 252023 | } |
| 251271 | 252024 | |
| 251272 | 252025 | va_end(ap); |
| | @@ -251497,10 +252250,192 @@ |
| 251497 | 252250 | sqlite3_free(p->p.base.zErrMsg); |
| 251498 | 252251 | p->p.base.zErrMsg = sqlite3_vmprintf(zFormat, ap); |
| 251499 | 252252 | va_end(ap); |
| 251500 | 252253 | } |
| 251501 | 252254 | |
| 252255 | +/* |
| 252256 | +** Arrange for subsequent calls to sqlite3Fts5Tokenize() to use the locale |
| 252257 | +** specified by pLocale/nLocale. The buffer indicated by pLocale must remain |
| 252258 | +** valid until after the final call to sqlite3Fts5Tokenize() that will use |
| 252259 | +** the locale. |
| 252260 | +*/ |
| 252261 | +static void fts5SetLocale( |
| 252262 | + Fts5Config *pConfig, |
| 252263 | + const char *zLocale, |
| 252264 | + int nLocale |
| 252265 | +){ |
| 252266 | + Fts5TokenizerConfig *pT = &pConfig->t; |
| 252267 | + pT->pLocale = zLocale; |
| 252268 | + pT->nLocale = nLocale; |
| 252269 | +} |
| 252270 | + |
| 252271 | +/* |
| 252272 | +** Clear any locale configured by an earlier call to fts5SetLocale() or |
| 252273 | +** sqlite3Fts5ExtractText(). |
| 252274 | +*/ |
| 252275 | +static void sqlite3Fts5ClearLocale(Fts5Config *pConfig){ |
| 252276 | + fts5SetLocale(pConfig, 0, 0); |
| 252277 | +} |
| 252278 | + |
| 252279 | +/* |
| 252280 | +** This function is used to extract utf-8 text from an sqlite3_value. This |
| 252281 | +** is usually done in order to tokenize it. For example, when: |
| 252282 | +** |
| 252283 | +** * a value is written to an fts5 table, |
| 252284 | +** * a value is deleted from an FTS5_CONTENT_NORMAL table, |
| 252285 | +** * a value containing a query expression is passed to xFilter() |
| 252286 | +** |
| 252287 | +** and so on. |
| 252288 | +** |
| 252289 | +** This function handles 2 cases: |
| 252290 | +** |
| 252291 | +** 1) Ordinary values. The text can be extracted from these using |
| 252292 | +** sqlite3_value_text(). |
| 252293 | +** |
| 252294 | +** 2) Combination text/locale blobs created by fts5_locale(). There |
| 252295 | +** are several cases for these: |
| 252296 | +** |
| 252297 | +** * Blobs tagged with FTS5_LOCALE_SUBTYPE. |
| 252298 | +** * Blobs read from the content table of a locale=1 external-content |
| 252299 | +** table, and |
| 252300 | +** * Blobs read from the content table of a locale=1 regular |
| 252301 | +** content table. |
| 252302 | +** |
| 252303 | +** The first two cases above should have the 4 byte FTS5_LOCALE_HEADER |
| 252304 | +** header. It is an error if a blob with the subtype or a blob read |
| 252305 | +** from the content table of an external content table does not have |
| 252306 | +** the required header. A blob read from the content table of a regular |
| 252307 | +** locale=1 table does not have the header. This is to save space. |
| 252308 | +** |
| 252309 | +** If successful, SQLITE_OK is returned and output parameters (*ppText) |
| 252310 | +** and (*pnText) are set to point to a buffer containing the extracted utf-8 |
| 252311 | +** text and its length in bytes, respectively. The buffer is not |
| 252312 | +** nul-terminated. It has the same lifetime as the sqlite3_value object |
| 252313 | +** from which it is extracted. |
| 252314 | +** |
| 252315 | +** Parameter bContent must be true if the value was read from an indexed |
| 252316 | +** column (i.e. not UNINDEXED) of the on disk content. |
| 252317 | +** |
| 252318 | +** If pbResetTokenizer is not NULL and if case (2) is used, then |
| 252319 | +** fts5SetLocale() is called to ensure subsequent sqlite3Fts5Tokenize() calls |
| 252320 | +** use the locale. In this case (*pbResetTokenizer) is set to true before |
| 252321 | +** returning, to indicate that the caller must call sqlite3Fts5ClearLocale() |
| 252322 | +** to clear the locale after tokenizing the text. |
| 252323 | +*/ |
| 252324 | +static int sqlite3Fts5ExtractText( |
| 252325 | + Fts5Config *pConfig, |
| 252326 | + sqlite3_value *pVal, /* Value to extract text from */ |
| 252327 | + int bContent, /* True if indexed table content */ |
| 252328 | + int *pbResetTokenizer, /* OUT: True if xSetLocale(NULL) required */ |
| 252329 | + const char **ppText, /* OUT: Pointer to text buffer */ |
| 252330 | + int *pnText /* OUT: Size of (*ppText) in bytes */ |
| 252331 | +){ |
| 252332 | + const char *pText = 0; |
| 252333 | + int nText = 0; |
| 252334 | + int rc = SQLITE_OK; |
| 252335 | + int bDecodeBlob = 0; |
| 252336 | + |
| 252337 | + assert( pbResetTokenizer==0 || *pbResetTokenizer==0 ); |
| 252338 | + assert( bContent==0 || pConfig->eContent!=FTS5_CONTENT_NONE ); |
| 252339 | + assert( bContent==0 || sqlite3_value_subtype(pVal)==0 ); |
| 252340 | + |
| 252341 | + if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ |
| 252342 | + if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE |
| 252343 | + || (bContent && pConfig->bLocale) |
| 252344 | + ){ |
| 252345 | + bDecodeBlob = 1; |
| 252346 | + } |
| 252347 | + } |
| 252348 | + |
| 252349 | + if( bDecodeBlob ){ |
| 252350 | + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; |
| 252351 | + const u8 *pBlob = sqlite3_value_blob(pVal); |
| 252352 | + int nBlob = sqlite3_value_bytes(pVal); |
| 252353 | + |
| 252354 | + /* Unless this blob was read from the %_content table of an |
| 252355 | + ** FTS5_CONTENT_NORMAL table, it should have the 4 byte fts5_locale() |
| 252356 | + ** header. Check for this. If it is not found, return an error. */ |
| 252357 | + if( (!bContent || pConfig->eContent!=FTS5_CONTENT_NORMAL) ){ |
| 252358 | + if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){ |
| 252359 | + rc = SQLITE_ERROR; |
| 252360 | + }else{ |
| 252361 | + pBlob += 4; |
| 252362 | + nBlob -= 4; |
| 252363 | + } |
| 252364 | + } |
| 252365 | + |
| 252366 | + if( rc==SQLITE_OK ){ |
| 252367 | + int nLocale = 0; |
| 252368 | + |
| 252369 | + for(nLocale=0; nLocale<nBlob; nLocale++){ |
| 252370 | + if( pBlob[nLocale]==0x00 ) break; |
| 252371 | + } |
| 252372 | + if( nLocale==nBlob || nLocale==0 ){ |
| 252373 | + rc = SQLITE_ERROR; |
| 252374 | + }else{ |
| 252375 | + pText = (const char*)&pBlob[nLocale+1]; |
| 252376 | + nText = nBlob-nLocale-1; |
| 252377 | + |
| 252378 | + if( pbResetTokenizer ){ |
| 252379 | + fts5SetLocale(pConfig, (const char*)pBlob, nLocale); |
| 252380 | + *pbResetTokenizer = 1; |
| 252381 | + } |
| 252382 | + } |
| 252383 | + } |
| 252384 | + |
| 252385 | + }else{ |
| 252386 | + pText = (const char*)sqlite3_value_text(pVal); |
| 252387 | + nText = sqlite3_value_bytes(pVal); |
| 252388 | + } |
| 252389 | + |
| 252390 | + *ppText = pText; |
| 252391 | + *pnText = nText; |
| 252392 | + return rc; |
| 252393 | +} |
| 252394 | + |
| 252395 | +/* |
| 252396 | +** Argument pVal is the text of a full-text search expression. It may or |
| 252397 | +** may not have been wrapped by fts5_locale(). This function extracts |
| 252398 | +** the text of the expression, and sets output variable (*pzText) to |
| 252399 | +** point to a nul-terminated buffer containing the expression. |
| 252400 | +** |
| 252401 | +** If pVal was an fts5_locale() value, then fts5SetLocale() is called to |
| 252402 | +** set the tokenizer to use the specified locale. |
| 252403 | +** |
| 252404 | +** If output variable (*pbFreeAndReset) is set to true, then the caller |
| 252405 | +** is required to (a) call sqlite3Fts5ClearLocale() to reset the tokenizer |
| 252406 | +** locale, and (b) call sqlite3_free() to free (*pzText). |
| 252407 | +*/ |
| 252408 | +static int fts5ExtractExprText( |
| 252409 | + Fts5Config *pConfig, /* Fts5 configuration */ |
| 252410 | + sqlite3_value *pVal, /* Value to extract expression text from */ |
| 252411 | + char **pzText, /* OUT: nul-terminated buffer of text */ |
| 252412 | + int *pbFreeAndReset /* OUT: Free (*pzText) and clear locale */ |
| 252413 | +){ |
| 252414 | + const char *zText = 0; |
| 252415 | + int nText = 0; |
| 252416 | + int rc = SQLITE_OK; |
| 252417 | + int bReset = 0; |
| 252418 | + |
| 252419 | + *pbFreeAndReset = 0; |
| 252420 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, &bReset, &zText, &nText); |
| 252421 | + if( rc==SQLITE_OK ){ |
| 252422 | + if( bReset ){ |
| 252423 | + *pzText = sqlite3Fts5Mprintf(&rc, "%.*s", nText, zText); |
| 252424 | + if( rc!=SQLITE_OK ){ |
| 252425 | + sqlite3Fts5ClearLocale(pConfig); |
| 252426 | + }else{ |
| 252427 | + *pbFreeAndReset = 1; |
| 252428 | + } |
| 252429 | + }else{ |
| 252430 | + *pzText = (char*)zText; |
| 252431 | + } |
| 252432 | + } |
| 252433 | + |
| 252434 | + return rc; |
| 252435 | +} |
| 252436 | + |
| 251502 | 252437 | |
| 251503 | 252438 | /* |
| 251504 | 252439 | ** This is the xFilter interface for the virtual table. See |
| 251505 | 252440 | ** the virtual table xFilter method documentation for additional |
| 251506 | 252441 | ** information. |
| | @@ -251532,17 +252467,11 @@ |
| 251532 | 252467 | char **pzErrmsg = pConfig->pzErrmsg; |
| 251533 | 252468 | int i; |
| 251534 | 252469 | int iIdxStr = 0; |
| 251535 | 252470 | Fts5Expr *pExpr = 0; |
| 251536 | 252471 | |
| 251537 | | - if( pConfig->bLock ){ |
| 251538 | | - pTab->p.base.zErrMsg = sqlite3_mprintf( |
| 251539 | | - "recursively defined fts5 content table" |
| 251540 | | - ); |
| 251541 | | - return SQLITE_ERROR; |
| 251542 | | - } |
| 251543 | | - |
| 252472 | + assert( pConfig->bLock==0 ); |
| 251544 | 252473 | if( pCsr->ePlan ){ |
| 251545 | 252474 | fts5FreeCursorComponents(pCsr); |
| 251546 | 252475 | memset(&pCsr->ePlan, 0, sizeof(Fts5Cursor) - ((u8*)&pCsr->ePlan-(u8*)pCsr)); |
| 251547 | 252476 | } |
| 251548 | 252477 | |
| | @@ -251562,12 +252491,18 @@ |
| 251562 | 252491 | switch( idxStr[iIdxStr++] ){ |
| 251563 | 252492 | case 'r': |
| 251564 | 252493 | pRank = apVal[i]; |
| 251565 | 252494 | break; |
| 251566 | 252495 | case 'M': { |
| 251567 | | - const char *zText = (const char*)sqlite3_value_text(apVal[i]); |
| 252496 | + char *zText = 0; |
| 252497 | + int bFreeAndReset = 0; |
| 252498 | + int bInternal = 0; |
| 252499 | + |
| 252500 | + rc = fts5ExtractExprText(pConfig, apVal[i], &zText, &bFreeAndReset); |
| 252501 | + if( rc!=SQLITE_OK ) goto filter_out; |
| 251568 | 252502 | if( zText==0 ) zText = ""; |
| 252503 | + |
| 251569 | 252504 | iCol = 0; |
| 251570 | 252505 | do{ |
| 251571 | 252506 | iCol = iCol*10 + (idxStr[iIdxStr]-'0'); |
| 251572 | 252507 | iIdxStr++; |
| 251573 | 252508 | }while( idxStr[iIdxStr]>='0' && idxStr[iIdxStr]<='9' ); |
| | @@ -251575,21 +252510,27 @@ |
| 251575 | 252510 | if( zText[0]=='*' ){ |
| 251576 | 252511 | /* The user has issued a query of the form "MATCH '*...'". This |
| 251577 | 252512 | ** indicates that the MATCH expression is not a full text query, |
| 251578 | 252513 | ** but a request for an internal parameter. */ |
| 251579 | 252514 | rc = fts5SpecialMatch(pTab, pCsr, &zText[1]); |
| 251580 | | - goto filter_out; |
| 252515 | + bInternal = 1; |
| 251581 | 252516 | }else{ |
| 251582 | 252517 | char **pzErr = &pTab->p.base.zErrMsg; |
| 251583 | 252518 | rc = sqlite3Fts5ExprNew(pConfig, 0, iCol, zText, &pExpr, pzErr); |
| 251584 | 252519 | if( rc==SQLITE_OK ){ |
| 251585 | 252520 | rc = sqlite3Fts5ExprAnd(&pCsr->pExpr, pExpr); |
| 251586 | 252521 | pExpr = 0; |
| 251587 | 252522 | } |
| 251588 | | - if( rc!=SQLITE_OK ) goto filter_out; |
| 251589 | 252523 | } |
| 251590 | 252524 | |
| 252525 | + if( bFreeAndReset ){ |
| 252526 | + sqlite3_free(zText); |
| 252527 | + sqlite3Fts5ClearLocale(pConfig); |
| 252528 | + } |
| 252529 | + |
| 252530 | + if( bInternal || rc!=SQLITE_OK ) goto filter_out; |
| 252531 | + |
| 251591 | 252532 | break; |
| 251592 | 252533 | } |
| 251593 | 252534 | case 'L': |
| 251594 | 252535 | case 'G': { |
| 251595 | 252536 | int bGlob = (idxStr[iIdxStr-1]=='G'); |
| | @@ -251893,11 +252834,11 @@ |
| 251893 | 252834 | ){ |
| 251894 | 252835 | int rc = SQLITE_OK; |
| 251895 | 252836 | int eType1 = sqlite3_value_type(apVal[1]); |
| 251896 | 252837 | if( eType1==SQLITE_INTEGER ){ |
| 251897 | 252838 | sqlite3_int64 iDel = sqlite3_value_int64(apVal[1]); |
| 251898 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2]); |
| 252839 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, &apVal[2], 0); |
| 251899 | 252840 | } |
| 251900 | 252841 | return rc; |
| 251901 | 252842 | } |
| 251902 | 252843 | |
| 251903 | 252844 | static void fts5StorageInsert( |
| | @@ -252017,59 +252958,81 @@ |
| 252017 | 252958 | } |
| 252018 | 252959 | |
| 252019 | 252960 | /* DELETE */ |
| 252020 | 252961 | else if( nArg==1 ){ |
| 252021 | 252962 | i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */ |
| 252022 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0); |
| 252963 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0, 0); |
| 252023 | 252964 | bUpdateOrDelete = 1; |
| 252024 | 252965 | } |
| 252025 | 252966 | |
| 252026 | 252967 | /* INSERT or UPDATE */ |
| 252027 | 252968 | else{ |
| 252028 | 252969 | int eType1 = sqlite3_value_numeric_type(apVal[1]); |
| 252029 | 252970 | |
| 252030 | | - if( eType1!=SQLITE_INTEGER && eType1!=SQLITE_NULL ){ |
| 252031 | | - rc = SQLITE_MISMATCH; |
| 252971 | + /* Ensure that no fts5_locale() values are written to locale=0 tables. |
| 252972 | + ** And that no blobs except fts5_locale() blobs are written to indexed |
| 252973 | + ** (i.e. not UNINDEXED) columns of locale=1 tables. */ |
| 252974 | + int ii; |
| 252975 | + for(ii=0; ii<pConfig->nCol; ii++){ |
| 252976 | + if( sqlite3_value_type(apVal[ii+2])==SQLITE_BLOB ){ |
| 252977 | + int bSub = (sqlite3_value_subtype(apVal[ii+2])==FTS5_LOCALE_SUBTYPE); |
| 252978 | + if( (pConfig->bLocale && !bSub && pConfig->abUnindexed[ii]==0) |
| 252979 | + || (pConfig->bLocale==0 && bSub) |
| 252980 | + ){ |
| 252981 | + if( pConfig->bLocale==0 ){ |
| 252982 | + fts5SetVtabError(pTab, "fts5_locale() requires locale=1"); |
| 252983 | + } |
| 252984 | + rc = SQLITE_MISMATCH; |
| 252985 | + goto update_out; |
| 252986 | + } |
| 252987 | + } |
| 252032 | 252988 | } |
| 252033 | 252989 | |
| 252034 | | - else if( eType0!=SQLITE_INTEGER ){ |
| 252990 | + if( eType0!=SQLITE_INTEGER ){ |
| 252035 | 252991 | /* An INSERT statement. If the conflict-mode is REPLACE, first remove |
| 252036 | 252992 | ** the current entry (if any). */ |
| 252037 | 252993 | if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){ |
| 252038 | 252994 | i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */ |
| 252039 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 252995 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); |
| 252040 | 252996 | bUpdateOrDelete = 1; |
| 252041 | 252997 | } |
| 252042 | 252998 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 252043 | 252999 | } |
| 252044 | 253000 | |
| 252045 | 253001 | /* UPDATE */ |
| 252046 | 253002 | else{ |
| 252047 | 253003 | i64 iOld = sqlite3_value_int64(apVal[0]); /* Old rowid */ |
| 252048 | 253004 | i64 iNew = sqlite3_value_int64(apVal[1]); /* New rowid */ |
| 252049 | | - if( eType1==SQLITE_INTEGER && iOld!=iNew ){ |
| 253005 | + if( eType1!=SQLITE_INTEGER ){ |
| 253006 | + rc = SQLITE_MISMATCH; |
| 253007 | + }else if( iOld!=iNew ){ |
| 252050 | 253008 | if( eConflict==SQLITE_REPLACE ){ |
| 252051 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 253009 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); |
| 252052 | 253010 | if( rc==SQLITE_OK ){ |
| 252053 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0); |
| 253011 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0, 0); |
| 252054 | 253012 | } |
| 252055 | 253013 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 252056 | 253014 | }else{ |
| 252057 | | - rc = sqlite3Fts5StorageContentInsert(pTab->pStorage, apVal, pRowid); |
| 253015 | + rc = sqlite3Fts5StorageFindDeleteRow(pTab->pStorage, iOld); |
| 253016 | + if( rc==SQLITE_OK ){ |
| 253017 | + rc = sqlite3Fts5StorageContentInsert(pTab->pStorage,apVal,pRowid); |
| 253018 | + } |
| 252058 | 253019 | if( rc==SQLITE_OK ){ |
| 252059 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 253020 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); |
| 252060 | 253021 | } |
| 252061 | 253022 | if( rc==SQLITE_OK ){ |
| 252062 | 253023 | rc = sqlite3Fts5StorageIndexInsert(pTab->pStorage, apVal,*pRowid); |
| 252063 | 253024 | } |
| 252064 | 253025 | } |
| 252065 | 253026 | }else{ |
| 252066 | | - rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0); |
| 253027 | + rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0, 1); |
| 252067 | 253028 | fts5StorageInsert(&rc, pTab, apVal, pRowid); |
| 252068 | 253029 | } |
| 252069 | 253030 | bUpdateOrDelete = 1; |
| 253031 | + sqlite3Fts5StorageReleaseDeleteRow(pTab->pStorage); |
| 252070 | 253032 | } |
| 253033 | + |
| 252071 | 253034 | } |
| 252072 | 253035 | } |
| 252073 | 253036 | |
| 252074 | 253037 | if( rc==SQLITE_OK |
| 252075 | 253038 | && bUpdateOrDelete |
| | @@ -252082,10 +253045,11 @@ |
| 252082 | 253045 | if( rc==SQLITE_OK ){ |
| 252083 | 253046 | pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE; |
| 252084 | 253047 | } |
| 252085 | 253048 | } |
| 252086 | 253049 | |
| 253050 | + update_out: |
| 252087 | 253051 | pTab->p.pConfig->pzErrmsg = 0; |
| 252088 | 253052 | return rc; |
| 252089 | 253053 | } |
| 252090 | 253054 | |
| 252091 | 253055 | /* |
| | @@ -252159,21 +253123,44 @@ |
| 252159 | 253123 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 252160 | 253124 | Fts5FullTable *pTab = (Fts5FullTable*)(pCsr->base.pVtab); |
| 252161 | 253125 | return sqlite3Fts5StorageRowCount(pTab->pStorage, pnRow); |
| 252162 | 253126 | } |
| 252163 | 253127 | |
| 253128 | +/* |
| 253129 | +** Implementation of xTokenize_v2() API. |
| 253130 | +*/ |
| 253131 | +static int fts5ApiTokenize_v2( |
| 253132 | + Fts5Context *pCtx, |
| 253133 | + const char *pText, int nText, |
| 253134 | + const char *pLoc, int nLoc, |
| 253135 | + void *pUserData, |
| 253136 | + int (*xToken)(void*, int, const char*, int, int, int) |
| 253137 | +){ |
| 253138 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 253139 | + Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 253140 | + int rc = SQLITE_OK; |
| 253141 | + |
| 253142 | + fts5SetLocale(pTab->pConfig, pLoc, nLoc); |
| 253143 | + rc = sqlite3Fts5Tokenize(pTab->pConfig, |
| 253144 | + FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken |
| 253145 | + ); |
| 253146 | + fts5SetLocale(pTab->pConfig, 0, 0); |
| 253147 | + |
| 253148 | + return rc; |
| 253149 | +} |
| 253150 | + |
| 253151 | +/* |
| 253152 | +** Implementation of xTokenize() API. This is just xTokenize_v2() with NULL/0 |
| 253153 | +** passed as the locale. |
| 253154 | +*/ |
| 252164 | 253155 | static int fts5ApiTokenize( |
| 252165 | 253156 | Fts5Context *pCtx, |
| 252166 | 253157 | const char *pText, int nText, |
| 252167 | 253158 | void *pUserData, |
| 252168 | 253159 | int (*xToken)(void*, int, const char*, int, int, int) |
| 252169 | 253160 | ){ |
| 252170 | | - Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 252171 | | - Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 252172 | | - return sqlite3Fts5Tokenize( |
| 252173 | | - pTab->pConfig, FTS5_TOKENIZE_AUX, pText, nText, pUserData, xToken |
| 252174 | | - ); |
| 253161 | + return fts5ApiTokenize_v2(pCtx, pText, nText, 0, 0, pUserData, xToken); |
| 252175 | 253162 | } |
| 252176 | 253163 | |
| 252177 | 253164 | static int fts5ApiPhraseCount(Fts5Context *pCtx){ |
| 252178 | 253165 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 252179 | 253166 | return sqlite3Fts5ExprPhraseCount(pCsr->pExpr); |
| | @@ -252191,53 +253178,76 @@ |
| 252191 | 253178 | int *pn |
| 252192 | 253179 | ){ |
| 252193 | 253180 | int rc = SQLITE_OK; |
| 252194 | 253181 | Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 252195 | 253182 | Fts5Table *pTab = (Fts5Table*)(pCsr->base.pVtab); |
| 253183 | + |
| 253184 | + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); |
| 252196 | 253185 | if( iCol<0 || iCol>=pTab->pConfig->nCol ){ |
| 252197 | 253186 | rc = SQLITE_RANGE; |
| 252198 | | - }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) |
| 252199 | | - || pCsr->ePlan==FTS5_PLAN_SPECIAL |
| 252200 | | - ){ |
| 253187 | + }else if( fts5IsContentless((Fts5FullTable*)(pCsr->base.pVtab)) ){ |
| 252201 | 253188 | *pz = 0; |
| 252202 | 253189 | *pn = 0; |
| 252203 | 253190 | }else{ |
| 252204 | 253191 | rc = fts5SeekCursor(pCsr, 0); |
| 252205 | 253192 | if( rc==SQLITE_OK ){ |
| 252206 | | - *pz = (const char*)sqlite3_column_text(pCsr->pStmt, iCol+1); |
| 252207 | | - *pn = sqlite3_column_bytes(pCsr->pStmt, iCol+1); |
| 253193 | + Fts5Config *pConfig = pTab->pConfig; |
| 253194 | + int bContent = (pConfig->abUnindexed[iCol]==0); |
| 253195 | + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); |
| 253196 | + sqlite3Fts5ExtractText(pConfig, pVal, bContent, 0, pz, pn); |
| 252208 | 253197 | } |
| 252209 | 253198 | } |
| 252210 | 253199 | return rc; |
| 252211 | 253200 | } |
| 252212 | 253201 | |
| 253202 | +/* |
| 253203 | +** This is called by various API functions - xInst, xPhraseFirst, |
| 253204 | +** xPhraseFirstColumn etc. - to obtain the position list for phrase iPhrase |
| 253205 | +** of the current row. This function works for both detail=full tables (in |
| 253206 | +** which case the position-list was read from the fts index) or for other |
| 253207 | +** detail= modes if the row content is available. |
| 253208 | +*/ |
| 252213 | 253209 | static int fts5CsrPoslist( |
| 252214 | | - Fts5Cursor *pCsr, |
| 252215 | | - int iPhrase, |
| 252216 | | - const u8 **pa, |
| 252217 | | - int *pn |
| 253210 | + Fts5Cursor *pCsr, /* Fts5 cursor object */ |
| 253211 | + int iPhrase, /* Phrase to find position list for */ |
| 253212 | + const u8 **pa, /* OUT: Pointer to position list buffer */ |
| 253213 | + int *pn /* OUT: Size of (*pa) in bytes */ |
| 252218 | 253214 | ){ |
| 252219 | 253215 | Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 252220 | 253216 | int rc = SQLITE_OK; |
| 252221 | 253217 | int bLive = (pCsr->pSorter==0); |
| 252222 | 253218 | |
| 252223 | 253219 | if( iPhrase<0 || iPhrase>=sqlite3Fts5ExprPhraseCount(pCsr->pExpr) ){ |
| 252224 | 253220 | rc = SQLITE_RANGE; |
| 253221 | + }else if( pConfig->eDetail!=FTS5_DETAIL_FULL |
| 253222 | + && pConfig->eContent==FTS5_CONTENT_NONE |
| 253223 | + ){ |
| 253224 | + *pa = 0; |
| 253225 | + *pn = 0; |
| 253226 | + return SQLITE_OK; |
| 252225 | 253227 | }else if( CsrFlagTest(pCsr, FTS5CSR_REQUIRE_POSLIST) ){ |
| 252226 | 253228 | if( pConfig->eDetail!=FTS5_DETAIL_FULL ){ |
| 252227 | 253229 | Fts5PoslistPopulator *aPopulator; |
| 252228 | 253230 | int i; |
| 253231 | + |
| 252229 | 253232 | aPopulator = sqlite3Fts5ExprClearPoslists(pCsr->pExpr, bLive); |
| 252230 | 253233 | if( aPopulator==0 ) rc = SQLITE_NOMEM; |
| 253234 | + if( rc==SQLITE_OK ){ |
| 253235 | + rc = fts5SeekCursor(pCsr, 0); |
| 253236 | + } |
| 252231 | 253237 | for(i=0; i<pConfig->nCol && rc==SQLITE_OK; i++){ |
| 252232 | | - int n; const char *z; |
| 252233 | | - rc = fts5ApiColumnText((Fts5Context*)pCsr, i, &z, &n); |
| 253238 | + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); |
| 253239 | + const char *z = 0; |
| 253240 | + int n = 0; |
| 253241 | + int bReset = 0; |
| 253242 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); |
| 252234 | 253243 | if( rc==SQLITE_OK ){ |
| 252235 | 253244 | rc = sqlite3Fts5ExprPopulatePoslists( |
| 252236 | 253245 | pConfig, pCsr->pExpr, aPopulator, i, z, n |
| 252237 | 253246 | ); |
| 252238 | 253247 | } |
| 253248 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 252239 | 253249 | } |
| 252240 | 253250 | sqlite3_free(aPopulator); |
| 252241 | 253251 | |
| 252242 | 253252 | if( pCsr->pSorter ){ |
| 252243 | 253253 | sqlite3Fts5ExprCheckPoslists(pCsr->pExpr, pCsr->pSorter->iRowid); |
| | @@ -252257,11 +253267,10 @@ |
| 252257 | 253267 | } |
| 252258 | 253268 | }else{ |
| 252259 | 253269 | *pa = 0; |
| 252260 | 253270 | *pn = 0; |
| 252261 | 253271 | } |
| 252262 | | - |
| 252263 | 253272 | |
| 252264 | 253273 | return rc; |
| 252265 | 253274 | } |
| 252266 | 253275 | |
| 252267 | 253276 | /* |
| | @@ -252327,11 +253336,12 @@ |
| 252327 | 253336 | |
| 252328 | 253337 | aInst = &pCsr->aInst[3 * (nInst-1)]; |
| 252329 | 253338 | aInst[0] = iBest; |
| 252330 | 253339 | aInst[1] = FTS5_POS2COLUMN(aIter[iBest].iPos); |
| 252331 | 253340 | aInst[2] = FTS5_POS2OFFSET(aIter[iBest].iPos); |
| 252332 | | - if( aInst[1]<0 || aInst[1]>=nCol ){ |
| 253341 | + assert( aInst[1]>=0 ); |
| 253342 | + if( aInst[1]>=nCol ){ |
| 252333 | 253343 | rc = FTS5_CORRUPT; |
| 252334 | 253344 | break; |
| 252335 | 253345 | } |
| 252336 | 253346 | sqlite3Fts5PoslistReaderNext(&aIter[iBest]); |
| 252337 | 253347 | } |
| | @@ -252414,20 +253424,25 @@ |
| 252414 | 253424 | pCsr->aColumnSize[i] = -1; |
| 252415 | 253425 | } |
| 252416 | 253426 | } |
| 252417 | 253427 | }else{ |
| 252418 | 253428 | int i; |
| 253429 | + rc = fts5SeekCursor(pCsr, 0); |
| 252419 | 253430 | for(i=0; rc==SQLITE_OK && i<pConfig->nCol; i++){ |
| 252420 | 253431 | if( pConfig->abUnindexed[i]==0 ){ |
| 252421 | | - const char *z; int n; |
| 252422 | | - void *p = (void*)(&pCsr->aColumnSize[i]); |
| 253432 | + const char *z = 0; |
| 253433 | + int n = 0; |
| 253434 | + int bReset = 0; |
| 253435 | + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, i+1); |
| 253436 | + |
| 252423 | 253437 | pCsr->aColumnSize[i] = 0; |
| 252424 | | - rc = fts5ApiColumnText(pCtx, i, &z, &n); |
| 253438 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &z, &n); |
| 252425 | 253439 | if( rc==SQLITE_OK ){ |
| 252426 | | - rc = sqlite3Fts5Tokenize( |
| 252427 | | - pConfig, FTS5_TOKENIZE_AUX, z, n, p, fts5ColumnSizeCb |
| 253440 | + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_AUX, |
| 253441 | + z, n, (void*)&pCsr->aColumnSize[i], fts5ColumnSizeCb |
| 252428 | 253442 | ); |
| 253443 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 252429 | 253444 | } |
| 252430 | 253445 | } |
| 252431 | 253446 | } |
| 252432 | 253447 | } |
| 252433 | 253448 | CsrFlagClear(pCsr, FTS5CSR_REQUIRE_DOCSIZE); |
| | @@ -252669,13 +253684,76 @@ |
| 252669 | 253684 | |
| 252670 | 253685 | |
| 252671 | 253686 | static int fts5ApiQueryPhrase(Fts5Context*, int, void*, |
| 252672 | 253687 | int(*)(const Fts5ExtensionApi*, Fts5Context*, void*) |
| 252673 | 253688 | ); |
| 253689 | + |
| 253690 | +/* |
| 253691 | +** The xColumnLocale() API. |
| 253692 | +*/ |
| 253693 | +static int fts5ApiColumnLocale( |
| 253694 | + Fts5Context *pCtx, |
| 253695 | + int iCol, |
| 253696 | + const char **pzLocale, |
| 253697 | + int *pnLocale |
| 253698 | +){ |
| 253699 | + int rc = SQLITE_OK; |
| 253700 | + Fts5Cursor *pCsr = (Fts5Cursor*)pCtx; |
| 253701 | + Fts5Config *pConfig = ((Fts5Table*)(pCsr->base.pVtab))->pConfig; |
| 253702 | + |
| 253703 | + *pzLocale = 0; |
| 253704 | + *pnLocale = 0; |
| 253705 | + |
| 253706 | + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); |
| 253707 | + if( iCol<0 || iCol>=pConfig->nCol ){ |
| 253708 | + rc = SQLITE_RANGE; |
| 253709 | + }else if( |
| 253710 | + pConfig->abUnindexed[iCol]==0 |
| 253711 | + && pConfig->eContent!=FTS5_CONTENT_NONE |
| 253712 | + && pConfig->bLocale |
| 253713 | + ){ |
| 253714 | + rc = fts5SeekCursor(pCsr, 0); |
| 253715 | + if( rc==SQLITE_OK ){ |
| 253716 | + /* Load the value into pVal. pVal is a locale/text pair iff: |
| 253717 | + ** |
| 253718 | + ** 1) It is an SQLITE_BLOB, and |
| 253719 | + ** 2) Either the subtype is FTS5_LOCALE_SUBTYPE, or else the |
| 253720 | + ** value was loaded from an FTS5_CONTENT_NORMAL table, and |
| 253721 | + ** 3) It does not begin with an 0x00 byte. |
| 253722 | + */ |
| 253723 | + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); |
| 253724 | + if( sqlite3_value_type(pVal)==SQLITE_BLOB ){ |
| 253725 | + const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); |
| 253726 | + int nBlob = sqlite3_value_bytes(pVal); |
| 253727 | + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ |
| 253728 | + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; |
| 253729 | + if( nBlob<SZHDR || memcmp(FTS5_LOCALE_HEADER, pBlob, SZHDR) ){ |
| 253730 | + rc = SQLITE_ERROR; |
| 253731 | + } |
| 253732 | + pBlob += 4; |
| 253733 | + nBlob -= 4; |
| 253734 | + } |
| 253735 | + if( rc==SQLITE_OK ){ |
| 253736 | + int nLocale = 0; |
| 253737 | + for(nLocale=0; nLocale<nBlob && pBlob[nLocale]!=0x00; nLocale++); |
| 253738 | + if( nLocale==nBlob || nLocale==0 ){ |
| 253739 | + rc = SQLITE_ERROR; |
| 253740 | + }else{ |
| 253741 | + /* A locale/text pair */ |
| 253742 | + *pzLocale = (const char*)pBlob; |
| 253743 | + *pnLocale = nLocale; |
| 253744 | + } |
| 253745 | + } |
| 253746 | + } |
| 253747 | + } |
| 253748 | + } |
| 253749 | + |
| 253750 | + return rc; |
| 253751 | +} |
| 252674 | 253752 | |
| 252675 | 253753 | static const Fts5ExtensionApi sFts5Api = { |
| 252676 | | - 3, /* iVersion */ |
| 253754 | + 4, /* iVersion */ |
| 252677 | 253755 | fts5ApiUserData, |
| 252678 | 253756 | fts5ApiColumnCount, |
| 252679 | 253757 | fts5ApiRowCount, |
| 252680 | 253758 | fts5ApiColumnTotalSize, |
| 252681 | 253759 | fts5ApiTokenize, |
| | @@ -252692,11 +253770,13 @@ |
| 252692 | 253770 | fts5ApiPhraseFirst, |
| 252693 | 253771 | fts5ApiPhraseNext, |
| 252694 | 253772 | fts5ApiPhraseFirstColumn, |
| 252695 | 253773 | fts5ApiPhraseNextColumn, |
| 252696 | 253774 | fts5ApiQueryToken, |
| 252697 | | - fts5ApiInstToken |
| 253775 | + fts5ApiInstToken, |
| 253776 | + fts5ApiColumnLocale, |
| 253777 | + fts5ApiTokenize_v2 |
| 252698 | 253778 | }; |
| 252699 | 253779 | |
| 252700 | 253780 | /* |
| 252701 | 253781 | ** Implementation of API function xQueryPhrase(). |
| 252702 | 253782 | */ |
| | @@ -252743,10 +253823,11 @@ |
| 252743 | 253823 | sqlite3_context *context, |
| 252744 | 253824 | int argc, |
| 252745 | 253825 | sqlite3_value **argv |
| 252746 | 253826 | ){ |
| 252747 | 253827 | assert( pCsr->pAux==0 ); |
| 253828 | + assert( pCsr->ePlan!=FTS5_PLAN_SPECIAL ); |
| 252748 | 253829 | pCsr->pAux = pAux; |
| 252749 | 253830 | pAux->xFunc(&sFts5Api, (Fts5Context*)pCsr, context, argc, argv); |
| 252750 | 253831 | pCsr->pAux = 0; |
| 252751 | 253832 | } |
| 252752 | 253833 | |
| | @@ -252755,10 +253836,25 @@ |
| 252755 | 253836 | for(pCsr=pGlobal->pCsr; pCsr; pCsr=pCsr->pNext){ |
| 252756 | 253837 | if( pCsr->iCsrId==iCsrId ) break; |
| 252757 | 253838 | } |
| 252758 | 253839 | return pCsr; |
| 252759 | 253840 | } |
| 253841 | + |
| 253842 | +/* |
| 253843 | +** Parameter zFmt is a printf() style formatting string. This function |
| 253844 | +** formats it using the trailing arguments and returns the result as |
| 253845 | +** an error message to the context passed as the first argument. |
| 253846 | +*/ |
| 253847 | +static void fts5ResultError(sqlite3_context *pCtx, const char *zFmt, ...){ |
| 253848 | + char *zErr = 0; |
| 253849 | + va_list ap; |
| 253850 | + va_start(ap, zFmt); |
| 253851 | + zErr = sqlite3_vmprintf(zFmt, ap); |
| 253852 | + sqlite3_result_error(pCtx, zErr, -1); |
| 253853 | + sqlite3_free(zErr); |
| 253854 | + va_end(ap); |
| 253855 | +} |
| 252760 | 253856 | |
| 252761 | 253857 | static void fts5ApiCallback( |
| 252762 | 253858 | sqlite3_context *context, |
| 252763 | 253859 | int argc, |
| 252764 | 253860 | sqlite3_value **argv |
| | @@ -252771,14 +253867,12 @@ |
| 252771 | 253867 | assert( argc>=1 ); |
| 252772 | 253868 | pAux = (Fts5Auxiliary*)sqlite3_user_data(context); |
| 252773 | 253869 | iCsrId = sqlite3_value_int64(argv[0]); |
| 252774 | 253870 | |
| 252775 | 253871 | pCsr = fts5CursorFromCsrid(pAux->pGlobal, iCsrId); |
| 252776 | | - if( pCsr==0 || pCsr->ePlan==0 ){ |
| 252777 | | - char *zErr = sqlite3_mprintf("no such cursor: %lld", iCsrId); |
| 252778 | | - sqlite3_result_error(context, zErr, -1); |
| 252779 | | - sqlite3_free(zErr); |
| 253872 | + if( pCsr==0 || (pCsr->ePlan==0 || pCsr->ePlan==FTS5_PLAN_SPECIAL) ){ |
| 253873 | + fts5ResultError(context, "no such cursor: %lld", iCsrId); |
| 252780 | 253874 | }else{ |
| 252781 | 253875 | sqlite3_vtab *pTab = pCsr->base.pVtab; |
| 252782 | 253876 | fts5ApiInvoke(pAux, pCsr, context, argc-1, &argv[1]); |
| 252783 | 253877 | sqlite3_free(pTab->zErrMsg); |
| 252784 | 253878 | pTab->zErrMsg = 0; |
| | @@ -252867,10 +253961,61 @@ |
| 252867 | 253961 | } |
| 252868 | 253962 | |
| 252869 | 253963 | sqlite3_result_blob(pCtx, val.p, val.n, sqlite3_free); |
| 252870 | 253964 | return rc; |
| 252871 | 253965 | } |
| 253966 | + |
| 253967 | +/* |
| 253968 | +** Value pVal was read from column iCol of the FTS5 table. This function |
| 253969 | +** returns it to the owner of pCtx via a call to an sqlite3_result_xxx() |
| 253970 | +** function. This function deals with the same cases as |
| 253971 | +** sqlite3Fts5ExtractText(): |
| 253972 | +** |
| 253973 | +** 1) Ordinary values. These can be returned using sqlite3_result_value(). |
| 253974 | +** |
| 253975 | +** 2) Blobs from fts5_locale(). The text is extracted from these and |
| 253976 | +** returned via sqlite3_result_text(). The locale is discarded. |
| 253977 | +*/ |
| 253978 | +static void fts5ExtractValueFromColumn( |
| 253979 | + sqlite3_context *pCtx, |
| 253980 | + Fts5Config *pConfig, |
| 253981 | + int iCol, |
| 253982 | + sqlite3_value *pVal |
| 253983 | +){ |
| 253984 | + assert( pConfig->eContent!=FTS5_CONTENT_NONE ); |
| 253985 | + |
| 253986 | + if( pConfig->bLocale |
| 253987 | + && sqlite3_value_type(pVal)==SQLITE_BLOB |
| 253988 | + && pConfig->abUnindexed[iCol]==0 |
| 253989 | + ){ |
| 253990 | + const int SZHDR = sizeof(FTS5_LOCALE_HEADER)-1; |
| 253991 | + const u8 *pBlob = sqlite3_value_blob(pVal); |
| 253992 | + int nBlob = sqlite3_value_bytes(pVal); |
| 253993 | + int ii; |
| 253994 | + |
| 253995 | + if( pConfig->eContent==FTS5_CONTENT_EXTERNAL ){ |
| 253996 | + if( nBlob<SZHDR || memcmp(pBlob, FTS5_LOCALE_HEADER, SZHDR) ){ |
| 253997 | + sqlite3_result_error_code(pCtx, SQLITE_ERROR); |
| 253998 | + return; |
| 253999 | + }else{ |
| 254000 | + pBlob += 4; |
| 254001 | + nBlob -= 4; |
| 254002 | + } |
| 254003 | + } |
| 254004 | + |
| 254005 | + for(ii=0; ii<nBlob && pBlob[ii]; ii++); |
| 254006 | + if( ii==0 || ii==nBlob ){ |
| 254007 | + sqlite3_result_error_code(pCtx, SQLITE_ERROR); |
| 254008 | + }else{ |
| 254009 | + const char *pText = (const char*)&pBlob[ii+1]; |
| 254010 | + sqlite3_result_text(pCtx, pText, nBlob-ii-1, SQLITE_TRANSIENT); |
| 254011 | + } |
| 254012 | + return; |
| 254013 | + } |
| 254014 | + |
| 254015 | + sqlite3_result_value(pCtx, pVal); |
| 254016 | +} |
| 252872 | 254017 | |
| 252873 | 254018 | /* |
| 252874 | 254019 | ** This is the xColumn method, called by SQLite to request a value from |
| 252875 | 254020 | ** the row that the supplied cursor currently points to. |
| 252876 | 254021 | */ |
| | @@ -252897,12 +254042,12 @@ |
| 252897 | 254042 | ** as the table. Return the cursor integer id number. This value is only |
| 252898 | 254043 | ** useful in that it may be passed as the first argument to an FTS5 |
| 252899 | 254044 | ** auxiliary function. */ |
| 252900 | 254045 | sqlite3_result_int64(pCtx, pCsr->iCsrId); |
| 252901 | 254046 | }else if( iCol==pConfig->nCol+1 ){ |
| 252902 | | - |
| 252903 | 254047 | /* The value of the "rank" column. */ |
| 254048 | + |
| 252904 | 254049 | if( pCsr->ePlan==FTS5_PLAN_SOURCE ){ |
| 252905 | 254050 | fts5PoslistBlob(pCtx, pCsr); |
| 252906 | 254051 | }else if( |
| 252907 | 254052 | pCsr->ePlan==FTS5_PLAN_MATCH |
| 252908 | 254053 | || pCsr->ePlan==FTS5_PLAN_SORTED_MATCH |
| | @@ -252909,24 +254054,31 @@ |
| 252909 | 254054 | ){ |
| 252910 | 254055 | if( pCsr->pRank || SQLITE_OK==(rc = fts5FindRankFunction(pCsr)) ){ |
| 252911 | 254056 | fts5ApiInvoke(pCsr->pRank, pCsr, pCtx, pCsr->nRankArg, pCsr->apRankArg); |
| 252912 | 254057 | } |
| 252913 | 254058 | } |
| 252914 | | - }else if( !fts5IsContentless(pTab) ){ |
| 252915 | | - pConfig->pzErrmsg = &pTab->p.base.zErrMsg; |
| 252916 | | - rc = fts5SeekCursor(pCsr, 1); |
| 252917 | | - if( rc==SQLITE_OK ){ |
| 252918 | | - sqlite3_result_value(pCtx, sqlite3_column_value(pCsr->pStmt, iCol+1)); |
| 252919 | | - } |
| 252920 | | - pConfig->pzErrmsg = 0; |
| 252921 | | - }else if( pConfig->bContentlessDelete && sqlite3_vtab_nochange(pCtx) ){ |
| 252922 | | - char *zErr = sqlite3_mprintf("cannot UPDATE a subset of " |
| 252923 | | - "columns on fts5 contentless-delete table: %s", pConfig->zName |
| 252924 | | - ); |
| 252925 | | - sqlite3_result_error(pCtx, zErr, -1); |
| 252926 | | - sqlite3_free(zErr); |
| 252927 | | - } |
| 254059 | + }else{ |
| 254060 | + /* A column created by the user containing values. */ |
| 254061 | + int bNochange = sqlite3_vtab_nochange(pCtx); |
| 254062 | + |
| 254063 | + if( fts5IsContentless(pTab) ){ |
| 254064 | + if( bNochange && pConfig->bContentlessDelete ){ |
| 254065 | + fts5ResultError(pCtx, "cannot UPDATE a subset of " |
| 254066 | + "columns on fts5 contentless-delete table: %s", pConfig->zName |
| 254067 | + ); |
| 254068 | + } |
| 254069 | + }else if( bNochange==0 || pConfig->eContent!=FTS5_CONTENT_NORMAL ){ |
| 254070 | + pConfig->pzErrmsg = &pTab->p.base.zErrMsg; |
| 254071 | + rc = fts5SeekCursor(pCsr, 1); |
| 254072 | + if( rc==SQLITE_OK ){ |
| 254073 | + sqlite3_value *pVal = sqlite3_column_value(pCsr->pStmt, iCol+1); |
| 254074 | + fts5ExtractValueFromColumn(pCtx, pConfig, iCol, pVal); |
| 254075 | + } |
| 254076 | + pConfig->pzErrmsg = 0; |
| 254077 | + } |
| 254078 | + } |
| 254079 | + |
| 252928 | 254080 | return rc; |
| 252929 | 254081 | } |
| 252930 | 254082 | |
| 252931 | 254083 | |
| 252932 | 254084 | /* |
| | @@ -253060,53 +254212,214 @@ |
| 253060 | 254212 | } |
| 253061 | 254213 | } |
| 253062 | 254214 | |
| 253063 | 254215 | return rc; |
| 253064 | 254216 | } |
| 254217 | + |
| 254218 | +/* |
| 254219 | +** This function is used by xCreateTokenizer_v2() and xCreateTokenizer(). |
| 254220 | +** It allocates and partially populates a new Fts5TokenizerModule object. |
| 254221 | +** The new object is already linked into the Fts5Global context before |
| 254222 | +** returning. |
| 254223 | +** |
| 254224 | +** If successful, SQLITE_OK is returned and a pointer to the new |
| 254225 | +** Fts5TokenizerModule object returned via output parameter (*ppNew). All |
| 254226 | +** that is required is for the caller to fill in the methods in |
| 254227 | +** Fts5TokenizerModule.x1 and x2, and to set Fts5TokenizerModule.bV2Native |
| 254228 | +** as appropriate. |
| 254229 | +** |
| 254230 | +** If an error occurs, an SQLite error code is returned and the final value |
| 254231 | +** of (*ppNew) undefined. |
| 254232 | +*/ |
| 254233 | +static int fts5NewTokenizerModule( |
| 254234 | + Fts5Global *pGlobal, /* Global context (one per db handle) */ |
| 254235 | + const char *zName, /* Name of new function */ |
| 254236 | + void *pUserData, /* User data for aux. function */ |
| 254237 | + void(*xDestroy)(void*), /* Destructor for pUserData */ |
| 254238 | + Fts5TokenizerModule **ppNew |
| 254239 | +){ |
| 254240 | + int rc = SQLITE_OK; |
| 254241 | + Fts5TokenizerModule *pNew; |
| 254242 | + sqlite3_int64 nName; /* Size of zName and its \0 terminator */ |
| 254243 | + sqlite3_int64 nByte; /* Bytes of space to allocate */ |
| 254244 | + |
| 254245 | + nName = strlen(zName) + 1; |
| 254246 | + nByte = sizeof(Fts5TokenizerModule) + nName; |
| 254247 | + *ppNew = pNew = (Fts5TokenizerModule*)sqlite3Fts5MallocZero(&rc, nByte); |
| 254248 | + if( pNew ){ |
| 254249 | + pNew->zName = (char*)&pNew[1]; |
| 254250 | + memcpy(pNew->zName, zName, nName); |
| 254251 | + pNew->pUserData = pUserData; |
| 254252 | + pNew->xDestroy = xDestroy; |
| 254253 | + pNew->pNext = pGlobal->pTok; |
| 254254 | + pGlobal->pTok = pNew; |
| 254255 | + if( pNew->pNext==0 ){ |
| 254256 | + pGlobal->pDfltTok = pNew; |
| 254257 | + } |
| 254258 | + } |
| 254259 | + |
| 254260 | + return rc; |
| 254261 | +} |
| 254262 | + |
| 254263 | +/* |
| 254264 | +** An instance of this type is used as the Fts5Tokenizer object for |
| 254265 | +** wrapper tokenizers - those that provide access to a v1 tokenizer via |
| 254266 | +** the fts5_tokenizer_v2 API, and those that provide access to a v2 tokenizer |
| 254267 | +** via the fts5_tokenizer API. |
| 254268 | +*/ |
| 254269 | +typedef struct Fts5VtoVTokenizer Fts5VtoVTokenizer; |
| 254270 | +struct Fts5VtoVTokenizer { |
| 254271 | + Fts5TokenizerModule *pMod; |
| 254272 | + Fts5Tokenizer *pReal; |
| 254273 | +}; |
| 254274 | + |
| 254275 | +/* |
| 254276 | +** Create a wrapper tokenizer. The context argument pCtx points to the |
| 254277 | +** Fts5TokenizerModule object. |
| 254278 | +*/ |
| 254279 | +static int fts5VtoVCreate( |
| 254280 | + void *pCtx, |
| 254281 | + const char **azArg, |
| 254282 | + int nArg, |
| 254283 | + Fts5Tokenizer **ppOut |
| 254284 | +){ |
| 254285 | + Fts5TokenizerModule *pMod = (Fts5TokenizerModule*)pCtx; |
| 254286 | + Fts5VtoVTokenizer *pNew = 0; |
| 254287 | + int rc = SQLITE_OK; |
| 254288 | + |
| 254289 | + pNew = (Fts5VtoVTokenizer*)sqlite3Fts5MallocZero(&rc, sizeof(*pNew)); |
| 254290 | + if( rc==SQLITE_OK ){ |
| 254291 | + pNew->pMod = pMod; |
| 254292 | + if( pMod->bV2Native ){ |
| 254293 | + rc = pMod->x2.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); |
| 254294 | + }else{ |
| 254295 | + rc = pMod->x1.xCreate(pMod->pUserData, azArg, nArg, &pNew->pReal); |
| 254296 | + } |
| 254297 | + if( rc!=SQLITE_OK ){ |
| 254298 | + sqlite3_free(pNew); |
| 254299 | + pNew = 0; |
| 254300 | + } |
| 254301 | + } |
| 254302 | + |
| 254303 | + *ppOut = (Fts5Tokenizer*)pNew; |
| 254304 | + return rc; |
| 254305 | +} |
| 254306 | + |
| 254307 | +/* |
| 254308 | +** Delete an Fts5VtoVTokenizer wrapper tokenizer. |
| 254309 | +*/ |
| 254310 | +static void fts5VtoVDelete(Fts5Tokenizer *pTok){ |
| 254311 | + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; |
| 254312 | + if( p ){ |
| 254313 | + Fts5TokenizerModule *pMod = p->pMod; |
| 254314 | + if( pMod->bV2Native ){ |
| 254315 | + pMod->x2.xDelete(p->pReal); |
| 254316 | + }else{ |
| 254317 | + pMod->x1.xDelete(p->pReal); |
| 254318 | + } |
| 254319 | + sqlite3_free(p); |
| 254320 | + } |
| 254321 | +} |
| 254322 | + |
| 254323 | + |
| 254324 | +/* |
| 254325 | +** xTokenizer method for a wrapper tokenizer that offers the v1 interface |
| 254326 | +** (no support for locales). |
| 254327 | +*/ |
| 254328 | +static int fts5V1toV2Tokenize( |
| 254329 | + Fts5Tokenizer *pTok, |
| 254330 | + void *pCtx, int flags, |
| 254331 | + const char *pText, int nText, |
| 254332 | + int (*xToken)(void*, int, const char*, int, int, int) |
| 254333 | +){ |
| 254334 | + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; |
| 254335 | + Fts5TokenizerModule *pMod = p->pMod; |
| 254336 | + assert( pMod->bV2Native ); |
| 254337 | + return pMod->x2.xTokenize(p->pReal, pCtx, flags, pText, nText, 0, 0, xToken); |
| 254338 | +} |
| 254339 | + |
| 254340 | +/* |
| 254341 | +** xTokenizer method for a wrapper tokenizer that offers the v2 interface |
| 254342 | +** (with locale support). |
| 254343 | +*/ |
| 254344 | +static int fts5V2toV1Tokenize( |
| 254345 | + Fts5Tokenizer *pTok, |
| 254346 | + void *pCtx, int flags, |
| 254347 | + const char *pText, int nText, |
| 254348 | + const char *pLocale, int nLocale, |
| 254349 | + int (*xToken)(void*, int, const char*, int, int, int) |
| 254350 | +){ |
| 254351 | + Fts5VtoVTokenizer *p = (Fts5VtoVTokenizer*)pTok; |
| 254352 | + Fts5TokenizerModule *pMod = p->pMod; |
| 254353 | + assert( pMod->bV2Native==0 ); |
| 254354 | + return pMod->x1.xTokenize(p->pReal, pCtx, flags, pText, nText, xToken); |
| 254355 | +} |
| 253065 | 254356 | |
| 253066 | 254357 | /* |
| 253067 | 254358 | ** Register a new tokenizer. This is the implementation of the |
| 253068 | | -** fts5_api.xCreateTokenizer() method. |
| 254359 | +** fts5_api.xCreateTokenizer_v2() method. |
| 254360 | +*/ |
| 254361 | +static int fts5CreateTokenizer_v2( |
| 254362 | + fts5_api *pApi, /* Global context (one per db handle) */ |
| 254363 | + const char *zName, /* Name of new function */ |
| 254364 | + void *pUserData, /* User data for aux. function */ |
| 254365 | + fts5_tokenizer_v2 *pTokenizer, /* Tokenizer implementation */ |
| 254366 | + void(*xDestroy)(void*) /* Destructor for pUserData */ |
| 254367 | +){ |
| 254368 | + Fts5Global *pGlobal = (Fts5Global*)pApi; |
| 254369 | + int rc = SQLITE_OK; |
| 254370 | + |
| 254371 | + if( pTokenizer->iVersion>2 ){ |
| 254372 | + rc = SQLITE_ERROR; |
| 254373 | + }else{ |
| 254374 | + Fts5TokenizerModule *pNew = 0; |
| 254375 | + rc = fts5NewTokenizerModule(pGlobal, zName, pUserData, xDestroy, &pNew); |
| 254376 | + if( pNew ){ |
| 254377 | + pNew->x2 = *pTokenizer; |
| 254378 | + pNew->bV2Native = 1; |
| 254379 | + pNew->x1.xCreate = fts5VtoVCreate; |
| 254380 | + pNew->x1.xTokenize = fts5V1toV2Tokenize; |
| 254381 | + pNew->x1.xDelete = fts5VtoVDelete; |
| 254382 | + } |
| 254383 | + } |
| 254384 | + |
| 254385 | + return rc; |
| 254386 | +} |
| 254387 | + |
| 254388 | +/* |
| 254389 | +** The fts5_api.xCreateTokenizer() method. |
| 253069 | 254390 | */ |
| 253070 | 254391 | static int fts5CreateTokenizer( |
| 253071 | 254392 | fts5_api *pApi, /* Global context (one per db handle) */ |
| 253072 | 254393 | const char *zName, /* Name of new function */ |
| 253073 | 254394 | void *pUserData, /* User data for aux. function */ |
| 253074 | 254395 | fts5_tokenizer *pTokenizer, /* Tokenizer implementation */ |
| 253075 | 254396 | void(*xDestroy)(void*) /* Destructor for pUserData */ |
| 253076 | 254397 | ){ |
| 253077 | | - Fts5Global *pGlobal = (Fts5Global*)pApi; |
| 253078 | | - Fts5TokenizerModule *pNew; |
| 253079 | | - sqlite3_int64 nName; /* Size of zName and its \0 terminator */ |
| 253080 | | - sqlite3_int64 nByte; /* Bytes of space to allocate */ |
| 254398 | + Fts5TokenizerModule *pNew = 0; |
| 253081 | 254399 | int rc = SQLITE_OK; |
| 253082 | 254400 | |
| 253083 | | - nName = strlen(zName) + 1; |
| 253084 | | - nByte = sizeof(Fts5TokenizerModule) + nName; |
| 253085 | | - pNew = (Fts5TokenizerModule*)sqlite3_malloc64(nByte); |
| 254401 | + rc = fts5NewTokenizerModule( |
| 254402 | + (Fts5Global*)pApi, zName, pUserData, xDestroy, &pNew |
| 254403 | + ); |
| 253086 | 254404 | if( pNew ){ |
| 253087 | | - memset(pNew, 0, (size_t)nByte); |
| 253088 | | - pNew->zName = (char*)&pNew[1]; |
| 253089 | | - memcpy(pNew->zName, zName, nName); |
| 253090 | | - pNew->pUserData = pUserData; |
| 253091 | | - pNew->x = *pTokenizer; |
| 253092 | | - pNew->xDestroy = xDestroy; |
| 253093 | | - pNew->pNext = pGlobal->pTok; |
| 253094 | | - pGlobal->pTok = pNew; |
| 253095 | | - if( pNew->pNext==0 ){ |
| 253096 | | - pGlobal->pDfltTok = pNew; |
| 253097 | | - } |
| 253098 | | - }else{ |
| 253099 | | - rc = SQLITE_NOMEM; |
| 253100 | | - } |
| 253101 | | - |
| 254405 | + pNew->x1 = *pTokenizer; |
| 254406 | + pNew->x2.xCreate = fts5VtoVCreate; |
| 254407 | + pNew->x2.xTokenize = fts5V2toV1Tokenize; |
| 254408 | + pNew->x2.xDelete = fts5VtoVDelete; |
| 254409 | + } |
| 253102 | 254410 | return rc; |
| 253103 | 254411 | } |
| 253104 | 254412 | |
| 254413 | +/* |
| 254414 | +** Search the global context passed as the first argument for a tokenizer |
| 254415 | +** module named zName. If found, return a pointer to the Fts5TokenizerModule |
| 254416 | +** object. Otherwise, return NULL. |
| 254417 | +*/ |
| 253105 | 254418 | static Fts5TokenizerModule *fts5LocateTokenizer( |
| 253106 | | - Fts5Global *pGlobal, |
| 253107 | | - const char *zName |
| 254419 | + Fts5Global *pGlobal, /* Global (one per db handle) object */ |
| 254420 | + const char *zName /* Name of tokenizer module to find */ |
| 253108 | 254421 | ){ |
| 253109 | 254422 | Fts5TokenizerModule *pMod = 0; |
| 253110 | 254423 | |
| 253111 | 254424 | if( zName==0 ){ |
| 253112 | 254425 | pMod = pGlobal->pDfltTok; |
| | @@ -253116,10 +254429,40 @@ |
| 253116 | 254429 | } |
| 253117 | 254430 | } |
| 253118 | 254431 | |
| 253119 | 254432 | return pMod; |
| 253120 | 254433 | } |
| 254434 | + |
| 254435 | +/* |
| 254436 | +** Find a tokenizer. This is the implementation of the |
| 254437 | +** fts5_api.xFindTokenizer_v2() method. |
| 254438 | +*/ |
| 254439 | +static int fts5FindTokenizer_v2( |
| 254440 | + fts5_api *pApi, /* Global context (one per db handle) */ |
| 254441 | + const char *zName, /* Name of tokenizer */ |
| 254442 | + void **ppUserData, |
| 254443 | + fts5_tokenizer_v2 **ppTokenizer /* Populate this object */ |
| 254444 | +){ |
| 254445 | + int rc = SQLITE_OK; |
| 254446 | + Fts5TokenizerModule *pMod; |
| 254447 | + |
| 254448 | + pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); |
| 254449 | + if( pMod ){ |
| 254450 | + if( pMod->bV2Native ){ |
| 254451 | + *ppUserData = pMod->pUserData; |
| 254452 | + }else{ |
| 254453 | + *ppUserData = (void*)pMod; |
| 254454 | + } |
| 254455 | + *ppTokenizer = &pMod->x2; |
| 254456 | + }else{ |
| 254457 | + *ppTokenizer = 0; |
| 254458 | + *ppUserData = 0; |
| 254459 | + rc = SQLITE_ERROR; |
| 254460 | + } |
| 254461 | + |
| 254462 | + return rc; |
| 254463 | +} |
| 253121 | 254464 | |
| 253122 | 254465 | /* |
| 253123 | 254466 | ** Find a tokenizer. This is the implementation of the |
| 253124 | 254467 | ** fts5_api.xFindTokenizer() method. |
| 253125 | 254468 | */ |
| | @@ -253132,70 +254475,79 @@ |
| 253132 | 254475 | int rc = SQLITE_OK; |
| 253133 | 254476 | Fts5TokenizerModule *pMod; |
| 253134 | 254477 | |
| 253135 | 254478 | pMod = fts5LocateTokenizer((Fts5Global*)pApi, zName); |
| 253136 | 254479 | if( pMod ){ |
| 253137 | | - *pTokenizer = pMod->x; |
| 253138 | | - *ppUserData = pMod->pUserData; |
| 253139 | | - }else{ |
| 253140 | | - memset(pTokenizer, 0, sizeof(fts5_tokenizer)); |
| 253141 | | - rc = SQLITE_ERROR; |
| 253142 | | - } |
| 253143 | | - |
| 253144 | | - return rc; |
| 253145 | | -} |
| 253146 | | - |
| 253147 | | -int fts5GetTokenizer( |
| 253148 | | - Fts5Global *pGlobal, |
| 253149 | | - const char **azArg, |
| 253150 | | - int nArg, |
| 253151 | | - Fts5Config *pConfig, |
| 253152 | | - char **pzErr |
| 253153 | | -){ |
| 253154 | | - Fts5TokenizerModule *pMod; |
| 253155 | | - int rc = SQLITE_OK; |
| 253156 | | - |
| 253157 | | - pMod = fts5LocateTokenizer(pGlobal, nArg==0 ? 0 : azArg[0]); |
| 253158 | | - if( pMod==0 ){ |
| 253159 | | - assert( nArg>0 ); |
| 253160 | | - rc = SQLITE_ERROR; |
| 253161 | | - if( pzErr ) *pzErr = sqlite3_mprintf("no such tokenizer: %s", azArg[0]); |
| 253162 | | - }else{ |
| 253163 | | - rc = pMod->x.xCreate( |
| 253164 | | - pMod->pUserData, (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok |
| 253165 | | - ); |
| 253166 | | - pConfig->t.pTokApi = &pMod->x; |
| 253167 | | - if( rc!=SQLITE_OK ){ |
| 253168 | | - if( pzErr && rc!=SQLITE_NOMEM ){ |
| 253169 | | - *pzErr = sqlite3_mprintf("error in tokenizer constructor"); |
| 253170 | | - } |
| 253171 | | - }else{ |
| 253172 | | - pConfig->t.ePattern = sqlite3Fts5TokenizerPattern( |
| 253173 | | - pMod->x.xCreate, pConfig->t.pTok |
| 253174 | | - ); |
| 253175 | | - } |
| 253176 | | - } |
| 253177 | | - |
| 253178 | | - if( rc!=SQLITE_OK ){ |
| 253179 | | - pConfig->t.pTokApi = 0; |
| 253180 | | - pConfig->t.pTok = 0; |
| 254480 | + if( pMod->bV2Native==0 ){ |
| 254481 | + *ppUserData = pMod->pUserData; |
| 254482 | + }else{ |
| 254483 | + *ppUserData = (void*)pMod; |
| 254484 | + } |
| 254485 | + *pTokenizer = pMod->x1; |
| 254486 | + }else{ |
| 254487 | + memset(pTokenizer, 0, sizeof(*pTokenizer)); |
| 254488 | + *ppUserData = 0; |
| 254489 | + rc = SQLITE_ERROR; |
| 253181 | 254490 | } |
| 253182 | 254491 | |
| 253183 | 254492 | return rc; |
| 253184 | 254493 | } |
| 253185 | 254494 | |
| 253186 | 254495 | /* |
| 253187 | 254496 | ** Attempt to instantiate the tokenizer. |
| 253188 | 254497 | */ |
| 253189 | 254498 | static int sqlite3Fts5LoadTokenizer(Fts5Config *pConfig){ |
| 253190 | | - return fts5GetTokenizer( |
| 253191 | | - pConfig->pGlobal, pConfig->t.azArg, pConfig->t.nArg, |
| 253192 | | - pConfig, pConfig->pzErrmsg |
| 253193 | | - ); |
| 254499 | + const char **azArg = pConfig->t.azArg; |
| 254500 | + const int nArg = pConfig->t.nArg; |
| 254501 | + Fts5TokenizerModule *pMod = 0; |
| 254502 | + int rc = SQLITE_OK; |
| 254503 | + |
| 254504 | + pMod = fts5LocateTokenizer(pConfig->pGlobal, nArg==0 ? 0 : azArg[0]); |
| 254505 | + if( pMod==0 ){ |
| 254506 | + assert( nArg>0 ); |
| 254507 | + rc = SQLITE_ERROR; |
| 254508 | + sqlite3Fts5ConfigErrmsg(pConfig, "no such tokenizer: %s", azArg[0]); |
| 254509 | + }else{ |
| 254510 | + int (*xCreate)(void*, const char**, int, Fts5Tokenizer**) = 0; |
| 254511 | + if( pMod->bV2Native ){ |
| 254512 | + xCreate = pMod->x2.xCreate; |
| 254513 | + pConfig->t.pApi2 = &pMod->x2; |
| 254514 | + }else{ |
| 254515 | + pConfig->t.pApi1 = &pMod->x1; |
| 254516 | + xCreate = pMod->x1.xCreate; |
| 254517 | + } |
| 254518 | + |
| 254519 | + rc = xCreate(pMod->pUserData, |
| 254520 | + (azArg?&azArg[1]:0), (nArg?nArg-1:0), &pConfig->t.pTok |
| 254521 | + ); |
| 254522 | + |
| 254523 | + if( rc!=SQLITE_OK ){ |
| 254524 | + if( rc!=SQLITE_NOMEM ){ |
| 254525 | + sqlite3Fts5ConfigErrmsg(pConfig, "error in tokenizer constructor"); |
| 254526 | + } |
| 254527 | + }else if( pMod->bV2Native==0 ){ |
| 254528 | + pConfig->t.ePattern = sqlite3Fts5TokenizerPattern( |
| 254529 | + pMod->x1.xCreate, pConfig->t.pTok |
| 254530 | + ); |
| 254531 | + } |
| 254532 | + } |
| 254533 | + |
| 254534 | + if( rc!=SQLITE_OK ){ |
| 254535 | + pConfig->t.pApi1 = 0; |
| 254536 | + pConfig->t.pApi2 = 0; |
| 254537 | + pConfig->t.pTok = 0; |
| 254538 | + } |
| 254539 | + |
| 254540 | + return rc; |
| 253194 | 254541 | } |
| 253195 | 254542 | |
| 253196 | 254543 | |
| 254544 | +/* |
| 254545 | +** xDestroy callback passed to sqlite3_create_module(). This is invoked |
| 254546 | +** when the db handle is being closed. Free memory associated with |
| 254547 | +** tokenizers and aux functions registered with this db handle. |
| 254548 | +*/ |
| 253197 | 254549 | static void fts5ModuleDestroy(void *pCtx){ |
| 253198 | 254550 | Fts5TokenizerModule *pTok, *pNextTok; |
| 253199 | 254551 | Fts5Auxiliary *pAux, *pNextAux; |
| 253200 | 254552 | Fts5Global *pGlobal = (Fts5Global*)pCtx; |
| 253201 | 254553 | |
| | @@ -253212,10 +254564,14 @@ |
| 253212 | 254564 | } |
| 253213 | 254565 | |
| 253214 | 254566 | sqlite3_free(pGlobal); |
| 253215 | 254567 | } |
| 253216 | 254568 | |
| 254569 | +/* |
| 254570 | +** Implementation of the fts5() function used by clients to obtain the |
| 254571 | +** API pointer. |
| 254572 | +*/ |
| 253217 | 254573 | static void fts5Fts5Func( |
| 253218 | 254574 | sqlite3_context *pCtx, /* Function call context */ |
| 253219 | 254575 | int nArg, /* Number of args */ |
| 253220 | 254576 | sqlite3_value **apArg /* Function arguments */ |
| 253221 | 254577 | ){ |
| | @@ -253235,11 +254591,74 @@ |
| 253235 | 254591 | int nArg, /* Number of args */ |
| 253236 | 254592 | sqlite3_value **apUnused /* Function arguments */ |
| 253237 | 254593 | ){ |
| 253238 | 254594 | assert( nArg==0 ); |
| 253239 | 254595 | UNUSED_PARAM2(nArg, apUnused); |
| 253240 | | - sqlite3_result_text(pCtx, "fts5: 2024-08-16 18:51:46 7a0cdc7edb704a88a77b748cd28f6e00c49849cc2c1af838b95b34232ecc21f9", -1, SQLITE_TRANSIENT); |
| 254596 | + sqlite3_result_text(pCtx, "fts5: 2024-08-23 17:40:29 9a9d0f6301faefe324261f03543023ffb6a90823349c6946abb0df2f69b31f96", -1, SQLITE_TRANSIENT); |
| 254597 | +} |
| 254598 | + |
| 254599 | +/* |
| 254600 | +** Implementation of fts5_locale(LOCALE, TEXT) function. |
| 254601 | +** |
| 254602 | +** If parameter LOCALE is NULL, or a zero-length string, then a copy of |
| 254603 | +** TEXT is returned. Otherwise, both LOCALE and TEXT are interpreted as |
| 254604 | +** text, and the value returned is a blob consisting of: |
| 254605 | +** |
| 254606 | +** * The 4 bytes 0x00, 0xE0, 0xB2, 0xEb (FTS5_LOCALE_HEADER). |
| 254607 | +** * The LOCALE, as utf-8 text, followed by |
| 254608 | +** * 0x00, followed by |
| 254609 | +** * The TEXT, as utf-8 text. |
| 254610 | +** |
| 254611 | +** There is no final nul-terminator following the TEXT value. |
| 254612 | +*/ |
| 254613 | +static void fts5LocaleFunc( |
| 254614 | + sqlite3_context *pCtx, /* Function call context */ |
| 254615 | + int nArg, /* Number of args */ |
| 254616 | + sqlite3_value **apArg /* Function arguments */ |
| 254617 | +){ |
| 254618 | + const char *zLocale = 0; |
| 254619 | + int nLocale = 0; |
| 254620 | + const char *zText = 0; |
| 254621 | + int nText = 0; |
| 254622 | + |
| 254623 | + assert( nArg==2 ); |
| 254624 | + UNUSED_PARAM(nArg); |
| 254625 | + |
| 254626 | + zLocale = (const char*)sqlite3_value_text(apArg[0]); |
| 254627 | + nLocale = sqlite3_value_bytes(apArg[0]); |
| 254628 | + |
| 254629 | + zText = (const char*)sqlite3_value_text(apArg[1]); |
| 254630 | + nText = sqlite3_value_bytes(apArg[1]); |
| 254631 | + |
| 254632 | + if( zLocale==0 || zLocale[0]=='\0' ){ |
| 254633 | + sqlite3_result_text(pCtx, zText, nText, SQLITE_TRANSIENT); |
| 254634 | + }else{ |
| 254635 | + u8 *pBlob = 0; |
| 254636 | + u8 *pCsr = 0; |
| 254637 | + int nBlob = 0; |
| 254638 | + const int nHdr = 4; |
| 254639 | + assert( sizeof(FTS5_LOCALE_HEADER)==nHdr+1 ); |
| 254640 | + |
| 254641 | + nBlob = nHdr + nLocale + 1 + nText; |
| 254642 | + pBlob = (u8*)sqlite3_malloc(nBlob); |
| 254643 | + if( pBlob==0 ){ |
| 254644 | + sqlite3_result_error_nomem(pCtx); |
| 254645 | + return; |
| 254646 | + } |
| 254647 | + |
| 254648 | + pCsr = pBlob; |
| 254649 | + memcpy(pCsr, FTS5_LOCALE_HEADER, nHdr); |
| 254650 | + pCsr += nHdr; |
| 254651 | + memcpy(pCsr, zLocale, nLocale); |
| 254652 | + pCsr += nLocale; |
| 254653 | + (*pCsr++) = 0x00; |
| 254654 | + if( zText ) memcpy(pCsr, zText, nText); |
| 254655 | + assert( &pCsr[nText]==&pBlob[nBlob] ); |
| 254656 | + |
| 254657 | + sqlite3_result_blob(pCtx, pBlob, nBlob, sqlite3_free); |
| 254658 | + sqlite3_result_subtype(pCtx, FTS5_LOCALE_SUBTYPE); |
| 254659 | + } |
| 253241 | 254660 | } |
| 253242 | 254661 | |
| 253243 | 254662 | /* |
| 253244 | 254663 | ** Return true if zName is the extension on one of the shadow tables used |
| 253245 | 254664 | ** by this module. |
| | @@ -253330,14 +254749,16 @@ |
| 253330 | 254749 | rc = SQLITE_NOMEM; |
| 253331 | 254750 | }else{ |
| 253332 | 254751 | void *p = (void*)pGlobal; |
| 253333 | 254752 | memset(pGlobal, 0, sizeof(Fts5Global)); |
| 253334 | 254753 | pGlobal->db = db; |
| 253335 | | - pGlobal->api.iVersion = 2; |
| 254754 | + pGlobal->api.iVersion = 3; |
| 253336 | 254755 | pGlobal->api.xCreateFunction = fts5CreateAux; |
| 253337 | 254756 | pGlobal->api.xCreateTokenizer = fts5CreateTokenizer; |
| 253338 | 254757 | pGlobal->api.xFindTokenizer = fts5FindTokenizer; |
| 254758 | + pGlobal->api.xCreateTokenizer_v2 = fts5CreateTokenizer_v2; |
| 254759 | + pGlobal->api.xFindTokenizer_v2 = fts5FindTokenizer_v2; |
| 253339 | 254760 | rc = sqlite3_create_module_v2(db, "fts5", &fts5Mod, p, fts5ModuleDestroy); |
| 253340 | 254761 | if( rc==SQLITE_OK ) rc = sqlite3Fts5IndexInit(db); |
| 253341 | 254762 | if( rc==SQLITE_OK ) rc = sqlite3Fts5ExprInit(pGlobal, db); |
| 253342 | 254763 | if( rc==SQLITE_OK ) rc = sqlite3Fts5AuxInit(&pGlobal->api); |
| 253343 | 254764 | if( rc==SQLITE_OK ) rc = sqlite3Fts5TokenizerInit(&pGlobal->api); |
| | @@ -253351,10 +254772,17 @@ |
| 253351 | 254772 | rc = sqlite3_create_function( |
| 253352 | 254773 | db, "fts5_source_id", 0, |
| 253353 | 254774 | SQLITE_UTF8|SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS, |
| 253354 | 254775 | p, fts5SourceIdFunc, 0, 0 |
| 253355 | 254776 | ); |
| 254777 | + } |
| 254778 | + if( rc==SQLITE_OK ){ |
| 254779 | + rc = sqlite3_create_function( |
| 254780 | + db, "fts5_locale", 2, |
| 254781 | + SQLITE_UTF8|SQLITE_INNOCUOUS|SQLITE_RESULT_SUBTYPE, |
| 254782 | + p, fts5LocaleFunc, 0, 0 |
| 254783 | + ); |
| 253356 | 254784 | } |
| 253357 | 254785 | } |
| 253358 | 254786 | |
| 253359 | 254787 | /* If SQLITE_FTS5_ENABLE_TEST_MI is defined, assume that the file |
| 253360 | 254788 | ** fts5_test_mi.c is compiled and linked into the executable. And call |
| | @@ -253426,17 +254854,44 @@ |
| 253426 | 254854 | |
| 253427 | 254855 | |
| 253428 | 254856 | |
| 253429 | 254857 | /* #include "fts5Int.h" */ |
| 253430 | 254858 | |
| 254859 | +/* |
| 254860 | +** pSavedRow: |
| 254861 | +** SQL statement FTS5_STMT_LOOKUP2 is a copy of FTS5_STMT_LOOKUP, it |
| 254862 | +** does a by-rowid lookup to retrieve a single row from the %_content |
| 254863 | +** table or equivalent external-content table/view. |
| 254864 | +** |
| 254865 | +** However, FTS5_STMT_LOOKUP2 is only used when retrieving the original |
| 254866 | +** values for a row being UPDATEd. In that case, the SQL statement is |
| 254867 | +** not reset and pSavedRow is set to point at it. This is so that the |
| 254868 | +** insert operation that follows the delete may access the original |
| 254869 | +** row values for any new values for which sqlite3_value_nochange() returns |
| 254870 | +** true. i.e. if the user executes: |
| 254871 | +** |
| 254872 | +** CREATE VIRTUAL TABLE ft USING fts5(a, b, c, locale=1); |
| 254873 | +** ... |
| 254874 | +** UPDATE fts SET a=?, b=? WHERE rowid=?; |
| 254875 | +** |
| 254876 | +** then the value passed to the xUpdate() method of this table as the |
| 254877 | +** new.c value is an sqlite3_value_nochange() value. So in this case it |
| 254878 | +** must be read from the saved row stored in Fts5Storage.pSavedRow. |
| 254879 | +** |
| 254880 | +** This is necessary - using sqlite3_value_nochange() instead of just having |
| 254881 | +** SQLite pass the original value back via xUpdate() - so as not to discard |
| 254882 | +** any locale information associated with such values. |
| 254883 | +** |
| 254884 | +*/ |
| 253431 | 254885 | struct Fts5Storage { |
| 253432 | 254886 | Fts5Config *pConfig; |
| 253433 | 254887 | Fts5Index *pIndex; |
| 253434 | 254888 | int bTotalsValid; /* True if nTotalRow/aTotalSize[] are valid */ |
| 253435 | 254889 | i64 nTotalRow; /* Total number of rows in FTS table */ |
| 253436 | 254890 | i64 *aTotalSize; /* Total sizes of each column */ |
| 253437 | | - sqlite3_stmt *aStmt[11]; |
| 254891 | + sqlite3_stmt *pSavedRow; |
| 254892 | + sqlite3_stmt *aStmt[12]; |
| 253438 | 254893 | }; |
| 253439 | 254894 | |
| 253440 | 254895 | |
| 253441 | 254896 | #if FTS5_STMT_SCAN_ASC!=0 |
| 253442 | 254897 | # error "FTS5_STMT_SCAN_ASC mismatch" |
| | @@ -253446,18 +254901,19 @@ |
| 253446 | 254901 | #endif |
| 253447 | 254902 | #if FTS5_STMT_LOOKUP!=2 |
| 253448 | 254903 | # error "FTS5_STMT_LOOKUP mismatch" |
| 253449 | 254904 | #endif |
| 253450 | 254905 | |
| 253451 | | -#define FTS5_STMT_INSERT_CONTENT 3 |
| 253452 | | -#define FTS5_STMT_REPLACE_CONTENT 4 |
| 253453 | | -#define FTS5_STMT_DELETE_CONTENT 5 |
| 253454 | | -#define FTS5_STMT_REPLACE_DOCSIZE 6 |
| 253455 | | -#define FTS5_STMT_DELETE_DOCSIZE 7 |
| 253456 | | -#define FTS5_STMT_LOOKUP_DOCSIZE 8 |
| 253457 | | -#define FTS5_STMT_REPLACE_CONFIG 9 |
| 253458 | | -#define FTS5_STMT_SCAN 10 |
| 254906 | +#define FTS5_STMT_LOOKUP2 3 |
| 254907 | +#define FTS5_STMT_INSERT_CONTENT 4 |
| 254908 | +#define FTS5_STMT_REPLACE_CONTENT 5 |
| 254909 | +#define FTS5_STMT_DELETE_CONTENT 6 |
| 254910 | +#define FTS5_STMT_REPLACE_DOCSIZE 7 |
| 254911 | +#define FTS5_STMT_DELETE_DOCSIZE 8 |
| 254912 | +#define FTS5_STMT_LOOKUP_DOCSIZE 9 |
| 254913 | +#define FTS5_STMT_REPLACE_CONFIG 10 |
| 254914 | +#define FTS5_STMT_SCAN 11 |
| 253459 | 254915 | |
| 253460 | 254916 | /* |
| 253461 | 254917 | ** Prepare the two insert statements - Fts5Storage.pInsertContent and |
| 253462 | 254918 | ** Fts5Storage.pInsertDocsize - if they have not already been prepared. |
| 253463 | 254919 | ** Return SQLITE_OK if successful, or an SQLite error code if an error |
| | @@ -253483,10 +254939,11 @@ |
| 253483 | 254939 | if( p->aStmt[eStmt]==0 ){ |
| 253484 | 254940 | const char *azStmt[] = { |
| 253485 | 254941 | "SELECT %s FROM %s T WHERE T.%Q >= ? AND T.%Q <= ? ORDER BY T.%Q ASC", |
| 253486 | 254942 | "SELECT %s FROM %s T WHERE T.%Q <= ? AND T.%Q >= ? ORDER BY T.%Q DESC", |
| 253487 | 254943 | "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP */ |
| 254944 | + "SELECT %s FROM %s T WHERE T.%Q=?", /* LOOKUP2 */ |
| 253488 | 254945 | |
| 253489 | 254946 | "INSERT INTO %Q.'%q_content' VALUES(%s)", /* INSERT_CONTENT */ |
| 253490 | 254947 | "REPLACE INTO %Q.'%q_content' VALUES(%s)", /* REPLACE_CONTENT */ |
| 253491 | 254948 | "DELETE FROM %Q.'%q_content' WHERE id=?", /* DELETE_CONTENT */ |
| 253492 | 254949 | "REPLACE INTO %Q.'%q_docsize' VALUES(?,?%s)", /* REPLACE_DOCSIZE */ |
| | @@ -253497,10 +254954,12 @@ |
| 253497 | 254954 | "REPLACE INTO %Q.'%q_config' VALUES(?,?)", /* REPLACE_CONFIG */ |
| 253498 | 254955 | "SELECT %s FROM %s AS T", /* SCAN */ |
| 253499 | 254956 | }; |
| 253500 | 254957 | Fts5Config *pC = p->pConfig; |
| 253501 | 254958 | char *zSql = 0; |
| 254959 | + |
| 254960 | + assert( ArraySize(azStmt)==ArraySize(p->aStmt) ); |
| 253502 | 254961 | |
| 253503 | 254962 | switch( eStmt ){ |
| 253504 | 254963 | case FTS5_STMT_SCAN: |
| 253505 | 254964 | zSql = sqlite3_mprintf(azStmt[eStmt], |
| 253506 | 254965 | pC->zContentExprlist, pC->zContent |
| | @@ -253514,10 +254973,11 @@ |
| 253514 | 254973 | pC->zContentRowid |
| 253515 | 254974 | ); |
| 253516 | 254975 | break; |
| 253517 | 254976 | |
| 253518 | 254977 | case FTS5_STMT_LOOKUP: |
| 254978 | + case FTS5_STMT_LOOKUP2: |
| 253519 | 254979 | zSql = sqlite3_mprintf(azStmt[eStmt], |
| 253520 | 254980 | pC->zContentExprlist, pC->zContent, pC->zContentRowid |
| 253521 | 254981 | ); |
| 253522 | 254982 | break; |
| 253523 | 254983 | |
| | @@ -253560,11 +255020,11 @@ |
| 253560 | 255020 | |
| 253561 | 255021 | if( zSql==0 ){ |
| 253562 | 255022 | rc = SQLITE_NOMEM; |
| 253563 | 255023 | }else{ |
| 253564 | 255024 | int f = SQLITE_PREPARE_PERSISTENT; |
| 253565 | | - if( eStmt>FTS5_STMT_LOOKUP ) f |= SQLITE_PREPARE_NO_VTAB; |
| 255025 | + if( eStmt>FTS5_STMT_LOOKUP2 ) f |= SQLITE_PREPARE_NO_VTAB; |
| 253566 | 255026 | p->pConfig->bLock++; |
| 253567 | 255027 | rc = sqlite3_prepare_v3(pC->db, zSql, -1, f, &p->aStmt[eStmt], 0); |
| 253568 | 255028 | p->pConfig->bLock--; |
| 253569 | 255029 | sqlite3_free(zSql); |
| 253570 | 255030 | if( rc!=SQLITE_OK && pzErrMsg ){ |
| | @@ -253808,74 +255268,141 @@ |
| 253808 | 255268 | if( (tflags & FTS5_TOKEN_COLOCATED)==0 || pCtx->szCol==0 ){ |
| 253809 | 255269 | pCtx->szCol++; |
| 253810 | 255270 | } |
| 253811 | 255271 | return sqlite3Fts5IndexWrite(pIdx, pCtx->iCol, pCtx->szCol-1, pToken, nToken); |
| 253812 | 255272 | } |
| 255273 | + |
| 255274 | +/* |
| 255275 | +** This function is used as part of an UPDATE statement that modifies the |
| 255276 | +** rowid of a row. In that case, this function is called first to set |
| 255277 | +** Fts5Storage.pSavedRow to point to a statement that may be used to |
| 255278 | +** access the original values of the row being deleted - iDel. |
| 255279 | +** |
| 255280 | +** SQLITE_OK is returned if successful, or an SQLite error code otherwise. |
| 255281 | +** It is not considered an error if row iDel does not exist. In this case |
| 255282 | +** pSavedRow is not set and SQLITE_OK returned. |
| 255283 | +*/ |
| 255284 | +static int sqlite3Fts5StorageFindDeleteRow(Fts5Storage *p, i64 iDel){ |
| 255285 | + int rc = SQLITE_OK; |
| 255286 | + sqlite3_stmt *pSeek = 0; |
| 255287 | + |
| 255288 | + assert( p->pSavedRow==0 ); |
| 255289 | + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+1, &pSeek, 0); |
| 255290 | + if( rc==SQLITE_OK ){ |
| 255291 | + sqlite3_bind_int64(pSeek, 1, iDel); |
| 255292 | + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ |
| 255293 | + rc = sqlite3_reset(pSeek); |
| 255294 | + }else{ |
| 255295 | + p->pSavedRow = pSeek; |
| 255296 | + } |
| 255297 | + } |
| 255298 | + |
| 255299 | + return rc; |
| 255300 | +} |
| 253813 | 255301 | |
| 253814 | 255302 | /* |
| 253815 | 255303 | ** If a row with rowid iDel is present in the %_content table, add the |
| 253816 | 255304 | ** delete-markers to the FTS index necessary to delete it. Do not actually |
| 253817 | 255305 | ** remove the %_content row at this time though. |
| 255306 | +** |
| 255307 | +** If parameter bSaveRow is true, then Fts5Storage.pSavedRow is left |
| 255308 | +** pointing to a statement (FTS5_STMT_LOOKUP2) that may be used to access |
| 255309 | +** the original values of the row being deleted. This is used by UPDATE |
| 255310 | +** statements. |
| 253818 | 255311 | */ |
| 253819 | 255312 | static int fts5StorageDeleteFromIndex( |
| 253820 | 255313 | Fts5Storage *p, |
| 253821 | 255314 | i64 iDel, |
| 253822 | | - sqlite3_value **apVal |
| 255315 | + sqlite3_value **apVal, |
| 255316 | + int bSaveRow /* True to set pSavedRow */ |
| 253823 | 255317 | ){ |
| 253824 | 255318 | Fts5Config *pConfig = p->pConfig; |
| 253825 | 255319 | sqlite3_stmt *pSeek = 0; /* SELECT to read row iDel from %_data */ |
| 253826 | 255320 | int rc = SQLITE_OK; /* Return code */ |
| 253827 | 255321 | int rc2; /* sqlite3_reset() return code */ |
| 253828 | 255322 | int iCol; |
| 253829 | 255323 | Fts5InsertCtx ctx; |
| 253830 | 255324 | |
| 255325 | + assert( bSaveRow==0 || apVal==0 ); |
| 255326 | + assert( bSaveRow==0 || bSaveRow==1 ); |
| 255327 | + assert( FTS5_STMT_LOOKUP2==FTS5_STMT_LOOKUP+1 ); |
| 255328 | + |
| 253831 | 255329 | if( apVal==0 ){ |
| 253832 | | - rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP, &pSeek, 0); |
| 253833 | | - if( rc!=SQLITE_OK ) return rc; |
| 253834 | | - sqlite3_bind_int64(pSeek, 1, iDel); |
| 253835 | | - if( sqlite3_step(pSeek)!=SQLITE_ROW ){ |
| 253836 | | - return sqlite3_reset(pSeek); |
| 255330 | + if( p->pSavedRow && bSaveRow ){ |
| 255331 | + pSeek = p->pSavedRow; |
| 255332 | + p->pSavedRow = 0; |
| 255333 | + }else{ |
| 255334 | + rc = fts5StorageGetStmt(p, FTS5_STMT_LOOKUP+bSaveRow, &pSeek, 0); |
| 255335 | + if( rc!=SQLITE_OK ) return rc; |
| 255336 | + sqlite3_bind_int64(pSeek, 1, iDel); |
| 255337 | + if( sqlite3_step(pSeek)!=SQLITE_ROW ){ |
| 255338 | + return sqlite3_reset(pSeek); |
| 255339 | + } |
| 253837 | 255340 | } |
| 253838 | 255341 | } |
| 253839 | 255342 | |
| 253840 | 255343 | ctx.pStorage = p; |
| 253841 | 255344 | ctx.iCol = -1; |
| 253842 | 255345 | for(iCol=1; rc==SQLITE_OK && iCol<=pConfig->nCol; iCol++){ |
| 253843 | 255346 | if( pConfig->abUnindexed[iCol-1]==0 ){ |
| 253844 | | - const char *zText; |
| 253845 | | - int nText; |
| 255347 | + sqlite3_value *pVal = 0; |
| 255348 | + const char *pText = 0; |
| 255349 | + int nText = 0; |
| 255350 | + int bReset = 0; |
| 255351 | + |
| 253846 | 255352 | assert( pSeek==0 || apVal==0 ); |
| 253847 | 255353 | assert( pSeek!=0 || apVal!=0 ); |
| 253848 | 255354 | if( pSeek ){ |
| 253849 | | - zText = (const char*)sqlite3_column_text(pSeek, iCol); |
| 253850 | | - nText = sqlite3_column_bytes(pSeek, iCol); |
| 253851 | | - }else if( ALWAYS(apVal) ){ |
| 253852 | | - zText = (const char*)sqlite3_value_text(apVal[iCol-1]); |
| 253853 | | - nText = sqlite3_value_bytes(apVal[iCol-1]); |
| 255355 | + pVal = sqlite3_column_value(pSeek, iCol); |
| 253854 | 255356 | }else{ |
| 253855 | | - continue; |
| 255357 | + pVal = apVal[iCol-1]; |
| 253856 | 255358 | } |
| 253857 | | - ctx.szCol = 0; |
| 253858 | | - rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, |
| 253859 | | - zText, nText, (void*)&ctx, fts5StorageInsertCallback |
| 255359 | + |
| 255360 | + rc = sqlite3Fts5ExtractText( |
| 255361 | + pConfig, pVal, pSeek!=0, &bReset, &pText, &nText |
| 253860 | 255362 | ); |
| 253861 | | - p->aTotalSize[iCol-1] -= (i64)ctx.szCol; |
| 253862 | | - if( p->aTotalSize[iCol-1]<0 && rc==SQLITE_OK ){ |
| 253863 | | - rc = FTS5_CORRUPT; |
| 255363 | + if( rc==SQLITE_OK ){ |
| 255364 | + ctx.szCol = 0; |
| 255365 | + rc = sqlite3Fts5Tokenize(pConfig, FTS5_TOKENIZE_DOCUMENT, |
| 255366 | + pText, nText, (void*)&ctx, fts5StorageInsertCallback |
| 255367 | + ); |
| 255368 | + p->aTotalSize[iCol-1] -= (i64)ctx.szCol; |
| 255369 | + if( rc==SQLITE_OK && p->aTotalSize[iCol-1]<0 ){ |
| 255370 | + rc = FTS5_CORRUPT; |
| 255371 | + } |
| 255372 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 253864 | 255373 | } |
| 253865 | 255374 | } |
| 253866 | 255375 | } |
| 253867 | 255376 | if( rc==SQLITE_OK && p->nTotalRow<1 ){ |
| 253868 | 255377 | rc = FTS5_CORRUPT; |
| 253869 | 255378 | }else{ |
| 253870 | 255379 | p->nTotalRow--; |
| 253871 | 255380 | } |
| 253872 | 255381 | |
| 253873 | | - rc2 = sqlite3_reset(pSeek); |
| 253874 | | - if( rc==SQLITE_OK ) rc = rc2; |
| 255382 | + if( rc==SQLITE_OK && bSaveRow ){ |
| 255383 | + assert( p->pSavedRow==0 ); |
| 255384 | + p->pSavedRow = pSeek; |
| 255385 | + }else{ |
| 255386 | + rc2 = sqlite3_reset(pSeek); |
| 255387 | + if( rc==SQLITE_OK ) rc = rc2; |
| 255388 | + } |
| 253875 | 255389 | return rc; |
| 253876 | 255390 | } |
| 255391 | + |
| 255392 | +/* |
| 255393 | +** Reset any saved statement pSavedRow. Zero pSavedRow as well. This |
| 255394 | +** should be called by the xUpdate() method of the fts5 table before |
| 255395 | +** returning from any operation that may have set Fts5Storage.pSavedRow. |
| 255396 | +*/ |
| 255397 | +static void sqlite3Fts5StorageReleaseDeleteRow(Fts5Storage *pStorage){ |
| 255398 | + assert( pStorage->pSavedRow==0 |
| 255399 | + || pStorage->pSavedRow==pStorage->aStmt[FTS5_STMT_LOOKUP2] |
| 255400 | + ); |
| 255401 | + sqlite3_reset(pStorage->pSavedRow); |
| 255402 | + pStorage->pSavedRow = 0; |
| 255403 | +} |
| 253877 | 255404 | |
| 253878 | 255405 | /* |
| 253879 | 255406 | ** This function is called to process a DELETE on a contentless_delete=1 |
| 253880 | 255407 | ** table. It adds the tombstone required to delete the entry with rowid |
| 253881 | 255408 | ** iDel. If successful, SQLITE_OK is returned. Or, if an error occurs, |
| | @@ -253929,16 +255456,16 @@ |
| 253929 | 255456 | if( p->pConfig->bContentlessDelete ){ |
| 253930 | 255457 | i64 iOrigin = 0; |
| 253931 | 255458 | rc = sqlite3Fts5IndexGetOrigin(p->pIndex, &iOrigin); |
| 253932 | 255459 | sqlite3_bind_int64(pReplace, 3, iOrigin); |
| 253933 | 255460 | } |
| 253934 | | - if( rc==SQLITE_OK ){ |
| 253935 | | - sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); |
| 253936 | | - sqlite3_step(pReplace); |
| 253937 | | - rc = sqlite3_reset(pReplace); |
| 253938 | | - sqlite3_bind_null(pReplace, 2); |
| 253939 | | - } |
| 255461 | + } |
| 255462 | + if( rc==SQLITE_OK ){ |
| 255463 | + sqlite3_bind_blob(pReplace, 2, pBuf->p, pBuf->n, SQLITE_STATIC); |
| 255464 | + sqlite3_step(pReplace); |
| 255465 | + rc = sqlite3_reset(pReplace); |
| 255466 | + sqlite3_bind_null(pReplace, 2); |
| 253940 | 255467 | } |
| 253941 | 255468 | } |
| 253942 | 255469 | return rc; |
| 253943 | 255470 | } |
| 253944 | 255471 | |
| | @@ -253988,11 +255515,16 @@ |
| 253988 | 255515 | } |
| 253989 | 255516 | |
| 253990 | 255517 | /* |
| 253991 | 255518 | ** Remove a row from the FTS table. |
| 253992 | 255519 | */ |
| 253993 | | -static int sqlite3Fts5StorageDelete(Fts5Storage *p, i64 iDel, sqlite3_value **apVal){ |
| 255520 | +static int sqlite3Fts5StorageDelete( |
| 255521 | + Fts5Storage *p, /* Storage object */ |
| 255522 | + i64 iDel, /* Rowid to delete from table */ |
| 255523 | + sqlite3_value **apVal, /* Optional - values to remove from index */ |
| 255524 | + int bSaveRow /* If true, set pSavedRow for deleted row */ |
| 255525 | +){ |
| 253994 | 255526 | Fts5Config *pConfig = p->pConfig; |
| 253995 | 255527 | int rc; |
| 253996 | 255528 | sqlite3_stmt *pDel = 0; |
| 253997 | 255529 | |
| 253998 | 255530 | assert( pConfig->eContent!=FTS5_CONTENT_NORMAL || apVal==0 ); |
| | @@ -254005,11 +255537,11 @@ |
| 254005 | 255537 | |
| 254006 | 255538 | if( rc==SQLITE_OK ){ |
| 254007 | 255539 | if( p->pConfig->bContentlessDelete ){ |
| 254008 | 255540 | rc = fts5StorageContentlessDelete(p, iDel); |
| 254009 | 255541 | }else{ |
| 254010 | | - rc = fts5StorageDeleteFromIndex(p, iDel, apVal); |
| 255542 | + rc = fts5StorageDeleteFromIndex(p, iDel, apVal, bSaveRow); |
| 254011 | 255543 | } |
| 254012 | 255544 | } |
| 254013 | 255545 | |
| 254014 | 255546 | /* Delete the %_docsize record */ |
| 254015 | 255547 | if( rc==SQLITE_OK && pConfig->bColumnsize ){ |
| | @@ -254094,18 +255626,25 @@ |
| 254094 | 255626 | sqlite3Fts5BufferZero(&buf); |
| 254095 | 255627 | rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); |
| 254096 | 255628 | for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ |
| 254097 | 255629 | ctx.szCol = 0; |
| 254098 | 255630 | if( pConfig->abUnindexed[ctx.iCol]==0 ){ |
| 254099 | | - const char *zText = (const char*)sqlite3_column_text(pScan, ctx.iCol+1); |
| 254100 | | - int nText = sqlite3_column_bytes(pScan, ctx.iCol+1); |
| 254101 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 254102 | | - FTS5_TOKENIZE_DOCUMENT, |
| 254103 | | - zText, nText, |
| 254104 | | - (void*)&ctx, |
| 254105 | | - fts5StorageInsertCallback |
| 254106 | | - ); |
| 255631 | + int bReset = 0; /* True if tokenizer locale must be reset */ |
| 255632 | + int nText = 0; /* Size of pText in bytes */ |
| 255633 | + const char *pText = 0; /* Pointer to buffer containing text value */ |
| 255634 | + sqlite3_value *pVal = sqlite3_column_value(pScan, ctx.iCol+1); |
| 255635 | + |
| 255636 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, 1, &bReset, &pText, &nText); |
| 255637 | + if( rc==SQLITE_OK ){ |
| 255638 | + rc = sqlite3Fts5Tokenize(pConfig, |
| 255639 | + FTS5_TOKENIZE_DOCUMENT, |
| 255640 | + pText, nText, |
| 255641 | + (void*)&ctx, |
| 255642 | + fts5StorageInsertCallback |
| 255643 | + ); |
| 255644 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 255645 | + } |
| 254107 | 255646 | } |
| 254108 | 255647 | sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); |
| 254109 | 255648 | p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; |
| 254110 | 255649 | } |
| 254111 | 255650 | p->nTotalRow++; |
| | @@ -254185,11 +255724,35 @@ |
| 254185 | 255724 | }else{ |
| 254186 | 255725 | sqlite3_stmt *pInsert = 0; /* Statement to write %_content table */ |
| 254187 | 255726 | int i; /* Counter variable */ |
| 254188 | 255727 | rc = fts5StorageGetStmt(p, FTS5_STMT_INSERT_CONTENT, &pInsert, 0); |
| 254189 | 255728 | for(i=1; rc==SQLITE_OK && i<=pConfig->nCol+1; i++){ |
| 254190 | | - rc = sqlite3_bind_value(pInsert, i, apVal[i]); |
| 255729 | + sqlite3_value *pVal = apVal[i]; |
| 255730 | + if( sqlite3_value_nochange(pVal) && p->pSavedRow ){ |
| 255731 | + /* This is an UPDATE statement, and column (i-2) was not modified. |
| 255732 | + ** Retrieve the value from Fts5Storage.pSavedRow instead. */ |
| 255733 | + pVal = sqlite3_column_value(p->pSavedRow, i-1); |
| 255734 | + }else if( sqlite3_value_subtype(pVal)==FTS5_LOCALE_SUBTYPE ){ |
| 255735 | + assert( pConfig->bLocale ); |
| 255736 | + assert( i>1 ); |
| 255737 | + if( pConfig->abUnindexed[i-2] ){ |
| 255738 | + /* At attempt to insert an fts5_locale() value into an UNINDEXED |
| 255739 | + ** column. Strip the locale away and just bind the text. */ |
| 255740 | + const char *pText = 0; |
| 255741 | + int nText = 0; |
| 255742 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, 0, 0, &pText, &nText); |
| 255743 | + sqlite3_bind_text(pInsert, i, pText, nText, SQLITE_TRANSIENT); |
| 255744 | + }else{ |
| 255745 | + const u8 *pBlob = (const u8*)sqlite3_value_blob(pVal); |
| 255746 | + int nBlob = sqlite3_value_bytes(pVal); |
| 255747 | + assert( nBlob>4 ); |
| 255748 | + sqlite3_bind_blob(pInsert, i, pBlob+4, nBlob-4, SQLITE_TRANSIENT); |
| 255749 | + } |
| 255750 | + continue; |
| 255751 | + } |
| 255752 | + |
| 255753 | + rc = sqlite3_bind_value(pInsert, i, pVal); |
| 254191 | 255754 | } |
| 254192 | 255755 | if( rc==SQLITE_OK ){ |
| 254193 | 255756 | sqlite3_step(pInsert); |
| 254194 | 255757 | rc = sqlite3_reset(pInsert); |
| 254195 | 255758 | } |
| | @@ -254220,18 +255783,28 @@ |
| 254220 | 255783 | rc = sqlite3Fts5IndexBeginWrite(p->pIndex, 0, iRowid); |
| 254221 | 255784 | } |
| 254222 | 255785 | for(ctx.iCol=0; rc==SQLITE_OK && ctx.iCol<pConfig->nCol; ctx.iCol++){ |
| 254223 | 255786 | ctx.szCol = 0; |
| 254224 | 255787 | if( pConfig->abUnindexed[ctx.iCol]==0 ){ |
| 254225 | | - const char *zText = (const char*)sqlite3_value_text(apVal[ctx.iCol+2]); |
| 254226 | | - int nText = sqlite3_value_bytes(apVal[ctx.iCol+2]); |
| 254227 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 254228 | | - FTS5_TOKENIZE_DOCUMENT, |
| 254229 | | - zText, nText, |
| 254230 | | - (void*)&ctx, |
| 254231 | | - fts5StorageInsertCallback |
| 254232 | | - ); |
| 255788 | + int bReset = 0; /* True if tokenizer locale must be reset */ |
| 255789 | + int nText = 0; /* Size of pText in bytes */ |
| 255790 | + const char *pText = 0; /* Pointer to buffer containing text value */ |
| 255791 | + sqlite3_value *pVal = apVal[ctx.iCol+2]; |
| 255792 | + int bDisk = 0; |
| 255793 | + if( p->pSavedRow && sqlite3_value_nochange(pVal) ){ |
| 255794 | + pVal = sqlite3_column_value(p->pSavedRow, ctx.iCol+1); |
| 255795 | + bDisk = 1; |
| 255796 | + } |
| 255797 | + rc = sqlite3Fts5ExtractText(pConfig, pVal, bDisk, &bReset, &pText,&nText); |
| 255798 | + if( rc==SQLITE_OK ){ |
| 255799 | + assert( bReset==0 || pConfig->bLocale ); |
| 255800 | + rc = sqlite3Fts5Tokenize(pConfig, |
| 255801 | + FTS5_TOKENIZE_DOCUMENT, pText, nText, (void*)&ctx, |
| 255802 | + fts5StorageInsertCallback |
| 255803 | + ); |
| 255804 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 255805 | + } |
| 254233 | 255806 | } |
| 254234 | 255807 | sqlite3Fts5BufferAppendVarint(&rc, &buf, ctx.szCol); |
| 254235 | 255808 | p->aTotalSize[ctx.iCol] += (i64)ctx.szCol; |
| 254236 | 255809 | } |
| 254237 | 255810 | p->nTotalRow++; |
| | @@ -254398,18 +255971,26 @@ |
| 254398 | 255971 | ctx.szCol = 0; |
| 254399 | 255972 | if( pConfig->eDetail==FTS5_DETAIL_COLUMNS ){ |
| 254400 | 255973 | rc = sqlite3Fts5TermsetNew(&ctx.pTermset); |
| 254401 | 255974 | } |
| 254402 | 255975 | if( rc==SQLITE_OK ){ |
| 254403 | | - const char *zText = (const char*)sqlite3_column_text(pScan, i+1); |
| 254404 | | - int nText = sqlite3_column_bytes(pScan, i+1); |
| 254405 | | - rc = sqlite3Fts5Tokenize(pConfig, |
| 254406 | | - FTS5_TOKENIZE_DOCUMENT, |
| 254407 | | - zText, nText, |
| 254408 | | - (void*)&ctx, |
| 254409 | | - fts5StorageIntegrityCallback |
| 255976 | + int bReset = 0; /* True if tokenizer locale must be reset */ |
| 255977 | + int nText = 0; /* Size of pText in bytes */ |
| 255978 | + const char *pText = 0; /* Pointer to buffer containing text value */ |
| 255979 | + |
| 255980 | + rc = sqlite3Fts5ExtractText(pConfig, |
| 255981 | + sqlite3_column_value(pScan, i+1), 1, &bReset, &pText, &nText |
| 254410 | 255982 | ); |
| 255983 | + if( rc==SQLITE_OK ){ |
| 255984 | + rc = sqlite3Fts5Tokenize(pConfig, |
| 255985 | + FTS5_TOKENIZE_DOCUMENT, |
| 255986 | + pText, nText, |
| 255987 | + (void*)&ctx, |
| 255988 | + fts5StorageIntegrityCallback |
| 255989 | + ); |
| 255990 | + if( bReset ) sqlite3Fts5ClearLocale(pConfig); |
| 255991 | + } |
| 254411 | 255992 | } |
| 254412 | 255993 | if( rc==SQLITE_OK && pConfig->bColumnsize && ctx.szCol!=aColSize[i] ){ |
| 254413 | 255994 | rc = FTS5_CORRUPT; |
| 254414 | 255995 | } |
| 254415 | 255996 | aTotalSize[i] += ctx.szCol; |
| | @@ -254720,11 +256301,11 @@ |
| 254720 | 256301 | rc = SQLITE_NOMEM; |
| 254721 | 256302 | }else{ |
| 254722 | 256303 | int i; |
| 254723 | 256304 | memset(p, 0, sizeof(AsciiTokenizer)); |
| 254724 | 256305 | memcpy(p->aTokenChar, aAsciiTokenChar, sizeof(aAsciiTokenChar)); |
| 254725 | | - for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){ |
| 256306 | + for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ |
| 254726 | 256307 | const char *zArg = azArg[i+1]; |
| 254727 | 256308 | if( 0==sqlite3_stricmp(azArg[i], "tokenchars") ){ |
| 254728 | 256309 | fts5AsciiAddExceptions(p, zArg, 1); |
| 254729 | 256310 | }else |
| 254730 | 256311 | if( 0==sqlite3_stricmp(azArg[i], "separators") ){ |
| | @@ -254731,11 +256312,10 @@ |
| 254731 | 256312 | fts5AsciiAddExceptions(p, zArg, 0); |
| 254732 | 256313 | }else{ |
| 254733 | 256314 | rc = SQLITE_ERROR; |
| 254734 | 256315 | } |
| 254735 | 256316 | } |
| 254736 | | - if( rc==SQLITE_OK && i<nArg ) rc = SQLITE_ERROR; |
| 254737 | 256317 | if( rc!=SQLITE_OK ){ |
| 254738 | 256318 | fts5AsciiDelete((Fts5Tokenizer*)p); |
| 254739 | 256319 | p = 0; |
| 254740 | 256320 | } |
| 254741 | 256321 | } |
| | @@ -255023,20 +256603,20 @@ |
| 255023 | 256603 | if( p->aFold==0 ){ |
| 255024 | 256604 | rc = SQLITE_NOMEM; |
| 255025 | 256605 | } |
| 255026 | 256606 | |
| 255027 | 256607 | /* Search for a "categories" argument */ |
| 255028 | | - for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){ |
| 256608 | + for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ |
| 255029 | 256609 | if( 0==sqlite3_stricmp(azArg[i], "categories") ){ |
| 255030 | 256610 | zCat = azArg[i+1]; |
| 255031 | 256611 | } |
| 255032 | 256612 | } |
| 255033 | 256613 | if( rc==SQLITE_OK ){ |
| 255034 | 256614 | rc = unicodeSetCategories(p, zCat); |
| 255035 | 256615 | } |
| 255036 | 256616 | |
| 255037 | | - for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){ |
| 256617 | + for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ |
| 255038 | 256618 | const char *zArg = azArg[i+1]; |
| 255039 | 256619 | if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ |
| 255040 | 256620 | if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ |
| 255041 | 256621 | rc = SQLITE_ERROR; |
| 255042 | 256622 | }else{ |
| | @@ -255057,12 +256637,10 @@ |
| 255057 | 256637 | /* no-op */ |
| 255058 | 256638 | }else{ |
| 255059 | 256639 | rc = SQLITE_ERROR; |
| 255060 | 256640 | } |
| 255061 | 256641 | } |
| 255062 | | - if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR; |
| 255063 | | - |
| 255064 | 256642 | }else{ |
| 255065 | 256643 | rc = SQLITE_NOMEM; |
| 255066 | 256644 | } |
| 255067 | 256645 | if( rc!=SQLITE_OK ){ |
| 255068 | 256646 | fts5UnicodeDelete((Fts5Tokenizer*)p); |
| | @@ -255197,11 +256775,11 @@ |
| 255197 | 256775 | ** stemming. */ |
| 255198 | 256776 | #define FTS5_PORTER_MAX_TOKEN 64 |
| 255199 | 256777 | |
| 255200 | 256778 | typedef struct PorterTokenizer PorterTokenizer; |
| 255201 | 256779 | struct PorterTokenizer { |
| 255202 | | - fts5_tokenizer tokenizer; /* Parent tokenizer module */ |
| 256780 | + fts5_tokenizer_v2 tokenizer_v2; /* Parent tokenizer module */ |
| 255203 | 256781 | Fts5Tokenizer *pTokenizer; /* Parent tokenizer instance */ |
| 255204 | 256782 | char aBuf[FTS5_PORTER_MAX_TOKEN + 64]; |
| 255205 | 256783 | }; |
| 255206 | 256784 | |
| 255207 | 256785 | /* |
| | @@ -255209,11 +256787,11 @@ |
| 255209 | 256787 | */ |
| 255210 | 256788 | static void fts5PorterDelete(Fts5Tokenizer *pTok){ |
| 255211 | 256789 | if( pTok ){ |
| 255212 | 256790 | PorterTokenizer *p = (PorterTokenizer*)pTok; |
| 255213 | 256791 | if( p->pTokenizer ){ |
| 255214 | | - p->tokenizer.xDelete(p->pTokenizer); |
| 256792 | + p->tokenizer_v2.xDelete(p->pTokenizer); |
| 255215 | 256793 | } |
| 255216 | 256794 | sqlite3_free(p); |
| 255217 | 256795 | } |
| 255218 | 256796 | } |
| 255219 | 256797 | |
| | @@ -255228,26 +256806,28 @@ |
| 255228 | 256806 | fts5_api *pApi = (fts5_api*)pCtx; |
| 255229 | 256807 | int rc = SQLITE_OK; |
| 255230 | 256808 | PorterTokenizer *pRet; |
| 255231 | 256809 | void *pUserdata = 0; |
| 255232 | 256810 | const char *zBase = "unicode61"; |
| 256811 | + fts5_tokenizer_v2 *pV2 = 0; |
| 255233 | 256812 | |
| 255234 | 256813 | if( nArg>0 ){ |
| 255235 | 256814 | zBase = azArg[0]; |
| 255236 | 256815 | } |
| 255237 | 256816 | |
| 255238 | 256817 | pRet = (PorterTokenizer*)sqlite3_malloc(sizeof(PorterTokenizer)); |
| 255239 | 256818 | if( pRet ){ |
| 255240 | 256819 | memset(pRet, 0, sizeof(PorterTokenizer)); |
| 255241 | | - rc = pApi->xFindTokenizer(pApi, zBase, &pUserdata, &pRet->tokenizer); |
| 256820 | + rc = pApi->xFindTokenizer_v2(pApi, zBase, &pUserdata, &pV2); |
| 255242 | 256821 | }else{ |
| 255243 | 256822 | rc = SQLITE_NOMEM; |
| 255244 | 256823 | } |
| 255245 | 256824 | if( rc==SQLITE_OK ){ |
| 255246 | 256825 | int nArg2 = (nArg>0 ? nArg-1 : 0); |
| 255247 | | - const char **azArg2 = (nArg2 ? &azArg[1] : 0); |
| 255248 | | - rc = pRet->tokenizer.xCreate(pUserdata, azArg2, nArg2, &pRet->pTokenizer); |
| 256826 | + const char **az2 = (nArg2 ? &azArg[1] : 0); |
| 256827 | + memcpy(&pRet->tokenizer_v2, pV2, sizeof(fts5_tokenizer_v2)); |
| 256828 | + rc = pRet->tokenizer_v2.xCreate(pUserdata, az2, nArg2, &pRet->pTokenizer); |
| 255249 | 256829 | } |
| 255250 | 256830 | |
| 255251 | 256831 | if( rc!=SQLITE_OK ){ |
| 255252 | 256832 | fts5PorterDelete((Fts5Tokenizer*)pRet); |
| 255253 | 256833 | pRet = 0; |
| | @@ -255894,19 +257474,20 @@ |
| 255894 | 257474 | static int fts5PorterTokenize( |
| 255895 | 257475 | Fts5Tokenizer *pTokenizer, |
| 255896 | 257476 | void *pCtx, |
| 255897 | 257477 | int flags, |
| 255898 | 257478 | const char *pText, int nText, |
| 257479 | + const char *pLoc, int nLoc, |
| 255899 | 257480 | int (*xToken)(void*, int, const char*, int nToken, int iStart, int iEnd) |
| 255900 | 257481 | ){ |
| 255901 | 257482 | PorterTokenizer *p = (PorterTokenizer*)pTokenizer; |
| 255902 | 257483 | PorterContext sCtx; |
| 255903 | 257484 | sCtx.xToken = xToken; |
| 255904 | 257485 | sCtx.pCtx = pCtx; |
| 255905 | 257486 | sCtx.aBuf = p->aBuf; |
| 255906 | | - return p->tokenizer.xTokenize( |
| 255907 | | - p->pTokenizer, (void*)&sCtx, flags, pText, nText, fts5PorterCb |
| 257487 | + return p->tokenizer_v2.xTokenize( |
| 257488 | + p->pTokenizer, (void*)&sCtx, flags, pText, nText, pLoc, nLoc, fts5PorterCb |
| 255908 | 257489 | ); |
| 255909 | 257490 | } |
| 255910 | 257491 | |
| 255911 | 257492 | /************************************************************************** |
| 255912 | 257493 | ** Start of trigram implementation. |
| | @@ -255932,45 +257513,50 @@ |
| 255932 | 257513 | const char **azArg, |
| 255933 | 257514 | int nArg, |
| 255934 | 257515 | Fts5Tokenizer **ppOut |
| 255935 | 257516 | ){ |
| 255936 | 257517 | int rc = SQLITE_OK; |
| 255937 | | - TrigramTokenizer *pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); |
| 257518 | + TrigramTokenizer *pNew = 0; |
| 255938 | 257519 | UNUSED_PARAM(pUnused); |
| 255939 | | - if( pNew==0 ){ |
| 255940 | | - rc = SQLITE_NOMEM; |
| 257520 | + if( nArg%2 ){ |
| 257521 | + rc = SQLITE_ERROR; |
| 255941 | 257522 | }else{ |
| 255942 | 257523 | int i; |
| 255943 | | - pNew->bFold = 1; |
| 255944 | | - pNew->iFoldParam = 0; |
| 255945 | | - for(i=0; rc==SQLITE_OK && i<nArg-1; i+=2){ |
| 255946 | | - const char *zArg = azArg[i+1]; |
| 255947 | | - if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){ |
| 255948 | | - if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){ |
| 255949 | | - rc = SQLITE_ERROR; |
| 255950 | | - }else{ |
| 255951 | | - pNew->bFold = (zArg[0]=='0'); |
| 255952 | | - } |
| 255953 | | - }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ |
| 255954 | | - if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ |
| 255955 | | - rc = SQLITE_ERROR; |
| 255956 | | - }else{ |
| 255957 | | - pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; |
| 255958 | | - } |
| 255959 | | - }else{ |
| 255960 | | - rc = SQLITE_ERROR; |
| 255961 | | - } |
| 255962 | | - } |
| 255963 | | - if( i<nArg && rc==SQLITE_OK ) rc = SQLITE_ERROR; |
| 255964 | | - |
| 255965 | | - if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ |
| 255966 | | - rc = SQLITE_ERROR; |
| 255967 | | - } |
| 255968 | | - |
| 255969 | | - if( rc!=SQLITE_OK ){ |
| 255970 | | - fts5TriDelete((Fts5Tokenizer*)pNew); |
| 255971 | | - pNew = 0; |
| 257524 | + pNew = (TrigramTokenizer*)sqlite3_malloc(sizeof(*pNew)); |
| 257525 | + if( pNew==0 ){ |
| 257526 | + rc = SQLITE_NOMEM; |
| 257527 | + }else{ |
| 257528 | + pNew->bFold = 1; |
| 257529 | + pNew->iFoldParam = 0; |
| 257530 | + |
| 257531 | + for(i=0; rc==SQLITE_OK && i<nArg; i+=2){ |
| 257532 | + const char *zArg = azArg[i+1]; |
| 257533 | + if( 0==sqlite3_stricmp(azArg[i], "case_sensitive") ){ |
| 257534 | + if( (zArg[0]!='0' && zArg[0]!='1') || zArg[1] ){ |
| 257535 | + rc = SQLITE_ERROR; |
| 257536 | + }else{ |
| 257537 | + pNew->bFold = (zArg[0]=='0'); |
| 257538 | + } |
| 257539 | + }else if( 0==sqlite3_stricmp(azArg[i], "remove_diacritics") ){ |
| 257540 | + if( (zArg[0]!='0' && zArg[0]!='1' && zArg[0]!='2') || zArg[1] ){ |
| 257541 | + rc = SQLITE_ERROR; |
| 257542 | + }else{ |
| 257543 | + pNew->iFoldParam = (zArg[0]!='0') ? 2 : 0; |
| 257544 | + } |
| 257545 | + }else{ |
| 257546 | + rc = SQLITE_ERROR; |
| 257547 | + } |
| 257548 | + } |
| 257549 | + |
| 257550 | + if( pNew->iFoldParam!=0 && pNew->bFold==0 ){ |
| 257551 | + rc = SQLITE_ERROR; |
| 257552 | + } |
| 257553 | + |
| 257554 | + if( rc!=SQLITE_OK ){ |
| 257555 | + fts5TriDelete((Fts5Tokenizer*)pNew); |
| 257556 | + pNew = 0; |
| 257557 | + } |
| 255972 | 257558 | } |
| 255973 | 257559 | } |
| 255974 | 257560 | *ppOut = (Fts5Tokenizer*)pNew; |
| 255975 | 257561 | return rc; |
| 255976 | 257562 | } |
| | @@ -256091,11 +257677,10 @@ |
| 256091 | 257677 | const char *zName; |
| 256092 | 257678 | fts5_tokenizer x; |
| 256093 | 257679 | } aBuiltin[] = { |
| 256094 | 257680 | { "unicode61", {fts5UnicodeCreate, fts5UnicodeDelete, fts5UnicodeTokenize}}, |
| 256095 | 257681 | { "ascii", {fts5AsciiCreate, fts5AsciiDelete, fts5AsciiTokenize }}, |
| 256096 | | - { "porter", {fts5PorterCreate, fts5PorterDelete, fts5PorterTokenize }}, |
| 256097 | 257682 | { "trigram", {fts5TriCreate, fts5TriDelete, fts5TriTokenize}}, |
| 256098 | 257683 | }; |
| 256099 | 257684 | |
| 256100 | 257685 | int rc = SQLITE_OK; /* Return code */ |
| 256101 | 257686 | int i; /* To iterate through builtin functions */ |
| | @@ -256106,11 +257691,24 @@ |
| 256106 | 257691 | (void*)pApi, |
| 256107 | 257692 | &aBuiltin[i].x, |
| 256108 | 257693 | 0 |
| 256109 | 257694 | ); |
| 256110 | 257695 | } |
| 256111 | | - |
| 257696 | + if( rc==SQLITE_OK ){ |
| 257697 | + fts5_tokenizer_v2 sPorter = { |
| 257698 | + 2, |
| 257699 | + fts5PorterCreate, |
| 257700 | + fts5PorterDelete, |
| 257701 | + fts5PorterTokenize |
| 257702 | + }; |
| 257703 | + rc = pApi->xCreateTokenizer_v2(pApi, |
| 257704 | + "porter", |
| 257705 | + (void*)pApi, |
| 257706 | + &sPorter, |
| 257707 | + 0 |
| 257708 | + ); |
| 257709 | + } |
| 256112 | 257710 | return rc; |
| 256113 | 257711 | } |
| 256114 | 257712 | |
| 256115 | 257713 | /* |
| 256116 | 257714 | ** 2012-05-25 |
| | @@ -256476,10 +258074,13 @@ |
| 256476 | 258074 | aArray[29] = 1; |
| 256477 | 258075 | break; |
| 256478 | 258076 | default: return 1; } |
| 256479 | 258077 | break; |
| 256480 | 258078 | |
| 258079 | + |
| 258080 | + default: |
| 258081 | + return 1; |
| 256481 | 258082 | } |
| 256482 | 258083 | return 0; |
| 256483 | 258084 | } |
| 256484 | 258085 | |
| 256485 | 258086 | static u16 aFts5UnicodeBlock[] = { |
| 256486 | 258087 | |