Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Merge latest trunk changes into this branch. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | exp-window-functions |
Files: | files | file ages | folders |
SHA3-256: |
cdb68d2c64e453fdcd29437d5915c5c5 |
User & Date: | dan 2018-05-22 20:36:12.808 |
Context
2018-05-23
| ||
20:55 | Add support for "ROWS BETWEEN <expr> PRECEDING AND <expr> FOLLOWING" window frames. (check-in: 3a203660f1 user: dan tags: exp-window-functions) | |
2018-05-22
| ||
20:36 | Merge latest trunk changes into this branch. (check-in: cdb68d2c64 user: dan tags: exp-window-functions) | |
20:35 | Add comments to window.c describing how other window frames will be implemented. (check-in: 16168146b2 user: dan tags: exp-window-functions) | |
2018-05-18
| ||
17:58 | Add support for auxiliary columns to the rtree extension. (check-in: c6071ac99c user: drh tags: trunk) | |
Changes
Changes to ext/rtree/rtree.c.
︙ | ︙ | |||
20 21 22 23 24 25 26 | ** The data structure for a single virtual r-tree table is stored in three ** native SQLite tables declared as follows. In each case, the '%' character ** in the table name is replaced with the user-supplied name of the r-tree ** table. ** ** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB) ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) | | | > | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | ** The data structure for a single virtual r-tree table is stored in three ** native SQLite tables declared as follows. In each case, the '%' character ** in the table name is replaced with the user-supplied name of the r-tree ** table. ** ** CREATE TABLE %_node(nodeno INTEGER PRIMARY KEY, data BLOB) ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) ** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) ** ** The data for each node of the r-tree structure is stored in the %_node ** table. For each node that is not the root node of the r-tree, there is ** an entry in the %_parent table associating the node with its parent. ** And for each row of data in the table, there is an entry in the %_rowid ** table that maps from the entries rowid to the id of the node that it ** is stored on. If the r-tree contains auxiliary columns, those are stored ** on the end of the %_rowid table. ** ** The root node of an r-tree always exists, even if the r-tree table is ** empty. The nodeno of the root node is always 1. All other nodes in the ** table must be the same size as the root node. The content of each node ** is formatted as follows: ** ** 1. If the node is the root node (node 1), then the first 2 bytes |
︙ | ︙ | |||
89 90 91 92 93 94 95 96 97 98 99 100 101 102 | typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 /* Size of hash table Rtree.aHash. This hash table is not expected to ** ever contain very many entries, so a fixed number of buckets is ** used. */ #define HASHSIZE 97 | > > > | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | typedef struct RtreeMatchArg RtreeMatchArg; typedef struct RtreeGeomCallback RtreeGeomCallback; typedef union RtreeCoord RtreeCoord; typedef struct RtreeSearchPoint RtreeSearchPoint; /* The rtree may have between 1 and RTREE_MAX_DIMENSIONS dimensions. */ #define RTREE_MAX_DIMENSIONS 5 /* Maximum number of auxiliary columns */ #define RTREE_MAX_AUX_COLUMN 100 /* Size of hash table Rtree.aHash. This hash table is not expected to ** ever contain very many entries, so a fixed number of buckets is ** used. */ #define HASHSIZE 97 |
︙ | ︙ | |||
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ RtreeNode *pDeleted; | > > | 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | sqlite3 *db; /* Host database connection */ int iNodeSize; /* Size in bytes of each node in the node table */ u8 nDim; /* Number of dimensions */ u8 nDim2; /* Twice the number of dimensions */ u8 eCoordType; /* RTREE_COORD_REAL32 or RTREE_COORD_INT32 */ u8 nBytesPerCell; /* Bytes consumed per cell */ u8 inWrTrans; /* True if inside write transaction */ u8 nAux; /* # of auxiliary columns in %_rowid */ int iDepth; /* Current depth of the r-tree structure */ char *zDb; /* Name of database containing r-tree table */ char *zName; /* Name of r-tree table */ u32 nBusy; /* Current number of users of this structure */ i64 nRowEst; /* Estimated number of rows in this table */ u32 nCursor; /* Number of open cursors */ char *zReadAuxSql; /* SQL for statement to read aux data */ /* List of nodes removed during a CondenseTree operation. List is ** linked together via the pointer normally used for hash chains - ** RtreeNode.pNext. RtreeNode.iNode stores the depth of the sub-tree ** headed by the node (leaf nodes have RtreeNode.iNode==0). */ RtreeNode *pDeleted; |
︙ | ︙ | |||
149 150 151 152 153 154 155 156 157 158 159 160 161 162 | sqlite3_stmt *pWriteRowid; sqlite3_stmt *pDeleteRowid; /* Statements to read/write/delete a record from xxx_parent */ sqlite3_stmt *pReadParent; sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ }; /* Possible values for Rtree.eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 | > > > | 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 | sqlite3_stmt *pWriteRowid; sqlite3_stmt *pDeleteRowid; /* Statements to read/write/delete a record from xxx_parent */ sqlite3_stmt *pReadParent; sqlite3_stmt *pWriteParent; sqlite3_stmt *pDeleteParent; /* Statement for writing to the "aux:" fields, if there are any */ sqlite3_stmt *pWriteAux; RtreeNode *aHash[HASHSIZE]; /* Hash table of in-memory nodes. */ }; /* Possible values for Rtree.eCoordType: */ #define RTREE_COORD_REAL32 0 #define RTREE_COORD_INT32 1 |
︙ | ︙ | |||
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | /* ** An rtree cursor object. */ struct RtreeCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ u8 atEOF; /* True if at end of search */ u8 bPoint; /* True if sPoint is valid */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ int nPointAlloc; /* Number of slots allocated for aPoint[] */ int nPoint; /* Number of slots used in aPoint[] */ int mxLevel; /* iLevel value for root of the tree */ RtreeSearchPoint *aPoint; /* Priority queue for search points */ RtreeSearchPoint sPoint; /* Cached next search point */ RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; /* Return the Rtree of a RtreeCursor */ #define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) | > > | 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | /* ** An rtree cursor object. */ struct RtreeCursor { sqlite3_vtab_cursor base; /* Base class. Must be first */ u8 atEOF; /* True if at end of search */ u8 bPoint; /* True if sPoint is valid */ u8 bAuxValid; /* True if pReadAux is valid */ int iStrategy; /* Copy of idxNum search parameter */ int nConstraint; /* Number of entries in aConstraint */ RtreeConstraint *aConstraint; /* Search constraints. */ int nPointAlloc; /* Number of slots allocated for aPoint[] */ int nPoint; /* Number of slots used in aPoint[] */ int mxLevel; /* iLevel value for root of the tree */ RtreeSearchPoint *aPoint; /* Priority queue for search points */ sqlite3_stmt *pReadAux; /* Statement to read aux-data */ RtreeSearchPoint sPoint; /* Cached next search point */ RtreeNode *aNode[RTREE_CACHE_SZ]; /* Rtree node cache */ u32 anQueue[RTREE_MAX_DEPTH+1]; /* Number of queued entries by iLevel */ }; /* Return the Rtree of a RtreeCursor */ #define RTREE_OF_CURSOR(X) ((Rtree*)((X)->base.pVtab)) |
︙ | ︙ | |||
926 927 928 929 930 931 932 933 934 935 936 937 938 939 | sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); sqlite3_finalize(pRtree->pWriteRowid); sqlite3_finalize(pRtree->pDeleteRowid); sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); sqlite3_finalize(pRtree->pDeleteParent); sqlite3_free(pRtree); } } /* ** Rtree virtual table module xDisconnect method. */ | > > | 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 | sqlite3_finalize(pRtree->pDeleteNode); sqlite3_finalize(pRtree->pReadRowid); sqlite3_finalize(pRtree->pWriteRowid); sqlite3_finalize(pRtree->pDeleteRowid); sqlite3_finalize(pRtree->pReadParent); sqlite3_finalize(pRtree->pWriteParent); sqlite3_finalize(pRtree->pDeleteParent); sqlite3_finalize(pRtree->pWriteAux); sqlite3_free(pRtree->zReadAuxSql); sqlite3_free(pRtree); } } /* ** Rtree virtual table module xDisconnect method. */ |
︙ | ︙ | |||
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 | */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]); sqlite3_free(pCsr); pRtree->nCursor--; nodeBlobReset(pRtree); return SQLITE_OK; } | > | 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 | */ static int rtreeClose(sqlite3_vtab_cursor *cur){ Rtree *pRtree = (Rtree *)(cur->pVtab); int ii; RtreeCursor *pCsr = (RtreeCursor *)cur; assert( pRtree->nCursor>0 ); freeCursorConstraints(pCsr); sqlite3_finalize(pCsr->pReadAux); sqlite3_free(pCsr->aPoint); for(ii=0; ii<RTREE_CACHE_SZ; ii++) nodeRelease(pRtree, pCsr->aNode[ii]); sqlite3_free(pCsr); pRtree->nCursor--; nodeBlobReset(pRtree); return SQLITE_OK; } |
︙ | ︙ | |||
1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 | */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; /* Move to the next entry that matches the configured constraints. */ RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); rtreeSearchPointPop(pCsr); rc = rtreeStepToLeaf(pCsr); return rc; } /* ** Rtree virtual table module xRowid method. | > > > > | 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 | */ static int rtreeNext(sqlite3_vtab_cursor *pVtabCursor){ RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; int rc = SQLITE_OK; /* Move to the next entry that matches the configured constraints. */ RTREE_QUEUE_TRACE(pCsr, "POP-Nx:"); if( pCsr->bAuxValid ){ pCsr->bAuxValid = 0; sqlite3_reset(pCsr->pReadAux); } rtreeSearchPointPop(pCsr); rc = rtreeStepToLeaf(pCsr); return rc; } /* ** Rtree virtual table module xRowid method. |
︙ | ︙ | |||
1590 1591 1592 1593 1594 1595 1596 | int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( p==0 ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); | | > > > > > > | > > > > > > > > > > > > > > | 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 | int rc = SQLITE_OK; RtreeNode *pNode = rtreeNodeOfFirstSearchPoint(pCsr, &rc); if( rc ) return rc; if( p==0 ) return SQLITE_OK; if( i==0 ){ sqlite3_result_int64(ctx, nodeGetRowid(pRtree, pNode, p->iCell)); }else if( i<=pRtree->nDim2 ){ nodeGetCoord(pRtree, pNode, p->iCell, i-1, &c); #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ sqlite3_result_double(ctx, c.f); }else #endif { assert( pRtree->eCoordType==RTREE_COORD_INT32 ); sqlite3_result_int(ctx, c.i); } }else{ if( !pCsr->bAuxValid ){ if( pCsr->pReadAux==0 ){ rc = sqlite3_prepare_v3(pRtree->db, pRtree->zReadAuxSql, -1, 0, &pCsr->pReadAux, 0); if( rc ) return rc; } sqlite3_bind_int64(pCsr->pReadAux, 1, nodeGetRowid(pRtree, pNode, p->iCell)); rc = sqlite3_step(pCsr->pReadAux); if( rc==SQLITE_ROW ){ pCsr->bAuxValid = 1; }else{ sqlite3_reset(pCsr->pReadAux); if( rc==SQLITE_DONE ) rc = SQLITE_OK; return rc; } } sqlite3_result_value(ctx, sqlite3_column_value(pCsr->pReadAux, i - pRtree->nDim2 + 1)); } return SQLITE_OK; } /* ** Use nodeAcquire() to obtain the leaf node containing the record with ** rowid iRowid. If successful, set *ppLeaf to point to the node and ** return SQLITE_OK. If there is no such record in the table, set |
︙ | ︙ | |||
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 | ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); | > > > | 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 | ){ Rtree *pRtree = (Rtree *)pVtabCursor->pVtab; RtreeCursor *pCsr = (RtreeCursor *)pVtabCursor; RtreeNode *pRoot = 0; int ii; int rc = SQLITE_OK; int iCell = 0; sqlite3_stmt *pStmt; rtreeReference(pRtree); /* Reset the cursor to the same state as rtreeOpen() leaves it in. */ freeCursorConstraints(pCsr); sqlite3_free(pCsr->aPoint); pStmt = pCsr->pReadAux; memset(pCsr, 0, sizeof(RtreeCursor)); pCsr->base.pVtab = (sqlite3_vtab*)pRtree; pCsr->pReadAux = pStmt; pCsr->iStrategy = idxNum; if( idxNum==1 ){ /* Special case - lookup by rowid. */ RtreeNode *pLeaf; /* Leaf on which the required cell resides */ RtreeSearchPoint *p; /* Search point for the leaf */ i64 iRowid = sqlite3_value_int64(argv[0]); |
︙ | ︙ | |||
1852 1853 1854 1855 1856 1857 1858 | ** a single row. */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; return SQLITE_OK; } | > > | > | 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 | ** a single row. */ pIdxInfo->estimatedCost = 30.0; pIdxInfo->estimatedRows = 1; return SQLITE_OK; } if( p->usable && ((p->iColumn>0 && p->iColumn<=pRtree->nDim2) || p->op==SQLITE_INDEX_CONSTRAINT_MATCH) ){ u8 op; switch( p->op ){ case SQLITE_INDEX_CONSTRAINT_EQ: op = RTREE_EQ; break; case SQLITE_INDEX_CONSTRAINT_GT: op = RTREE_GT; break; case SQLITE_INDEX_CONSTRAINT_LE: op = RTREE_LE; break; case SQLITE_INDEX_CONSTRAINT_LT: op = RTREE_LT; break; case SQLITE_INDEX_CONSTRAINT_GE: op = RTREE_GE; break; |
︙ | ︙ | |||
3011 3012 3013 3014 3015 3016 3017 | /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, | | | 3055 3056 3057 3058 3059 3060 3061 3062 3063 3064 3065 3066 3067 3068 3069 | /* ** The xUpdate method for rtree module virtual tables. */ static int rtreeUpdate( sqlite3_vtab *pVtab, int nData, sqlite3_value **aData, sqlite_int64 *pRowid ){ Rtree *pRtree = (Rtree *)pVtab; int rc = SQLITE_OK; RtreeCell cell; /* New cell to insert if nData>1 */ int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ |
︙ | ︙ | |||
3037 3038 3039 3040 3041 3042 3043 3044 | ** In the first case, if the conflict-handling mode is REPLACE, then ** the conflicting row can be removed before proceeding. In the second ** case, SQLITE_CONSTRAINT must be returned regardless of the ** conflict-handling mode specified by the user. */ if( nData>1 ){ int ii; | > > | < | | | | | | | | | | | | | | | | 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 | ** In the first case, if the conflict-handling mode is REPLACE, then ** the conflicting row can be removed before proceeding. In the second ** case, SQLITE_CONSTRAINT must be returned regardless of the ** conflict-handling mode specified by the user. */ if( nData>1 ){ int ii; int nn = nData - 4; if( nn > pRtree->nDim2 ) nn = pRtree->nDim2; /* Populate the cell.aCoord[] array. The first coordinate is aData[3]. ** ** NB: nData can only be less than nDim*2+3 if the rtree is mis-declared ** with "column" that are interpreted as table constraints. ** Example: CREATE VIRTUAL TABLE bad USING rtree(x,y,CHECK(y>5)); ** This problem was discovered after years of use, so we silently ignore ** these kinds of misdeclared tables to avoid breaking any legacy. */ #ifndef SQLITE_RTREE_INT_ONLY if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ for(ii=0; ii<nn; ii+=2){ cell.aCoord[ii].f = rtreeValueDown(aData[ii+3]); cell.aCoord[ii+1].f = rtreeValueUp(aData[ii+4]); if( cell.aCoord[ii].f>cell.aCoord[ii+1].f ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } }else #endif { for(ii=0; ii<nn; ii+=2){ cell.aCoord[ii].i = sqlite3_value_int(aData[ii+3]); cell.aCoord[ii+1].i = sqlite3_value_int(aData[ii+4]); if( cell.aCoord[ii].i>cell.aCoord[ii+1].i ){ rc = rtreeConstraintError(pRtree, ii+1); goto constraint; } } } /* If a rowid value was supplied, check if it is already present in ** the table. If so, the constraint has failed. */ if( sqlite3_value_type(aData[2])!=SQLITE_NULL ){ cell.iRowid = sqlite3_value_int64(aData[2]); if( sqlite3_value_type(aData[0])==SQLITE_NULL || sqlite3_value_int64(aData[0])!=cell.iRowid ){ int steprc; sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); steprc = sqlite3_step(pRtree->pReadRowid); rc = sqlite3_reset(pRtree->pReadRowid); if( SQLITE_ROW==steprc ){ if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ rc = rtreeDeleteRowid(pRtree, cell.iRowid); }else{ rc = rtreeConstraintError(pRtree, 0); goto constraint; } } } bHaveRowid = 1; } } /* If aData[0] is not an SQL NULL value, it is the rowid of a ** record to delete from the r-tree table. The following block does ** just that. */ if( sqlite3_value_type(aData[0])!=SQLITE_NULL ){ rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(aData[0])); } /* If the aData[] array contains more than one element, elements ** (aData[2]..aData[argc-1]) contain a new record to insert into ** the r-tree structure. */ if( rc==SQLITE_OK && nData>1 ){ /* Insert the new record into the r-tree */ RtreeNode *pLeaf = 0; /* Figure out the rowid of the new row. */ |
︙ | ︙ | |||
3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 | pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } } constraint: rtreeRelease(pRtree); return rc; } | > > > > > > > > > > | 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 | pRtree->iReinsertHeight = -1; rc = rtreeInsertCell(pRtree, pLeaf, &cell, 0); rc2 = nodeRelease(pRtree, pLeaf); if( rc==SQLITE_OK ){ rc = rc2; } } if( pRtree->nAux ){ sqlite3_stmt *pUp = pRtree->pWriteAux; int jj; sqlite3_bind_int64(pUp, 1, *pRowid); for(jj=0; jj<pRtree->nAux; jj++){ sqlite3_bind_value(pUp, jj+2, aData[pRtree->nDim2+3+jj]); } sqlite3_step(pUp); rc = sqlite3_reset(pUp); } } constraint: rtreeRelease(pRtree); return rc; } |
︙ | ︙ | |||
3285 3286 3287 3288 3289 3290 3291 | int isCreate ){ int rc = SQLITE_OK; #define N_STATEMENT 8 static const char *azSql[N_STATEMENT] = { /* Write the xxx_node table */ | | | | | | | | | | | > > | > > > > > > > > | | > | | | | 3340 3341 3342 3343 3344 3345 3346 3347 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 | int isCreate ){ int rc = SQLITE_OK; #define N_STATEMENT 8 static const char *azSql[N_STATEMENT] = { /* Write the xxx_node table */ "INSERT OR REPLACE INTO '%q'.'%q_node' VALUES(?1, ?2)", "DELETE FROM '%q'.'%q_node' WHERE nodeno = ?1", /* Read and write the xxx_rowid table */ "SELECT nodeno FROM '%q'.'%q_rowid' WHERE rowid = ?1", "INSERT OR REPLACE INTO '%q'.'%q_rowid' VALUES(?1, ?2)", "DELETE FROM '%q'.'%q_rowid' WHERE rowid = ?1", /* Read and write the xxx_parent table */ "SELECT parentnode FROM '%q'.'%q_parent' WHERE nodeno = ?1", "INSERT OR REPLACE INTO '%q'.'%q_parent' VALUES(?1, ?2)", "DELETE FROM '%q'.'%q_parent' WHERE nodeno = ?1" }; sqlite3_stmt **appStmt[N_STATEMENT]; int i; pRtree->db = db; if( isCreate ){ char *zCreate; sqlite3_str *p = sqlite3_str_new(db); int ii; sqlite3_str_appendf(p, "CREATE TABLE \"%w\".\"%w_rowid\"(rowid INTEGER PRIMARY KEY,nodeno", zDb, zPrefix); for(ii=0; ii<pRtree->nAux; ii++){ sqlite3_str_appendf(p,",a%d",ii); } sqlite3_str_appendf(p, ");CREATE TABLE \"%w\".\"%w_node\"(nodeno INTEGER PRIMARY KEY,data);", zDb, zPrefix); sqlite3_str_appendf(p, "CREATE TABLE \"%w\".\"%w_parent\"(nodeno INTEGER PRIMARY KEY,parentnode);", zDb, zPrefix); sqlite3_str_appendf(p, "INSERT INTO \"%w\".\"%w_node\"VALUES(1,zeroblob(%d))", zDb, zPrefix, pRtree->iNodeSize); zCreate = sqlite3_str_finish(p); if( !zCreate ){ return SQLITE_NOMEM; } rc = sqlite3_exec(db, zCreate, 0, 0, 0); sqlite3_free(zCreate); if( rc!=SQLITE_OK ){ return rc; |
︙ | ︙ | |||
3333 3334 3335 3336 3337 3338 3339 | appStmt[4] = &pRtree->pDeleteRowid; appStmt[5] = &pRtree->pReadParent; appStmt[6] = &pRtree->pWriteParent; appStmt[7] = &pRtree->pDeleteParent; rc = rtreeQueryStat1(db, pRtree); for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){ | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 | appStmt[4] = &pRtree->pDeleteRowid; appStmt[5] = &pRtree->pReadParent; appStmt[6] = &pRtree->pWriteParent; appStmt[7] = &pRtree->pDeleteParent; rc = rtreeQueryStat1(db, pRtree); for(i=0; i<N_STATEMENT && rc==SQLITE_OK; i++){ char *zSql; const char *zFormat; if( i!=3 || pRtree->nAux==0 ){ zFormat = azSql[i]; }else { /* An UPSERT is very slightly slower than REPLACE, but it is needed ** if there are auxiliary columns */ zFormat = "INSERT INTO\"%w\".\"%w_rowid\"(rowid,nodeno)VALUES(?1,?2)" "ON CONFLICT(rowid)DO UPDATE SET nodeno=excluded.nodeno"; } zSql = sqlite3_mprintf(zFormat, zDb, zPrefix); if( zSql ){ rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, appStmt[i], 0); }else{ rc = SQLITE_NOMEM; } sqlite3_free(zSql); } if( pRtree->nAux ){ pRtree->zReadAuxSql = sqlite3_mprintf( "SELECT * FROM \"%w\".\"%w_rowid\" WHERE rowid=?1", zDb, zPrefix); if( pRtree->zReadAuxSql==0 ){ rc = SQLITE_NOMEM; }else{ sqlite3_str *p = sqlite3_str_new(db); int ii; char *zSql; sqlite3_str_appendf(p, "UPDATE \"%w\".\"%w_rowid\"SET ", zDb, zPrefix); for(ii=0; ii<pRtree->nAux; ii++){ if( ii ) sqlite3_str_append(p, ",", 1); sqlite3_str_appendf(p,"a%d=?%d",ii,ii+2); } sqlite3_str_appendf(p, " WHERE rowid=?1"); zSql = sqlite3_str_finish(p); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_prepare_v3(db, zSql, -1, SQLITE_PREPARE_PERSISTENT, &pRtree->pWriteAux, 0); sqlite3_free(zSql); } } } return rc; } /* ** The second argument to this function contains the text of an SQL statement |
︙ | ︙ | |||
3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 | int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; int nDb; /* Length of string argv[1] */ int nName; /* Length of string argv[2] */ int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); const char *aErrMsg[] = { 0, /* 0 */ "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ | > > > > | > | | | < < < < < < < < < | < < < < < | | > > | > > > > > | > | | > > > > > > > | | > > > > > | | > > > > > | > | | | > > > > > > > < | > | > > | | | < | 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 3606 3607 3608 3609 3610 3611 3612 3613 3614 3615 3616 3617 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 3633 3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 3656 3657 3658 3659 | int isCreate /* True for xCreate, false for xConnect */ ){ int rc = SQLITE_OK; Rtree *pRtree; int nDb; /* Length of string argv[1] */ int nName; /* Length of string argv[2] */ int eCoordType = (pAux ? RTREE_COORD_INT32 : RTREE_COORD_REAL32); sqlite3_str *pSql; char *zSql; int ii = 4; int iErr; const char *aErrMsg[] = { 0, /* 0 */ "Wrong number of columns for an rtree table", /* 1 */ "Too few columns for an rtree table", /* 2 */ "Too many columns for an rtree table", /* 3 */ "Auxiliary rtree columns must be last" /* 4 */ }; assert( RTREE_MAX_AUX_COLUMN<256 ); /* Aux columns counted by a u8 */ if( argc>RTREE_MAX_AUX_COLUMN+3 ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[3]); return SQLITE_ERROR; } sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); /* Allocate the sqlite3_vtab structure */ nDb = (int)strlen(argv[1]); nName = (int)strlen(argv[2]); pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); if( !pRtree ){ return SQLITE_NOMEM; } memset(pRtree, 0, sizeof(Rtree)+nDb+nName+2); pRtree->nBusy = 1; pRtree->base.pModule = &rtreeModule; pRtree->zDb = (char *)&pRtree[1]; pRtree->zName = &pRtree->zDb[nDb+1]; pRtree->eCoordType = (u8)eCoordType; memcpy(pRtree->zDb, argv[1], nDb); memcpy(pRtree->zName, argv[2], nName); /* Create/Connect to the underlying relational database schema. If ** that is successful, call sqlite3_declare_vtab() to configure ** the r-tree table schema. */ pSql = sqlite3_str_new(db); sqlite3_str_appendf(pSql, "CREATE TABLE x(%s", argv[3]); for(ii=4; ii<argc; ii++){ if( argv[ii][0]=='+' ){ pRtree->nAux++; sqlite3_str_appendf(pSql, ",%s", argv[ii]+1); }else if( pRtree->nAux>0 ){ break; }else{ pRtree->nDim2++; sqlite3_str_appendf(pSql, ",%s", argv[ii]); } } sqlite3_str_appendf(pSql, ");"); zSql = sqlite3_str_finish(pSql); if( !zSql ){ rc = SQLITE_NOMEM; }else if( ii<argc ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[4]); rc = SQLITE_ERROR; }else if( SQLITE_OK!=(rc = sqlite3_declare_vtab(db, zSql)) ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } sqlite3_free(zSql); if( rc ) goto rtreeInit_fail; pRtree->nDim = pRtree->nDim2/2; if( pRtree->nDim<1 ){ iErr = 2; }else if( pRtree->nDim2>RTREE_MAX_DIMENSIONS*2 ){ iErr = 3; }else if( pRtree->nDim2 % 2 ){ iErr = 1; }else{ iErr = 0; } if( iErr ){ *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); goto rtreeInit_fail; } pRtree->nBytesPerCell = 8 + pRtree->nDim2*4; /* Figure out the node size to use. */ rc = getNodeSize(db, pRtree, isCreate, pzErr); if( rc ) goto rtreeInit_fail; rc = rtreeSqlInit(pRtree, db, argv[1], argv[2], isCreate); if( rc ){ *pzErr = sqlite3_mprintf("%s", sqlite3_errmsg(db)); goto rtreeInit_fail; } *ppVtab = (sqlite3_vtab *)pRtree; return SQLITE_OK; rtreeInit_fail: if( rc==SQLITE_OK ) rc = SQLITE_ERROR; assert( *ppVtab==0 ); assert( pRtree->nBusy==1 ); rtreeRelease(pRtree); return rc; } /* ** Implementation of a scalar function that decodes r-tree nodes to ** human readable strings. This can be used for debugging and analysis. |
︙ | ︙ | |||
3747 3748 3749 3750 3751 3752 3753 | /* ** This function is used to check that the %_parent (if bLeaf==0) or %_rowid ** (if bLeaf==1) table contains a specified entry. The schemas of the ** two tables are: ** ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) | | | | | 3874 3875 3876 3877 3878 3879 3880 3881 3882 3883 3884 3885 3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 | /* ** This function is used to check that the %_parent (if bLeaf==0) or %_rowid ** (if bLeaf==1) table contains a specified entry. The schemas of the ** two tables are: ** ** CREATE TABLE %_parent(nodeno INTEGER PRIMARY KEY, parentnode INTEGER) ** CREATE TABLE %_rowid(rowid INTEGER PRIMARY KEY, nodeno INTEGER, ...) ** ** In both cases, this function checks that there exists an entry with ** IPK value iKey and the second column set to iVal. ** */ static void rtreeCheckMapping( RtreeCheck *pCheck, /* RtreeCheck object */ int bLeaf, /* True for a leaf cell, false for interior */ i64 iKey, /* Key for mapping */ i64 iVal /* Expected value for mapping */ ){ int rc; sqlite3_stmt *pStmt; const char *azSql[2] = { "SELECT parentnode FROM %Q.'%q_parent' WHERE nodeno=?1", "SELECT nodeno FROM %Q.'%q_rowid' WHERE rowid=?1" }; assert( bLeaf==0 || bLeaf==1 ); if( pCheck->aCheckMapping[bLeaf]==0 ){ pCheck->aCheckMapping[bLeaf] = rtreeCheckPrepare(pCheck, azSql[bLeaf], pCheck->zDb, pCheck->zTab ); |
︙ | ︙ | |||
3947 3948 3949 3950 3951 3952 3953 3954 3955 3956 3957 3958 3959 3960 3961 3962 3963 3964 3965 3966 3967 3968 3969 3970 3971 3972 | const char *zDb, /* Name of db ("main", "temp" etc.) */ const char *zTab, /* Name of rtree table to check */ char **pzReport /* OUT: sqlite3_malloc'd report text */ ){ RtreeCheck check; /* Common context for various routines */ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ int bEnd = 0; /* True if transaction should be closed */ /* Initialize the context object */ memset(&check, 0, sizeof(check)); check.db = db; check.zDb = zDb; check.zTab = zTab; /* If there is not already an open transaction, open one now. This is ** to ensure that the queries run as part of this integrity-check operate ** on a consistent snapshot. */ if( sqlite3_get_autocommit(db) ){ check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); bEnd = 1; } /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ int rc; | > > > > > > > > > > > | | 4074 4075 4076 4077 4078 4079 4080 4081 4082 4083 4084 4085 4086 4087 4088 4089 4090 4091 4092 4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 | const char *zDb, /* Name of db ("main", "temp" etc.) */ const char *zTab, /* Name of rtree table to check */ char **pzReport /* OUT: sqlite3_malloc'd report text */ ){ RtreeCheck check; /* Common context for various routines */ sqlite3_stmt *pStmt = 0; /* Used to find column count of rtree table */ int bEnd = 0; /* True if transaction should be closed */ int nAux = 0; /* Number of extra columns. */ /* Initialize the context object */ memset(&check, 0, sizeof(check)); check.db = db; check.zDb = zDb; check.zTab = zTab; /* If there is not already an open transaction, open one now. This is ** to ensure that the queries run as part of this integrity-check operate ** on a consistent snapshot. */ if( sqlite3_get_autocommit(db) ){ check.rc = sqlite3_exec(db, "BEGIN", 0, 0, 0); bEnd = 1; } /* Find the number of auxiliary columns */ if( check.rc==SQLITE_OK ){ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.'%q_rowid'", zDb, zTab); if( pStmt ){ nAux = sqlite3_column_count(pStmt) - 2; sqlite3_finalize(pStmt); } check.rc = SQLITE_OK; } /* Find number of dimensions in the rtree table. */ pStmt = rtreeCheckPrepare(&check, "SELECT * FROM %Q.%Q", zDb, zTab); if( pStmt ){ int rc; check.nDim = (sqlite3_column_count(pStmt) - 1 - nAux) / 2; if( check.nDim<1 ){ rtreeCheckAppendMsg(&check, "Schema corrupt or not an rtree"); }else if( SQLITE_ROW==sqlite3_step(pStmt) ){ check.bInt = (sqlite3_column_type(pStmt, 1)==SQLITE_INTEGER); } rc = sqlite3_finalize(pStmt); if( rc!=SQLITE_CORRUPT ) check.rc = rc; |
︙ | ︙ |
Changes to ext/rtree/rtree1.test.
︙ | ︙ | |||
605 606 607 608 609 610 611 612 613 | INSERT INTO rt VALUES(1,2,3,4,5); } do_execsql_test 15.2 { DROP TABLE t13; COMMIT; } expand_all_sql db finish_test | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 | INSERT INTO rt VALUES(1,2,3,4,5); } do_execsql_test 15.2 { DROP TABLE t13; COMMIT; } # Test cases for the new auxiliary columns feature # do_catchsql_test 16.100 { CREATE VIRTUAL TABLE t16 USING rtree(id,x0,x1,y0,+aux1,x1); } {1 {Auxiliary rtree columns must be last}} do_test 16.110 { set sql { CREATE VIRTUAL TABLE t16 USING rtree( id, x00, x01, x10, x11, x20, x21, x30, x31, x40, x41 } for {set i 12} {$i<=100} {incr i} { append sql ", +a$i" } append sql ");" execsql $sql } {} do_test 16.120 { set sql { CREATE VIRTUAL TABLE t16b USING rtree( id, x00, x01, x10, x11, x20, x21, x30, x31, x40, x41 } for {set i 12} {$i<=101} {incr i} { append sql ", +a$i" } append sql ");" catchsql $sql } {1 {Too many columns for an rtree table}} do_execsql_test 16.130 { DROP TABLE IF EXISTS rt1; CREATE VIRTUAL TABLE rt1 USING rtree(id, x1, x2, +aux); INSERT INTO rt1 VALUES(1, 1, 2, 'aux1'); INSERT INTO rt1 VALUES(2, 2, 3, 'aux2'); INSERT INTO rt1 VALUES(3, 3, 4, 'aux3'); INSERT INTO rt1 VALUES(4, 4, 5, 'aux4'); SELECT * FROM rt1 WHERE id IN (1, 2, 3, 4); } {1 1.0 2.0 aux1 2 2.0 3.0 aux2 3 3.0 4.0 aux3 4 4.0 5.0 aux4} expand_all_sql db finish_test |
Changes to ext/rtree/rtree3.test.
︙ | ︙ | |||
77 78 79 80 81 82 83 | } -body { execsql { DROP TABLE rt } } do_malloc_test rtree3-3.prep { faultsim_delete_and_reopen execsql { | | | 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | } -body { execsql { DROP TABLE rt } } do_malloc_test rtree3-3.prep { faultsim_delete_and_reopen execsql { CREATE VIRTUAL TABLE rt USING rtree(ii, x1, x2, y1, y2, +a1, +a2); INSERT INTO rt VALUES(NULL, 3, 5, 7, 9); } faultsim_save_and_close } {} do_faultsim_test rtree3-3a -faults oom* -prep { faultsim_restore_and_reopen |
︙ | ︙ |
Changes to ext/rtree/rtreeC.test.
︙ | ︙ | |||
174 175 176 177 178 179 180 | #-------------------------------------------------------------------- # Test that the sqlite_stat1 data is used correctly. # reset_db do_execsql_test 5.1 { CREATE TABLE t1(x PRIMARY KEY, y); | | | | 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | #-------------------------------------------------------------------- # Test that the sqlite_stat1 data is used correctly. # reset_db do_execsql_test 5.1 { CREATE TABLE t1(x PRIMARY KEY, y); CREATE VIRTUAL TABLE rt USING rtree(id, x1, x2, +d1); INSERT INTO t1(x) VALUES(1); INSERT INTO t1(x) SELECT x+1 FROM t1; -- 2 INSERT INTO t1(x) SELECT x+2 FROM t1; -- 4 INSERT INTO t1(x) SELECT x+4 FROM t1; -- 8 INSERT INTO t1(x) SELECT x+8 FROM t1; -- 16 INSERT INTO t1(x) SELECT x+16 FROM t1; -- 32 INSERT INTO t1(x) SELECT x+32 FROM t1; -- 64 INSERT INTO t1(x) SELECT x+64 FROM t1; -- 128 INSERT INTO t1(x) SELECT x+128 FROM t1; -- 256 INSERT INTO t1(x) SELECT x+256 FROM t1; -- 512 INSERT INTO t1(x) SELECT x+512 FROM t1; --1024 INSERT INTO rt SELECT x, x, x+1, printf('x%04xy',x) FROM t1 WHERE x<=5; } do_rtree_integrity_test 5.1.1 rt # First test a query with no ANALYZE data at all. The outer loop is # real table "t1". # do_eqp_test 5.2 { |
︙ | ︙ |
Added ext/rtree/rtreeH.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | # 2018-05-16 # # The author disclaims copyright to this source code. In place of # a legal notice, here is a blessing: # # May you do good and not evil. # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # This file contains tests for the r-tree module, specifically the # auxiliary column mechanism. if {![info exists testdir]} { set testdir [file join [file dirname [info script]] .. .. test] } source [file join [file dirname [info script]] rtree_util.tcl] source $testdir/tester.tcl ifcapable !rtree { finish_test ; return } do_execsql_test rtreeH-100 { CREATE VIRTUAL TABLE t1 USING rtree(id,x0,x1,y0,y1,+label,+other); INSERT INTO t1(x0,x1,y0,y1,label) VALUES (0,10,0,10,'lower-left corner'), (0,10,90,100,'upper-left corner'), (90,100,0,10,'lower-right corner'), (90,100,90,100,'upper-right corner'), (40,60,40,60,'center'), (0,5,0,100,'left edge'), (95,100,0,100,'right edge'), (0,100,0,5,'bottom edge'), (0,100,95,100,'top edge'), (0,100,0,100,'the whole thing'), (0,50,0,100,'left half'), (51,100,0,100,'right half'), (0,100,0,50,'bottom half'), (0,100,51,100,'top half'); } {} do_execsql_test rtreeH-101 { SELECT * FROM t1_rowid ORDER BY rowid } {1 1 {lower-left corner} {} 2 1 {upper-left corner} {} 3 1 {lower-right corner} {} 4 1 {upper-right corner} {} 5 1 center {} 6 1 {left edge} {} 7 1 {right edge} {} 8 1 {bottom edge} {} 9 1 {top edge} {} 10 1 {the whole thing} {} 11 1 {left half} {} 12 1 {right half} {} 13 1 {bottom half} {} 14 1 {top half} {}} do_execsql_test rtreeH-102 { SELECT * FROM t1 WHERE rowid=5; } {5 40.0 60.0 40.0 60.0 center {}} do_execsql_test rtreeH-103 { SELECT * FROM t1 WHERE label='center'; } {5 40.0 60.0 40.0 60.0 center {}} do_rtree_integrity_test rtreeH-110 t1 do_execsql_test rtreeH-120 { SELECT label FROM t1 WHERE x1<=50 ORDER BY id } {{lower-left corner} {upper-left corner} {left edge} {left half}} do_execsql_test rtreeH-121 { SELECT label FROM t1 WHERE x1<=50 AND label NOT LIKE '%corner%' ORDER BY id } {{left edge} {left half}} do_execsql_test rtreeH-200 { WITH RECURSIVE c1(x) AS (VALUES(0) UNION ALL SELECT x+1 FROM c1 WHERE x<99), c2(y) AS (VALUES(0) UNION ALL SELECT y+1 FROM c2 WHERE y<99) INSERT INTO t1(id, x0,x1,y0,y1,label) SELECT 1000+x+y*100, x, x+1, y, y+1, printf('box-%d,%d',x,y) FROM c1, c2; } {} do_execsql_test rtreeH-210 { SELECT label FROM t1 WHERE x0>=48 AND x1<=50 AND y0>=48 AND y1<=50 ORDER BY id; } {box-48,48 box-49,48 box-48,49 box-49,49} do_execsql_test rtreeH-300 { UPDATE t1 SET label='x'||label WHERE x0>=49 AND x1<=50 AND y0>=49 AND y1<=50; SELECT label FROM t1 WHERE x0>=48 AND x1<=50 AND y0>=48 AND y1<=50 ORDER BY id; } {box-48,48 box-49,48 box-48,49 xbox-49,49} finish_test |
Changes to src/shell.c.in.
︙ | ︙ | |||
3543 3544 3545 3546 3547 3548 3549 | */ int deduceDatabaseType(const char *zName, int dfltZip){ FILE *f = fopen(zName, "rb"); size_t n; int rc = SHELL_OPEN_UNSPEC; char zBuf[100]; if( f==0 ){ | | > > | > > > > > > > > > > > > > > | | | > | 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570 3571 3572 3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592 3593 3594 3595 3596 3597 3598 3599 3600 3601 3602 3603 3604 3605 | */ int deduceDatabaseType(const char *zName, int dfltZip){ FILE *f = fopen(zName, "rb"); size_t n; int rc = SHELL_OPEN_UNSPEC; char zBuf[100]; if( f==0 ){ if( dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ return SHELL_OPEN_ZIPFILE; }else{ return SHELL_OPEN_NORMAL; } } fseek(f, -25, SEEK_END); n = fread(zBuf, 25, 1, f); if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){ rc = SHELL_OPEN_APPENDVFS; }else{ fseek(f, -22, SEEK_END); n = fread(zBuf, 22, 1, f); if( n==1 && zBuf[0]==0x50 && zBuf[1]==0x4b && zBuf[2]==0x05 && zBuf[3]==0x06 ){ rc = SHELL_OPEN_ZIPFILE; }else if( n==0 && dfltZip && sqlite3_strlike("%.zip",zName,0)==0 ){ rc = SHELL_OPEN_ZIPFILE; } } fclose(f); return rc; } /* Flags for open_db(). ** ** The default behavior of open_db() is to exit(1) if the database fails to ** open. The OPEN_DB_KEEPALIVE flag changes that so that it prints an error ** but still returns without calling exit. ** ** The OPEN_DB_ZIPFILE flag causes open_db() to prefer to open files as a ** ZIP archive if the file does not exist or is empty and its name matches ** the *.zip pattern. */ #define OPEN_DB_KEEPALIVE 0x001 /* Return after error if true */ #define OPEN_DB_ZIPFILE 0x002 /* Open as ZIP if name matches *.zip */ /* ** Make sure the database is open. If it is not, then open it. If ** the database fails to open, print an error message and exit. */ static void open_db(ShellState *p, int openFlags){ if( p->db==0 ){ if( p->openMode==SHELL_OPEN_UNSPEC ){ if( p->zDbFilename==0 || p->zDbFilename[0]==0 ){ p->openMode = SHELL_OPEN_NORMAL; }else{ p->openMode = (u8)deduceDatabaseType(p->zDbFilename, (openFlags & OPEN_DB_ZIPFILE)!=0); } } switch( p->openMode ){ case SHELL_OPEN_APPENDVFS: { sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs"); break; |
︙ | ︙ | |||
3601 3602 3603 3604 3605 3606 3607 | break; } } globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(p->db)); | | | 3618 3619 3620 3621 3622 3623 3624 3625 3626 3627 3628 3629 3630 3631 3632 | break; } } globalDb = p->db; if( p->db==0 || SQLITE_OK!=sqlite3_errcode(p->db) ){ utf8_printf(stderr,"Error: unable to open database \"%s\": %s\n", p->zDbFilename, sqlite3_errmsg(p->db)); if( openFlags & OPEN_DB_KEEPALIVE ) return; exit(1); } #ifndef SQLITE_OMIT_LOAD_EXTENSION sqlite3_enable_load_extension(p->db, 1); #endif sqlite3_fileio_init(p->db, 0, 0); sqlite3_shathree_init(p->db, 0, 0); |
︙ | ︙ | |||
3634 3635 3636 3637 3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 | char *zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } } } #if HAVE_READLINE || HAVE_EDITLINE /* ** Readline completion callbacks */ static char *readline_completion_generator(const char *text, int state){ static sqlite3_stmt *pStmt = 0; | > > > > > > > > > > > | 3651 3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670 3671 3672 3673 3674 3675 | char *zSql = sqlite3_mprintf( "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); } } } /* ** Attempt to close the databaes connection. Report errors. */ void close_db(sqlite3 *db){ int rc = sqlite3_close(db); if( rc ){ utf8_printf(stderr, "Error: sqlite3_close() returns %d: %s\n", rc, sqlite3_errmsg(db)); } } #if HAVE_READLINE || HAVE_EDITLINE /* ** Readline completion callbacks */ static char *readline_completion_generator(const char *text, int state){ static sqlite3_stmt *pStmt = 0; |
︙ | ︙ | |||
4215 4216 4217 4218 4219 4220 4221 | sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } | | | 4243 4244 4245 4246 4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 | sqlite3_exec(p->db, "PRAGMA writable_schema=ON;", 0, 0, 0); sqlite3_exec(newDb, "BEGIN EXCLUSIVE;", 0, 0, 0); tryToCloneSchema(p, newDb, "type='table'", tryToCloneData); tryToCloneSchema(p, newDb, "type!='table'", 0); sqlite3_exec(newDb, "COMMIT;", 0, 0, 0); sqlite3_exec(p->db, "PRAGMA writable_schema=OFF;", 0, 0, 0); } close_db(newDb); } /* ** Change the output file back to stdout. ** ** If the p->doXdgOpen flag is set, that means the output was being ** redirected to a temporary file named by p->zTempFile. In that case, |
︙ | ︙ | |||
4870 4871 4872 4873 4874 4875 4876 4877 4878 4879 4880 4881 4882 4883 | typedef struct ArCommand ArCommand; struct ArCommand { u8 eCmd; /* An AR_CMD_* value */ u8 bVerbose; /* True if --verbose */ u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ int nArg; /* Number of command arguments */ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ const char *zFile; /* --file argument, or NULL */ const char *zDir; /* --directory argument, or NULL */ char **azArg; /* Array of command arguments */ ShellState *p; /* Shell state */ sqlite3 *db; /* Database containing the archive */ | > | 4898 4899 4900 4901 4902 4903 4904 4905 4906 4907 4908 4909 4910 4911 4912 | typedef struct ArCommand ArCommand; struct ArCommand { u8 eCmd; /* An AR_CMD_* value */ u8 bVerbose; /* True if --verbose */ u8 bZip; /* True if the archive is a ZIP */ u8 bDryRun; /* True if --dry-run */ u8 bAppend; /* True if --append */ u8 fromCmdLine; /* Run from -A instead of .archive */ int nArg; /* Number of command arguments */ char *zSrcTable; /* "sqlar", "zipfile($file)" or "zip" */ const char *zFile; /* --file argument, or NULL */ const char *zDir; /* --directory argument, or NULL */ char **azArg; /* Array of command arguments */ ShellState *p; /* Shell state */ sqlite3 *db; /* Database containing the archive */ |
︙ | ︙ | |||
4916 4917 4918 4919 4920 4921 4922 | return SQLITE_ERROR; } /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ | | | > > > > > | 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 4970 | return SQLITE_ERROR; } /* ** Print an error message for the .ar command to stderr and return ** SQLITE_ERROR. */ static int arErrorMsg(ArCommand *pAr, const char *zFmt, ...){ va_list ap; char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); va_end(ap); utf8_printf(stderr, "Error: %s\n", z); if( pAr->fromCmdLine ){ utf8_printf(stderr, "Use \"-A\" for more help\n"); }else{ utf8_printf(stderr, "Use \".archive --help\" for more help\n"); } sqlite3_free(z); return SQLITE_ERROR; } /* ** Values for ArCommand.eCmd. */ |
︙ | ︙ | |||
4953 4954 4955 4956 4957 4958 4959 | switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_UPDATE: case AR_CMD_HELP: if( pAr->eCmd ){ | | | 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 | switch( eSwitch ){ case AR_CMD_CREATE: case AR_CMD_EXTRACT: case AR_CMD_LIST: case AR_CMD_UPDATE: case AR_CMD_HELP: if( pAr->eCmd ){ return arErrorMsg(pAr, "multiple command options"); } pAr->eCmd = eSwitch; break; case AR_SWITCH_DRYRUN: pAr->bDryRun = 1; break; |
︙ | ︙ | |||
5013 5014 5015 5016 5017 5018 5019 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ return arUsage(stderr); }else{ char *z = azArg[1]; | < < | | | 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 5065 5066 5067 5068 5069 5070 5071 5072 5073 5074 5075 5076 | int nSwitch = sizeof(aSwitch) / sizeof(struct ArSwitch); struct ArSwitch *pEnd = &aSwitch[nSwitch]; if( nArg<=1 ){ return arUsage(stderr); }else{ char *z = azArg[1]; if( z[0]!='-' ){ /* Traditional style [tar] invocation */ int i; int iArg = 2; for(i=0; z[i]; i++){ const char *zArg = 0; struct ArSwitch *pOpt; for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){ if( z[i]==pOpt->cShort ) break; } if( pOpt==pEnd ){ return arErrorMsg(pAr, "unrecognized option: %c", z[i]); } if( pOpt->bArg ){ if( iArg>=nArg ){ return arErrorMsg(pAr, "option requires an argument: %c",z[i]); } zArg = azArg[iArg++]; } if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; } pAr->nArg = nArg-iArg; if( pAr->nArg>0 ){ |
︙ | ︙ | |||
5064 5065 5066 5067 5068 5069 5070 | for(i=1; i<n; i++){ const char *zArg = 0; struct ArSwitch *pOpt; for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){ if( z[i]==pOpt->cShort ) break; } if( pOpt==pEnd ){ | | | | 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 5106 5107 5108 5109 5110 5111 5112 5113 5114 5115 5116 5117 5118 | for(i=1; i<n; i++){ const char *zArg = 0; struct ArSwitch *pOpt; for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){ if( z[i]==pOpt->cShort ) break; } if( pOpt==pEnd ){ return arErrorMsg(pAr, "unrecognized option: %c", z[i]); } if( pOpt->bArg ){ if( i<(n-1) ){ zArg = &z[i+1]; i = n; }else{ if( iArg>=(nArg-1) ){ return arErrorMsg(pAr, "option requires an argument: %c",z[i]); } zArg = azArg[++iArg]; } } if( arProcessSwitch(pAr, pOpt->eSwitch, zArg) ) return SQLITE_ERROR; } }else if( z[2]=='\0' ){ |
︙ | ︙ | |||
5094 5095 5096 5097 5098 5099 5100 | const char *zArg = 0; /* Argument for option, if any */ struct ArSwitch *pMatch = 0; /* Matching option */ struct ArSwitch *pOpt; /* Iterator */ for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){ const char *zLong = pOpt->zLong; if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){ if( pMatch ){ | | | | | 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140 5141 5142 5143 5144 5145 5146 5147 5148 5149 5150 5151 5152 | const char *zArg = 0; /* Argument for option, if any */ struct ArSwitch *pMatch = 0; /* Matching option */ struct ArSwitch *pOpt; /* Iterator */ for(pOpt=&aSwitch[0]; pOpt<pEnd; pOpt++){ const char *zLong = pOpt->zLong; if( (n-2)<=strlen30(zLong) && 0==memcmp(&z[2], zLong, n-2) ){ if( pMatch ){ return arErrorMsg(pAr, "ambiguous option: %s",z); }else{ pMatch = pOpt; } } } if( pMatch==0 ){ return arErrorMsg(pAr, "unrecognized option: %s", z); } if( pMatch->bArg ){ if( iArg>=(nArg-1) ){ return arErrorMsg(pAr, "option requires an argument: %s", z); } zArg = azArg[++iArg]; } if( arProcessSwitch(pAr, pMatch->eSwitch, zArg) ) return SQLITE_ERROR; } } } |
︙ | ︙ | |||
5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 | ); }else{ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellFinalize(&rc, pSql); return rc; } /* ** Implementation of .ar "eXtract" command. */ | > | 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 5278 5279 5280 5281 | ); }else{ utf8_printf(pAr->p->out, "%s\n", sqlite3_column_text(pSql, 0)); } } } shellFinalize(&rc, pSql); sqlite3_free(zWhere); return rc; } /* ** Implementation of .ar "eXtract" command. */ |
︙ | ︙ | |||
5437 5438 5439 5440 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 | } /* ** Implementation of ".ar" dot command. */ static int arDotCommand( ShellState *pState, /* Current shell tool state */ char **azArg, /* Array of arguments passed to dot command */ int nArg /* Number of entries in azArg[] */ ){ ArCommand cmd; int rc; memset(&cmd, 0, sizeof(cmd)); rc = arParseCommand(azArg, nArg, &cmd); if( rc==SQLITE_OK ){ int eDbType = SHELL_OPEN_UNSPEC; cmd.p = pState; cmd.db = pState->db; if( cmd.zFile ){ eDbType = deduceDatabaseType(cmd.zFile, 1); | > > | 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 | } /* ** Implementation of ".ar" dot command. */ static int arDotCommand( ShellState *pState, /* Current shell tool state */ int fromCmdLine, /* True if -A command-line option, not .ar cmd */ char **azArg, /* Array of arguments passed to dot command */ int nArg /* Number of entries in azArg[] */ ){ ArCommand cmd; int rc; memset(&cmd, 0, sizeof(cmd)); cmd.fromCmdLine = fromCmdLine; rc = arParseCommand(azArg, nArg, &cmd); if( rc==SQLITE_OK ){ int eDbType = SHELL_OPEN_UNSPEC; cmd.p = pState; cmd.db = pState->db; if( cmd.zFile ){ eDbType = deduceDatabaseType(cmd.zFile, 1); |
︙ | ︙ | |||
5489 5490 5491 5492 5493 5494 5495 | } sqlite3_fileio_init(cmd.db, 0, 0); sqlite3_sqlar_init(cmd.db, 0, 0); sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, shellPutsFunc, 0, 0); } | | | 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 | } sqlite3_fileio_init(cmd.db, 0, 0); sqlite3_sqlar_init(cmd.db, 0, 0); sqlite3_create_function(cmd.db, "shell_putsnl", 1, SQLITE_UTF8, cmd.p, shellPutsFunc, 0, 0); } if( cmd.zSrcTable==0 && cmd.bZip==0 && cmd.eCmd!=AR_CMD_HELP ){ if( cmd.eCmd!=AR_CMD_CREATE && sqlite3_table_column_metadata(cmd.db,0,"sqlar","name",0,0,0,0,0) ){ utf8_printf(stderr, "database does not contain an 'sqlar' table\n"); rc = SQLITE_ERROR; goto end_ar_command; } |
︙ | ︙ | |||
5525 5526 5527 5528 5529 5530 5531 | assert( cmd.eCmd==AR_CMD_UPDATE ); rc = arCreateOrUpdateCommand(&cmd, 1); break; } } end_ar_command: if( cmd.db!=pState->db ){ | | | 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 5572 5573 5574 | assert( cmd.eCmd==AR_CMD_UPDATE ); rc = arCreateOrUpdateCommand(&cmd, 1); break; } } end_ar_command: if( cmd.db!=pState->db ){ close_db(cmd.db); } sqlite3_free(cmd.zSrcTable); return rc; } /* End of the ".archive" or ".ar" command logic **********************************************************************************/ |
︙ | ︙ | |||
5605 5606 5607 5608 5609 5610 5611 | } }else #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); | | | 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 | } }else #endif #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) if( c=='a' && strncmp(azArg[0], "archive", n)==0 ){ open_db(p, 0); rc = arDotCommand(p, 0, azArg, nArg); }else #endif if( (c=='b' && n>=3 && strncmp(azArg[0], "backup", n)==0) || (c=='s' && n>=3 && strncmp(azArg[0], "save", n)==0) ){ const char *zDestFile = 0; |
︙ | ︙ | |||
5648 5649 5650 5651 5652 5653 5654 | return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); | | | | | 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 | return 1; } if( zDb==0 ) zDb = "main"; rc = sqlite3_open_v2(zDestFile, &pDest, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, zVfs); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zDestFile); close_db(pDest); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(pDest, "main", p->db, zDb); if( pBackup==0 ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); close_db(pDest); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK ){} sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(pDest)); rc = 1; } close_db(pDest); }else if( c=='b' && n>=3 && strncmp(azArg[0], "bail", n)==0 ){ if( nArg==2 ){ bail_on_error = booleanValue(azArg[1]); }else{ raw_printf(stderr, "Usage: .bail on|off\n"); |
︙ | ︙ | |||
6482 6483 6484 6485 6486 6487 6488 | if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ char *zNewFilename; /* Name of the database file to open */ int iName = 1; /* Index in azArg[] of the filename */ int newFlag = 0; /* True to delete file before opening */ /* Close the existing database */ session_close_all(p); | | | 6517 6518 6519 6520 6521 6522 6523 6524 6525 6526 6527 6528 6529 6530 6531 | if( c=='o' && strncmp(azArg[0], "open", n)==0 && n>=2 ){ char *zNewFilename; /* Name of the database file to open */ int iName = 1; /* Index in azArg[] of the filename */ int newFlag = 0; /* True to delete file before opening */ /* Close the existing database */ session_close_all(p); close_db(p->db); p->db = 0; p->zDbFilename = 0; sqlite3_free(p->zFreeOnClose); p->zFreeOnClose = 0; p->openMode = SHELL_OPEN_UNSPEC; /* Check for command-line arguments */ for(iName=1; iName<nArg && azArg[iName][0]=='-'; iName++){ |
︙ | ︙ | |||
6512 6513 6514 6515 6516 6517 6518 | } } /* If a filename is specified, try to open it first */ zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0; if( zNewFilename ){ if( newFlag ) shellDeleteFile(zNewFilename); p->zDbFilename = zNewFilename; | | | 6547 6548 6549 6550 6551 6552 6553 6554 6555 6556 6557 6558 6559 6560 6561 | } } /* If a filename is specified, try to open it first */ zNewFilename = nArg>iName ? sqlite3_mprintf("%s", azArg[iName]) : 0; if( zNewFilename ){ if( newFlag ) shellDeleteFile(zNewFilename); p->zDbFilename = zNewFilename; open_db(p, OPEN_DB_KEEPALIVE); if( p->db==0 ){ utf8_printf(stderr, "Error: cannot open '%s'\n", zNewFilename); sqlite3_free(zNewFilename); }else{ p->zFreeOnClose = zNewFilename; } } |
︙ | ︙ | |||
6662 6663 6664 6665 6666 6667 6668 | raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); | | | | | 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 6710 6711 6712 6713 6714 6715 6716 6717 6718 6719 6720 6721 6722 6723 6724 6725 6726 6727 6728 6729 6730 6731 6732 6733 6734 6735 6736 6737 6738 | raw_printf(stderr, "Usage: .restore ?DB? FILE\n"); rc = 1; goto meta_command_exit; } rc = sqlite3_open(zSrcFile, &pSrc); if( rc!=SQLITE_OK ){ utf8_printf(stderr, "Error: cannot open \"%s\"\n", zSrcFile); close_db(pSrc); return 1; } open_db(p, 0); pBackup = sqlite3_backup_init(p->db, zDb, pSrc, "main"); if( pBackup==0 ){ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); close_db(pSrc); return 1; } while( (rc = sqlite3_backup_step(pBackup,100))==SQLITE_OK || rc==SQLITE_BUSY ){ if( rc==SQLITE_BUSY ){ if( nTimeout++ >= 3 ) break; sqlite3_sleep(100); } } sqlite3_backup_finish(pBackup); if( rc==SQLITE_DONE ){ rc = 0; }else if( rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){ raw_printf(stderr, "Error: source database is busy\n"); rc = 1; }else{ utf8_printf(stderr, "Error: %s\n", sqlite3_errmsg(p->db)); rc = 1; } close_db(pSrc); }else if( c=='s' && strncmp(azArg[0], "scanstats", n)==0 ){ if( nArg==2 ){ p->scanstatsOn = (u8)booleanValue(azArg[1]); #ifndef SQLITE_ENABLE_STMT_SCANSTATUS raw_printf(stderr, "Warning: .scanstats not available in this build.\n"); |
︙ | ︙ | |||
7373 7374 7375 7376 7377 7378 7379 | char **azResult; int nRow, nAlloc; int ii; ShellText s; initText(&s); open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); | > > | > > | 7408 7409 7410 7411 7412 7413 7414 7415 7416 7417 7418 7419 7420 7421 7422 7423 7424 7425 7426 7427 7428 7429 7430 7431 7432 7433 | char **azResult; int nRow, nAlloc; int ii; ShellText s; initText(&s); open_db(p, 0); rc = sqlite3_prepare_v2(p->db, "PRAGMA database_list", -1, &pStmt, 0); if( rc ){ sqlite3_finalize(pStmt); return shellDatabaseError(p->db); } if( nArg>2 && c=='i' ){ /* It is an historical accident that the .indexes command shows an error ** when called with the wrong number of arguments whereas the .tables ** command does not. */ raw_printf(stderr, "Usage: .indexes ?LIKE-PATTERN?\n"); rc = 1; sqlite3_finalize(pStmt); goto meta_command_exit; } for(ii=0; sqlite3_step(pStmt)==SQLITE_ROW; ii++){ const char *zDbName = (const char*)sqlite3_column_text(pStmt, 1); if( zDbName==0 ) continue; if( s.z && s.z[0] ) appendText(&s, " UNION ALL ", 0); if( sqlite3_stricmp(zDbName, "main")==0 ){ |
︙ | ︙ | |||
8281 8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 | int i; int rc = 0; int warnInmemoryDb = 0; int readStdin = 1; int nCmd = 0; char **azCmd = 0; const char *zVfs = 0; /* Value of -vfs command-line option */ setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #if USE_SYSTEM_SQLITE+0!=1 | > > > > | 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 | int i; int rc = 0; int warnInmemoryDb = 0; int readStdin = 1; int nCmd = 0; char **azCmd = 0; const char *zVfs = 0; /* Value of -vfs command-line option */ #if !SQLITE_SHELL_IS_UTF8 char **argvToFree = 0; int argcToFree = 0; #endif setBinaryMode(stdin, 0); setvbuf(stderr, 0, _IONBF, 0); /* Make sure stderr is unbuffered */ stdin_is_interactive = isatty(0); stdout_is_console = isatty(1); #if USE_SYSTEM_SQLITE+0!=1 |
︙ | ︙ | |||
8304 8305 8306 8307 8308 8309 8310 | ** The SQLite memory allocator subsystem has to be enabled in order to ** do this. But we want to run an sqlite3_shutdown() afterwards so that ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); | | > > > | 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 | ** The SQLite memory allocator subsystem has to be enabled in order to ** do this. But we want to run an sqlite3_shutdown() afterwards so that ** subsequent sqlite3_config() calls will work. So copy all results into ** memory that does not come from the SQLite memory allocator. */ #if !SQLITE_SHELL_IS_UTF8 sqlite3_initialize(); argvToFree = malloc(sizeof(argv[0])*argc*2); argcToFree = argc; argv = argvToFree + argc; if( argv==0 ) shell_out_of_memory(); for(i=0; i<argc; i++){ char *z = sqlite3_win32_unicode_to_utf8(wargv[i]); int n; if( z==0 ) shell_out_of_memory(); n = (int)strlen(z); argv[i] = malloc( n+1 ); if( argv[i]==0 ) shell_out_of_memory(); memcpy(argv[i], z, n+1); argvToFree[i] = argv[i]; sqlite3_free(z); } sqlite3_shutdown(); #endif assert( argc>=1 && argv && argv[0] ); Argv0 = argv[0]; |
︙ | ︙ | |||
8635 8636 8637 8638 8639 8640 8641 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( strncmp(z, "-A", 2)==0 ){ if( nCmd>0 ){ utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" " with \"%s\"\n", z); return 1; } | | | | | 8681 8682 8683 8684 8685 8686 8687 8688 8689 8690 8691 8692 8693 8694 8695 8696 8697 8698 8699 8700 | #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( strncmp(z, "-A", 2)==0 ){ if( nCmd>0 ){ utf8_printf(stderr, "Error: cannot mix regular SQL or dot-commands" " with \"%s\"\n", z); return 1; } open_db(&data, OPEN_DB_ZIPFILE); if( z[2] ){ argv[i] = &z[2]; arDotCommand(&data, 1, argv+(i-1), argc-(i-1)); }else{ arDotCommand(&data, 1, argv+i, argc-i); } readStdin = 0; break; #endif }else{ utf8_printf(stderr,"%s: Error: unknown option: %s\n", Argv0, z); raw_printf(stderr,"Use -help for a list of options.\n"); |
︙ | ︙ | |||
8719 8720 8721 8722 8723 8724 8725 | }else{ rc = process_input(&data, stdin); } } set_table_name(&data, 0); if( data.db ){ session_close_all(&data); | | | | > > > | 8765 8766 8767 8768 8769 8770 8771 8772 8773 8774 8775 8776 8777 8778 8779 8780 8781 8782 8783 8784 8785 8786 8787 | }else{ rc = process_input(&data, stdin); } } set_table_name(&data, 0); if( data.db ){ session_close_all(&data); close_db(data.db); } sqlite3_free(data.zFreeOnClose); find_home_dir(1); output_reset(&data); data.doXdgOpen = 0; clearTempFile(&data); #if !SQLITE_SHELL_IS_UTF8 for(i=0; i<argcToFree; i++) free(argvToFree[i]); free(argvToFree); #endif /* Clear the global data structure so that valgrind will detect memory ** leaks */ memset(&data, 0, sizeof(data)); return rc; } |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
3913 3914 3915 3916 3917 3918 3919 | if( x<r ) return -1; if( x>r ) return +1; return 0; }else{ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; | | | < < < | 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 | if( x<r ) return -1; if( x>r ) return +1; return 0; }else{ i64 y; double s; if( r<-9223372036854775808.0 ) return +1; if( r>=9223372036854775808.0 ) return -1; y = (i64)r; if( i<y ) return -1; if( i>y ) return +1; s = (double)i; if( s<r ) return -1; if( s>r ) return +1; return 0; } } |
︙ | ︙ |