Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Ensure the mutex used to protect the linked list of all main database files opened by a single ota vfs is allocated. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | ota-update |
Files: | files | file ages | folders |
SHA1: |
9c8682d6650a94e11f9bec5baff69ed9 |
User & Date: | dan 2015-02-19 19:59:35.500 |
Context
2015-02-20
| ||
14:36 | Add some missing comments and fix other minor code issues in sqlite3ota.c. (check-in: 718fd8b673 user: dan tags: ota-update) | |
2015-02-19
| ||
19:59 | Ensure the mutex used to protect the linked list of all main database files opened by a single ota vfs is allocated. (check-in: 9c8682d665 user: dan tags: ota-update) | |
18:06 | Update various documentation comments in sqlite3ota.c and sqlite3ota.h. (check-in: 60e0a46b82 user: dan tags: ota-update) | |
Changes
Changes to ext/ota/ota1.test.
︙ | ︙ | |||
96 97 98 99 100 101 102 | return $filename } # Run the OTA in file $ota on target database $target until completion. # proc run_ota {target ota} { sqlite3ota ota $target $ota | > | > > | 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | return $filename } # Run the OTA in file $ota on target database $target until completion. # proc run_ota {target ota} { sqlite3ota ota $target $ota while 1 { set rc [ota step] if {$rc!="SQLITE_OK"} break } ota close } proc step_ota {target ota} { while 1 { sqlite3ota ota $target $ota set rc [ota step] |
︙ | ︙ |
Changes to ext/ota/sqlite3ota.c.
︙ | ︙ | |||
99 100 101 102 103 104 105 | /* ** The ota_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: ** ** OTA_STATE_STAGE: | | < | > | > > | > | 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /* ** The ota_state table is used to save the state of a partially applied ** update so that it can be resumed later. The table consists of integer ** keys mapped to values as follows: ** ** OTA_STATE_STAGE: ** May be set to integer values 1, 2, 4 or 5. As follows: ** 1: the *-ota file is currently under construction. ** 2: the *-ota file has been constructed, but not yet moved ** to the *-wal path. ** 4: the checkpoint is underway. ** 5: the ota update has been checkpointed. ** ** OTA_STATE_TBL: ** Only valid if STAGE==1. The target database name of the table ** currently being written. ** ** OTA_STATE_IDX: ** Only valid if STAGE==1. The target database name of the index ** currently being written, or NULL if the main table is currently being ** updated. ** ** OTA_STATE_ROW: ** Only valid if STAGE==1. Number of rows already processed for the current ** table/index. ** ** OTA_STATE_PROGRESS: ** Total number of sqlite3ota_step() calls made so far as part of this ** ota update. ** ** OTA_STATE_CKPT: ** Valid if STAGE==4. The 64-bit checksum associated with the wal-index ** header created by recovering the *-wal file. This is used to detect ** cases when another client appends frames to the *-wal file in the ** middle of an incremental checkpoint (an incremental checkpoint cannot ** be continued if this happens). ** ** OTA_STATE_COOKIE: ** Valid if STAGE==1. The current change-counter cookie value in the ** target db file. */ #define OTA_STATE_STAGE 1 #define OTA_STATE_TBL 2 |
︙ | ︙ | |||
149 150 151 152 153 154 155 | #define OTA_STAGE_CKPT 4 #define OTA_STAGE_DONE 5 #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state" \ "(k INTEGER PRIMARY KEY, v)" | | > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 | #define OTA_STAGE_CKPT 4 #define OTA_STAGE_DONE 5 #define OTA_CREATE_STATE "CREATE TABLE IF NOT EXISTS ota.ota_state" \ "(k INTEGER PRIMARY KEY, v)" typedef struct OtaFrame OtaFrame; typedef struct OtaObjIter OtaObjIter; typedef struct OtaState OtaState; typedef struct ota_vfs ota_vfs; typedef struct ota_file ota_file; #if !defined(SQLITE_AMALGAMATION) typedef unsigned int u32; typedef unsigned char u8; typedef sqlite3_int64 i64; |
︙ | ︙ | |||
209 210 211 212 213 214 215 | /* Output variables. zTbl==0 implies EOF. */ int bCleanup; /* True in "cleanup" state */ const char *zTbl; /* Name of target db table */ const char *zIdx; /* Name of target db index (or null) */ int iTnum; /* Root page of current object */ int iPkTnum; /* If eType==EXTERNAL, root of PK index */ int bUnique; /* Current index is unique */ | < | 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | /* Output variables. zTbl==0 implies EOF. */ int bCleanup; /* True in "cleanup" state */ const char *zTbl; /* Name of target db table */ const char *zIdx; /* Name of target db index (or null) */ int iTnum; /* Root page of current object */ int iPkTnum; /* If eType==EXTERNAL, root of PK index */ int bUnique; /* Current index is unique */ /* Statements created by otaObjIterPrepareAll() */ int nCol; /* Number of columns in current object */ sqlite3_stmt *pSelect; /* Source data */ sqlite3_stmt *pInsert; /* Statement for INSERT operations */ sqlite3_stmt *pDelete; /* Statement for DELETE ops */ |
︙ | ︙ | |||
240 241 242 243 244 245 246 | #define OTA_PK_NONE 1 #define OTA_PK_IPK 2 #define OTA_PK_EXTERNAL 3 #define OTA_PK_WITHOUT_ROWID 4 #define OTA_PK_VTAB 5 | > > > > > > > > > | > > > > > | 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | #define OTA_PK_NONE 1 #define OTA_PK_IPK 2 #define OTA_PK_EXTERNAL 3 #define OTA_PK_WITHOUT_ROWID 4 #define OTA_PK_VTAB 5 /* ** Within the OTA_STAGE_OAL stage, each call to sqlite3ota_step() performs ** one of the following operations. */ #define OTA_INSERT 1 /* Insert on a main table b-tree */ #define OTA_DELETE 2 /* Delete a row from a main table b-tree */ #define OTA_IDX_DELETE 3 /* Delete a row from an aux. index b-tree */ #define OTA_IDX_INSERT 4 /* Insert on an aux. index b-tree */ #define OTA_UPDATE 5 /* Update a row in a main table b-tree */ /* ** A single step of an incremental checkpoint - frame iWalFrame of the wal ** file should be copied to page iDbPage of the database file. */ struct OtaFrame { u32 iDbPage; u32 iWalFrame; }; /* ** OTA handle. |
︙ | ︙ | |||
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 | int nFrameAlloc; /* Allocated size of aFrame[] array */ OtaFrame *aFrame; int pgsz; u8 *aBuf; i64 iWalCksum; }; struct ota_vfs { sqlite3_vfs base; /* ota VFS shim methods */ sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ ota_file *pMain; /* Linked list of main db files */ }; struct ota_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ ota_vfs *pOtaVfs; /* Pointer to the ota_vfs object */ sqlite3ota *pOta; /* Pointer to ota object (ota target only) */ int openFlags; /* Flags this file was opened with */ | > > > > > > > | 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | int nFrameAlloc; /* Allocated size of aFrame[] array */ OtaFrame *aFrame; int pgsz; u8 *aBuf; i64 iWalCksum; }; /* ** An ota VFS is implemented using an instance of this structure. */ struct ota_vfs { sqlite3_vfs base; /* ota VFS shim methods */ sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ ota_file *pMain; /* Linked list of main db files */ }; /* ** Each file opened by an ota VFS is represented by an instance of ** the following structure. */ struct ota_file { sqlite3_file base; /* sqlite3_file methods */ sqlite3_file *pReal; /* Underlying file handle */ ota_vfs *pOtaVfs; /* Pointer to the ota_vfs object */ sqlite3ota *pOta; /* Pointer to ota object (ota target only) */ int openFlags; /* Flags this file was opened with */ |
︙ | ︙ | |||
455 456 457 458 459 460 461 | if( rc==SQLITE_OK ){ if( pIter->bCleanup ){ otaObjIterFreeCols(pIter); pIter->bCleanup = 0; rc = sqlite3_step(pIter->pTblIter); if( rc!=SQLITE_ROW ){ | | | < | 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 | if( rc==SQLITE_OK ){ if( pIter->bCleanup ){ otaObjIterFreeCols(pIter); pIter->bCleanup = 0; rc = sqlite3_step(pIter->pTblIter); if( rc!=SQLITE_ROW ){ rc = resetAndCollectError(pIter->pTblIter, &p->zErrmsg); pIter->zTbl = 0; }else{ pIter->zTbl = (const char*)sqlite3_column_text(pIter->pTblIter, 0); pIter->iTnum = sqlite3_column_int(pIter->pTblIter, 1); rc = pIter->zTbl ? SQLITE_OK : SQLITE_NOMEM; } }else{ if( pIter->zIdx==0 ){ sqlite3_stmt *pIdx = pIter->pIdxIter; rc = sqlite3_bind_text(pIdx, 1, pIter->zTbl, -1, SQLITE_STATIC); } if( rc==SQLITE_OK ){ rc = sqlite3_step(pIter->pIdxIter); if( rc!=SQLITE_ROW ){ rc = resetAndCollectError(pIter->pIdxIter, &p->zErrmsg); pIter->bCleanup = 1; pIter->zIdx = 0; }else{ pIter->zIdx = (const char*)sqlite3_column_text(pIter->pIdxIter, 0); pIter->iTnum = sqlite3_column_int(pIter->pIdxIter, 1); pIter->bUnique = sqlite3_column_int(pIter->pIdxIter, 2); rc = pIter->zIdx ? SQLITE_OK : SQLITE_NOMEM; } } } } } if( rc!=SQLITE_OK ){ otaObjIterFinalize(pIter); p->rc = rc; } return rc; } /* ** Initialize the iterator structure passed as the second argument. ** ** If no error occurs, SQLITE_OK is returned and the iterator is left |
︙ | ︙ | |||
523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 | ); } pIter->bCleanup = 1; p->rc = rc; return otaObjIterNext(p, pIter); } /* ** Argument zFmt is a sqlite3_mprintf() style format string. The trailing ** arguments are the usual subsitution values. This function performs ** the printf() style substitutions and executes the result as an SQL ** statement on the OTA handles database. ** ** If an error occurs, an error code and error message is stored in the ** OTA handle. If an error has already occurred when this function is ** called, it is a no-op. */ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); | > > > > > > > > > > > > > > > > > > > > > > > > < | > < > > > > > > > > > > > | 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 | ); } pIter->bCleanup = 1; p->rc = rc; return otaObjIterNext(p, pIter); } /* ** This is a wrapper around "sqlite3_mprintf(zFmt, ...)". If an OOM occurs, ** an error code is stored in the OTA handle passed as the first argument. ** ** If an error has already occurred (p->rc is already set to something other ** than SQLITE_OK), then this function returns NULL without modifying the ** stored error code. In this case it still calls sqlite3_free() on any ** printf() parameters associated with %z conversions. */ static char *otaMPrintf(sqlite3ota *p, const char *zFmt, ...){ char *zSql = 0; va_list ap; va_start(ap, zFmt); zSql = sqlite3_vmprintf(zFmt, ap); if( p->rc==SQLITE_OK ){ if( zSql==0 ) p->rc = SQLITE_NOMEM; }else{ sqlite3_free(zSql); zSql = 0; } va_end(ap); return zSql; } /* ** Argument zFmt is a sqlite3_mprintf() style format string. The trailing ** arguments are the usual subsitution values. This function performs ** the printf() style substitutions and executes the result as an SQL ** statement on the OTA handles database. ** ** If an error occurs, an error code and error message is stored in the ** OTA handle. If an error has already occurred when this function is ** called, it is a no-op. */ static int otaMPrintfExec(sqlite3ota *p, const char *zFmt, ...){ va_list ap; va_start(ap, zFmt); char *zSql = sqlite3_vmprintf(zFmt, ap); if( p->rc==SQLITE_OK ){ if( zSql==0 ){ p->rc = SQLITE_NOMEM; }else{ p->rc = sqlite3_exec(p->db, zSql, 0, 0, &p->zErrmsg); } } sqlite3_free(zSql); va_end(ap); return p->rc; } /* ** Attempt to allocate and return a pointer to a zeroed block of nByte ** bytes. ** ** If an error (i.e. an OOM condition) occurs, return NULL and leave an ** error code in the ota handle passed as the first argument. Or, if an ** error has already occurred when this function is called, return NULL ** immediately without attempting the allocation or modifying the stored ** error code. */ static void *otaMalloc(sqlite3ota *p, int nByte){ void *pRet = 0; if( p->rc==SQLITE_OK ){ pRet = sqlite3_malloc(nByte); if( pRet==0 ){ p->rc = SQLITE_NOMEM; }else{ |
︙ | ︙ | |||
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 | pIter->azTblType = &azNew[nCol]; pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol]; pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol]; pIter->abNotNull = (u8*)&pIter->abTblPk[nCol]; } } static char *otaStrndup(const char *zStr, int *pRc){ char *zRet = 0; assert( *pRc==SQLITE_OK ); if( zStr ){ int nCopy = strlen(zStr) + 1; zRet = (char*)sqlite3_malloc(nCopy); if( zRet ){ memcpy(zRet, zStr, nCopy); }else{ *pRc = SQLITE_NOMEM; } } return zRet; } /* Determine the type of a table. ** ** peType is of type (int*), a pointer to an output parameter of type ** (int). This call sets the output parameter as follows, depending ** on the type of the table specified by parameters dbName and zTbl. ** | > > > > > > > > > > > > > > > > > > > > > > > > > > | 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 | pIter->azTblType = &azNew[nCol]; pIter->aiSrcOrder = (int*)&pIter->azTblType[nCol]; pIter->abTblPk = (u8*)&pIter->aiSrcOrder[nCol]; pIter->abNotNull = (u8*)&pIter->abTblPk[nCol]; } } /* ** The first argument must be a nul-terminated string. This function ** returns a copy of the string in memory obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free this memory ** using sqlite3_free(). ** ** If an OOM condition is encountered when attempting to allocate memory, ** output variable (*pRc) is set to SQLITE_NOMEM before returning. Otherwise, ** if the allocation succeeds, (*pRc) is left unchanged. */ static char *otaStrndup(const char *zStr, int *pRc){ char *zRet = 0; assert( *pRc==SQLITE_OK ); if( zStr ){ int nCopy = strlen(zStr) + 1; zRet = (char*)sqlite3_malloc(nCopy); if( zRet ){ memcpy(zRet, zStr, nCopy); }else{ *pRc = SQLITE_NOMEM; } } return zRet; } /* ** Finalize the statement passed as the second argument. ** ** If the sqlite3_finalize() call indicates that an error occurs, and the ** ota handle error code is not already set, set the error code and error ** message accordingly. */ static void otaFinalize(sqlite3ota *p, sqlite3_stmt *pStmt){ sqlite3 *db = sqlite3_db_handle(pStmt); int rc = sqlite3_finalize(pStmt); if( p->rc==SQLITE_OK && rc!=SQLITE_OK ){ p->rc = rc; p->zErrmsg = sqlite3_mprintf("%s", sqlite3_errmsg(db)); } } /* Determine the type of a table. ** ** peType is of type (int*), a pointer to an output parameter of type ** (int). This call sets the output parameter as follows, depending ** on the type of the table specified by parameters dbName and zTbl. ** |
︙ | ︙ | |||
712 713 714 715 716 717 718 | } *peType = OTA_PK_NONE; } otaTableType_end: { int i; for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){ | | < < | 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 | } *peType = OTA_PK_NONE; } otaTableType_end: { int i; for(i=0; i<sizeof(aStmt)/sizeof(aStmt[0]); i++){ otaFinalize(p, aStmt[i]); } } } /* ** If they are not already populated, populate the pIter->azTblCol[], ** pIter->abTblPk[], pIter->nTblCol and pIter->bRowid variables according to ** the table (not index) that the iterator currently points to. ** ** Return SQLITE_OK if successful, or an SQLite error code otherwise. If ** an error does occur, an error code and error message are also left in ** the OTA handle. */ static int otaObjIterCacheTableInfo(sqlite3ota *p, OtaObjIter *pIter){ if( pIter->azTblCol==0 ){ sqlite3_stmt *pStmt = 0; int nCol = 0; int i; /* for() loop iterator variable */ int bOtaRowid = 0; /* If input table has column "ota_rowid" */ int iOrder = 0; /* Figure out the type of table this step will deal with. */ assert( pIter->eType==0 ); otaTableType(p, pIter->zTbl, &pIter->eType, &pIter->iPkTnum); if( p->rc ) return p->rc; |
︙ | ︙ | |||
817 818 819 820 821 822 823 | pIter->azTblType[iOrder] = otaStrndup(zType, &p->rc); pIter->abTblPk[iOrder] = (iPk!=0); pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } } | | < < < < < < < < < < < < < < < < < < < < < < < < < | 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 | pIter->azTblType[iOrder] = otaStrndup(zType, &p->rc); pIter->abTblPk[iOrder] = (iPk!=0); pIter->abNotNull[iOrder] = (u8)bNotNull || (iPk!=0); iOrder++; } } otaFinalize(p, pStmt); } return p->rc; } /* ** This function constructs and returns a pointer to a nul-terminated ** string containing some SQL clause or list based on one or more of the ** column names currently stored in the pIter->azTblCol[] array. */ static char *otaObjIterGetCollist( sqlite3ota *p, /* OTA object */ |
︙ | ︙ | |||
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 | */ static void otaBadControlError(sqlite3ota *p){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("invalid ota_control value"); } static char *otaObjIterGetSetlist( sqlite3ota *p, OtaObjIter *pIter, const char *zMask ){ char *zList = 0; if( p->rc==SQLITE_OK ){ | > > > > > > > > > > > > > > > > > | 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 | */ static void otaBadControlError(sqlite3ota *p){ p->rc = SQLITE_ERROR; p->zErrmsg = sqlite3_mprintf("invalid ota_control value"); } /* ** Return a nul-terminated string containing the comma separated list of ** assignments that should be included following the "SET" keyword of ** an UPDATE statement used to update the table object that the iterator ** passed as the second argument currently points to if the ota_control ** column of the data_xxx table entry is set to zMask. ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using ** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the ota handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *otaObjIterGetSetlist( sqlite3ota *p, OtaObjIter *pIter, const char *zMask ){ char *zList = 0; if( p->rc==SQLITE_OK ){ |
︙ | ︙ | |||
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 | } } } } return zList; } static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){ char *zRet = 0; int nByte = nBind*2 + 1; zRet = (char*)otaMalloc(p, nByte); if( zRet ){ int i; | > > > > > > > > > > > > > > > | 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 | } } } } return zList; } /* ** Return a nul-terminated string consisting of nByte comma separated ** "?" expressions. For example, if nByte is 3, return a pointer to ** a buffer containing the string "?,?,?". ** ** The memory for the returned string is obtained from sqlite3_malloc(). ** It is the responsibility of the caller to eventually free it using ** sqlite3_free(). ** ** If an OOM error is encountered when allocating space for the new ** string, an error code is left in the ota handle passed as the first ** argument and NULL is returned. Or, if an error has already occurred ** when this function is called, NULL is returned immediately, without ** attempting the allocation or modifying the stored error code. */ static char *otaObjIterGetBindlist(sqlite3ota *p, int nBind){ char *zRet = 0; int nByte = nBind*2 + 1; zRet = (char*)otaMalloc(p, nByte); if( zRet ){ int i; |
︙ | ︙ | |||
1145 1146 1147 1148 1149 1150 1151 | static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){ char *z = 0; assert( pIter->zIdx==0 ); if( p->rc==SQLITE_OK ){ const char *zSep = "PRIMARY KEY("; sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */ | < < | < | < < < < < < | 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 | static char *otaWithoutRowidPK(sqlite3ota *p, OtaObjIter *pIter){ char *z = 0; assert( pIter->zIdx==0 ); if( p->rc==SQLITE_OK ){ const char *zSep = "PRIMARY KEY("; sqlite3_stmt *pXList = 0; /* PRAGMA index_list = (pIter->zTbl) */ sqlite3_stmt *pXInfo = 0; /* PRAGMA index_xinfo = <pk-index> */ p->rc = prepareFreeAndCollectError(p->db, &pXList, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_list = %Q", pIter->zTbl) ); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXList) ){ const char *zOrig = (const char*)sqlite3_column_text(pXList,3); if( zOrig && strcmp(zOrig, "pk")==0 ){ const char *zIdx = (const char*)sqlite3_column_text(pXList,1); if( zIdx ){ p->rc = prepareFreeAndCollectError(p->db, &pXInfo, &p->zErrmsg, sqlite3_mprintf("PRAGMA main.index_xinfo = %Q", zIdx) ); } break; } } otaFinalize(p, pXList); while( p->rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pXInfo) ){ if( sqlite3_column_int(pXInfo, 5) ){ /* int iCid = sqlite3_column_int(pXInfo, 0); */ const char *zCol = (const char*)sqlite3_column_text(pXInfo, 2); const char *zDesc = sqlite3_column_int(pXInfo, 3) ? " DESC" : ""; z = otaMPrintf(p, "%z%s\"%w\"%s", z, zSep, zCol, zDesc); zSep = ", "; } } z = otaMPrintf(p, "%z)", z); otaFinalize(p, pXInfo); } return z; } /* ** This function creates the second imposter table used when writing to ** a table b-tree where the table has an external primary key. If the ** iterator passed as the second argument does not currently point to ** a table (not index) with an external primary key, this function is a ** no-op. ** |
︙ | ︙ | |||
1212 1213 1214 1215 1216 1217 1218 | */ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType==OTA_PK_EXTERNAL ){ int tnum = pIter->iPkTnum; /* Root page of PK index */ sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */ const char *zIdx = 0; /* Name of PK index */ sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */ | < < < < | 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 | */ static void otaCreateImposterTable2(sqlite3ota *p, OtaObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType==OTA_PK_EXTERNAL ){ int tnum = pIter->iPkTnum; /* Root page of PK index */ sqlite3_stmt *pQuery = 0; /* SELECT name ... WHERE rootpage = $tnum */ const char *zIdx = 0; /* Name of PK index */ sqlite3_stmt *pXInfo = 0; /* PRAGMA main.index_xinfo = $zIdx */ const char *zComma = ""; char *zCols = 0; /* Used to build up list of table cols */ char *zPk = 0; /* Used to build up table PK declaration */ /* Figure out the name of the primary key index for the current table. ** This is needed for the argument to "PRAGMA index_xinfo". Set ** zIdx to point to a nul-terminated string containing this name. */ p->rc = prepareAndCollectError(p->db, &pQuery, &p->zErrmsg, "SELECT name FROM sqlite_master WHERE rootpage = ?" ); |
︙ | ︙ | |||
1253 1254 1255 1256 1257 1258 1259 | iCid, pIter->azTblType[iCid], zCollate ); zPk = otaMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); zComma = ", "; } } zCols = otaMPrintf(p, "%z, id INTEGER", zCols); | | < > | < < < < | < < | | | < < < | | | | < < < < < < | < | 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 | iCid, pIter->azTblType[iCid], zCollate ); zPk = otaMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); zComma = ", "; } } zCols = otaMPrintf(p, "%z, id INTEGER", zCols); otaFinalize(p, pXInfo); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); otaMPrintfExec(p, "CREATE TABLE ota_imposter2(%z, PRIMARY KEY(%z)) WITHOUT ROWID", zCols, zPk ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); } } /* ** If an error has already occurred when this function is called, it ** immediately returns zero (without doing any work). Or, if an error ** occurs during the execution of this function, it sets the error code ** in the sqlite3ota object indicated by the first argument and returns ** zero. ** ** The iterator passed as the second argument is guaranteed to point to ** a table (not an index) when this function is called. This function ** attempts to create any imposter table required to write to the main ** table b-tree of the table before returning. Non-zero is returned if ** an imposter table are created, or zero otherwise. ** ** An imposter table is required in all cases except OTA_PK_VTAB. Only ** virtual tables are written to directly. The imposter table has the ** same schema as the actual target table (less any UNIQUE constraints). ** More precisely, the "same schema" means the same columns, types, ** collation sequences. For tables that do not have an external PRIMARY ** KEY, it also means the same PRIMARY KEY declaration. */ static void otaCreateImposterTable(sqlite3ota *p, OtaObjIter *pIter){ if( p->rc==SQLITE_OK && pIter->eType!=OTA_PK_VTAB ){ int tnum = pIter->iTnum; const char *zComma = ""; char *zSql = 0; int iCol; |
︙ | ︙ | |||
1336 1337 1338 1339 1340 1341 1342 | if( pIter->eType==OTA_PK_WITHOUT_ROWID ){ char *zPk = otaWithoutRowidPK(p, pIter); if( zPk ){ zSql = otaMPrintf(p, "%z, %z", zSql, zPk); } } | > | < < < | < < | 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | if( pIter->eType==OTA_PK_WITHOUT_ROWID ){ char *zPk = otaWithoutRowidPK(p, pIter); if( zPk ){ zSql = otaMPrintf(p, "%z, %z", zSql, zPk); } } sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 1, tnum); otaMPrintfExec(p, "CREATE TABLE \"ota_imp_%w\"(%z)%s", pIter->zTbl, zSql, (pIter->eType==OTA_PK_WITHOUT_ROWID ? " WITHOUT ROWID" : "") ); sqlite3_test_control(SQLITE_TESTCTRL_IMPOSTER, p->db, "main", 0, 0); } } /* ** Ensure that the SQLite statement handles required to update the ** target database object currently indicated by the iterator passed ** as the second argument are available. |
︙ | ︙ | |||
1543 1544 1545 1546 1547 1548 1549 | sqlite3_free(zCollist); sqlite3_free(zLimit); } return p->rc; } | < > | | | | | | | | | | 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 | sqlite3_free(zCollist); sqlite3_free(zLimit); } return p->rc; } /* ** Set output variable *ppStmt to point to an UPDATE statement that may ** be used to update the imposter table for the main table b-tree of the ** table object that pIter currently points to, assuming that the ** ota_control column of the data_xyz table contains zMask. */ static int otaGetUpdateStmt( sqlite3ota *p, /* OTA handle */ OtaObjIter *pIter, /* Object iterator */ const char *zMask, /* ota_control value ('x.x.') */ sqlite3_stmt **ppStmt /* OUT: UPDATE statement handle */ ){ if( pIter->pUpdate && strcmp(zMask, pIter->zMask)==0 ){ *ppStmt = pIter->pUpdate; }else{ char *zWhere = otaObjIterGetWhere(p, pIter); char *zSet = otaObjIterGetSetlist(p, pIter, zMask); char *zUpdate = 0; |
︙ | ︙ | |||
2003 2004 2005 2006 2007 2008 2009 | ** is already a transaction open, so the prepared statement cannot ** throw an SQLITE_SCHEMA exception. The only database page the ** statement reads is page 1, which is guaranteed to be in the cache. ** And no memory allocations are required. */ if( SQLITE_ROW==sqlite3_step(pStmt) ){ iCookie = sqlite3_column_int(pStmt, 0); } | | | 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 | ** is already a transaction open, so the prepared statement cannot ** throw an SQLITE_SCHEMA exception. The only database page the ** statement reads is page 1, which is guaranteed to be in the cache. ** And no memory allocations are required. */ if( SQLITE_ROW==sqlite3_step(pStmt) ){ iCookie = sqlite3_column_int(pStmt, 0); } otaFinalize(p, pStmt); } if( p->rc==SQLITE_OK ){ otaMPrintfExec(p, "PRAGMA schema_version = %d", iCookie+1); } } } |
︙ | ︙ | |||
2035 2036 2037 2038 2039 2040 2041 | OTA_STATE_TBL, p->objiter.zTbl, OTA_STATE_IDX, p->objiter.zIdx, OTA_STATE_ROW, p->nStep, OTA_STATE_PROGRESS, p->nProgress, OTA_STATE_CKPT, p->iWalCksum, OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie ) | | < < < | < < | 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 | OTA_STATE_TBL, p->objiter.zTbl, OTA_STATE_IDX, p->objiter.zIdx, OTA_STATE_ROW, p->nStep, OTA_STATE_PROGRESS, p->nProgress, OTA_STATE_CKPT, p->iWalCksum, OTA_STATE_COOKIE, (i64)p->pTargetFd->iCookie ) ); assert( pInsert==0 || rc==SQLITE_OK ); if( rc==SQLITE_OK ){ sqlite3_step(pInsert); rc = sqlite3_finalize(pInsert); } if( rc!=SQLITE_OK ) p->rc = rc; } } /* ** Step the OTA object. */ |
︙ | ︙ | |||
3099 3100 3101 3102 3103 3104 3105 3106 3107 3108 3109 3110 3111 3112 | static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return 0; } void sqlite3ota_destroy_vfs(const char *zName){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); if( pVfs && pVfs->xOpen==otaVfsOpen ){ sqlite3_vfs_unregister(pVfs); sqlite3_free(pVfs); } } int sqlite3ota_create_vfs(const char *zName, const char *zParent){ | > | 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 | static int otaVfsGetLastError(sqlite3_vfs *pVfs, int a, char *b){ return 0; } void sqlite3ota_destroy_vfs(const char *zName){ sqlite3_vfs *pVfs = sqlite3_vfs_find(zName); if( pVfs && pVfs->xOpen==otaVfsOpen ){ sqlite3_mutex_free(((ota_vfs*)pVfs)->mutex); sqlite3_vfs_unregister(pVfs); sqlite3_free(pVfs); } } int sqlite3ota_create_vfs(const char *zName, const char *zParent){ |
︙ | ︙ | |||
3154 3155 3156 3157 3158 3159 3160 | rc = SQLITE_NOTFOUND; }else{ char *zSpace; memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs)); pNew->base.mxPathname = pParent->mxPathname; pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile; pNew->pRealVfs = pParent; | < | > > > > | > > > > > > < < < | 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 | rc = SQLITE_NOTFOUND; }else{ char *zSpace; memcpy(&pNew->base, &vfs_template, sizeof(sqlite3_vfs)); pNew->base.mxPathname = pParent->mxPathname; pNew->base.szOsFile = sizeof(ota_file) + pParent->szOsFile; pNew->pRealVfs = pParent; pNew->base.zName = (const char*)(zSpace = (char*)&pNew[1]); memcpy(zSpace, zName, nName); /* Allocate the mutex and register the new VFS (not as the default) */ pNew->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_RECURSIVE); if( pNew->mutex==0 ){ rc = SQLITE_NOMEM; }else{ rc = sqlite3_vfs_register(&pNew->base, 0); } } if( rc!=SQLITE_OK ){ sqlite3_mutex_free(pNew->mutex); sqlite3_free(pNew); } } return rc; } /**************************************************************************/ #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_OTA) */ |