Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the "modeof=<filename>" URI parameter to os_unix.c - used to specify a file to copy permissions from when a new database is created. Also allow passing NULL as the second parameter to sqlite3rbu_vacuum(). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ed406d31ff54ee3de8db91690a966e5c |
User & Date: | dan 2016-08-11 18:05:47.763 |
Context
2016-08-13
| ||
06:38 | Fix a buffer overread in fts5. (check-in: fcfbee6c7d user: dan tags: trunk) | |
2016-08-12
| ||
16:21 | Have wal file checkpoints exit early if the sqlite3_interrupt() API function is called. (check-in: 8a5f41c7b1 user: dan tags: interruptible-checkpoint) | |
2016-08-11
| ||
19:12 | Merge version 3.14 plus some subsequent patches (including the page-cache performance patch) from trunk. (check-in: d9f8918c5b user: drh tags: begin-concurrent) | |
18:05 | Add the "modeof=<filename>" URI parameter to os_unix.c - used to specify a file to copy permissions from when a new database is created. Also allow passing NULL as the second parameter to sqlite3rbu_vacuum(). (check-in: ed406d31ff user: dan tags: trunk) | |
09:55 | Fix a 1 byte buffer overwrite in the "sqldiff --rbu" command. (check-in: ab83d7077d user: dan tags: trunk) | |
Changes
Changes to ext/rbu/rbuprogress.test.
︙ | ︙ | |||
356 357 358 359 360 361 362 363 364 365 366 367 368 369 | CREATE TABLE t1(a, b, c); CREATE INDEX t1c ON t1(c); } vtab { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); } } { foreach {tn2 rbusql r1 r2} { 1 { CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control); INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0); INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0); CREATE TABLE rbu_count(tbl, cnt); | > > | 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 | CREATE TABLE t1(a, b, c); CREATE INDEX t1c ON t1(c); } vtab { CREATE VIRTUAL TABLE t1 USING fts5(a, b, c); } } { if {$tn=="vtab"} { ifcapable !fts5 break } foreach {tn2 rbusql r1 r2} { 1 { CREATE TABLE data0_t1(a, b, c, rbu_rowid, rbu_control); INSERT INTO data0_t1 VALUES(15, 15, 15, 4, 0); INSERT INTO data0_t1 VALUES(20, 20, 20, 5, 0); CREATE TABLE rbu_count(tbl, cnt); |
︙ | ︙ |
Changes to ext/rbu/rbuvacuum2.test.
︙ | ︙ | |||
152 153 154 155 156 157 158 | SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } } | | | > > > | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 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 203 204 | SELECT * FROM sqlite_master; } { table t1 t1 2 {CREATE TABLE t1(a, b, c)} view v1 v1 0 {CREATE VIEW v1 AS SELECT * FROM t1} trigger tr1 t1 0 {CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN SELECT 1; END} } } } #------------------------------------------------------------------------- # Test that passing a NULL value as the second argument to # sqlite3rbu_vacuum() causes it to: # # * Use <database>-vacuum as the state db, and # * Set the state db permissions to the same as those on the db file. # db close if {$::tcl_platform(platform)=="unix"} { forcedelete test.db sqlite3 db test.db do_execsql_test 5.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); } db close foreach {tn perm} { 1 00755 2 00666 3 00644 4 00444 } { forcedelete test.db-vacuum do_test 5.$tn.1 { file attributes test.db -permissions $perm sqlite3rbu_vacuum rbu test.db rbu step } {SQLITE_OK} do_test 5.$tn.2 { file exists test.db-vacuum } 1 do_test 5.$tn.3 { file attributes test.db-vacuum -permissions} $perm rbu close } } finish_test |
Changes to ext/rbu/sqlite3rbu.c.
︙ | ︙ | |||
2330 2331 2332 2333 2334 2335 2336 | /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ | < | | > > > > | 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 | /* ** Open the database handle and attach the RBU database as "rbu". If an ** error occurs, leave an error code and message in the RBU handle. */ static void rbuOpenDatabase(sqlite3rbu *p){ assert( p->rc || (p->dbMain==0 && p->dbRbu==0) ); assert( p->rc || rbuIsVacuum(p) || p->zTarget!=0 ); /* Open the RBU database */ p->dbRbu = rbuOpenDbhandle(p, p->zRbu, 1); if( p->rc==SQLITE_OK && rbuIsVacuum(p) ){ sqlite3_file_control(p->dbRbu, "main", SQLITE_FCNTL_RBUCNT, (void*)p); if( p->zState==0 ){ const char *zFile = sqlite3_db_filename(p->dbRbu, "main"); p->zState = rbuMPrintf(p, "file://%s-vacuum?modeof=%s", zFile, zFile); } } /* If using separate RBU and state databases, attach the state database to ** the RBU db handle now. */ if( p->zState ){ rbuMPrintfExec(p, p->dbRbu, "ATTACH %Q AS stat", p->zState); memcpy(p->zStateDb, "stat", 4); |
︙ | ︙ | |||
3473 3474 3475 3476 3477 3478 3479 | const char *zTarget, const char *zRbu, const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); | < | | 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 | const char *zTarget, const char *zRbu, const char *zState ){ sqlite3rbu *p; size_t nTarget = zTarget ? strlen(zTarget) : 0; size_t nRbu = strlen(zRbu); size_t nByte = sizeof(sqlite3rbu) + nTarget+1 + nRbu+1; p = (sqlite3rbu*)sqlite3_malloc64(nByte); if( p ){ RbuState *pState = 0; /* Create the custom VFS. */ memset(p, 0, sizeof(sqlite3rbu)); |
︙ | ︙ | |||
3496 3497 3498 3499 3500 3501 3502 | memcpy(p->zTarget, zTarget, nTarget+1); pCsr += nTarget+1; } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ | | < | 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 | memcpy(p->zTarget, zTarget, nTarget+1); pCsr += nTarget+1; } p->zRbu = pCsr; memcpy(p->zRbu, zRbu, nRbu+1); pCsr += nRbu+1; if( zState ){ p->zState = rbuMPrintf(p, "%s", zState); } rbuOpenDatabase(p); } if( p->rc==SQLITE_OK ){ pState = rbuLoadState(p); assert( pState || p->rc!=SQLITE_OK ); |
︙ | ︙ | |||
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 | } rbuFreeState(pState); } return p; } /* ** Open and return a new RBU handle. */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* ** Open a handle to begin or resume an RBU VACUUM operation. */ sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState ){ /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } /* ** Return the database handle used by pRbu. */ | > > > > > > > > > > > > > > > > | 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 | } rbuFreeState(pState); } return p; } /* ** Allocate and return an RBU handle with all fields zeroed except for the ** error code, which is set to SQLITE_MISUSE. */ static sqlite3rbu *rbuMisuseError(void){ sqlite3rbu *pRet; pRet = sqlite3_malloc64(sizeof(sqlite3rbu)); if( pRet ){ memset(pRet, 0, sizeof(sqlite3rbu)); pRet->rc = SQLITE_MISUSE; } return pRet; } /* ** Open and return a new RBU handle. */ sqlite3rbu *sqlite3rbu_open( const char *zTarget, const char *zRbu, const char *zState ){ if( zTarget==0 || zRbu==0 ){ return rbuMisuseError(); } /* TODO: Check that zTarget and zRbu are non-NULL */ return openRbuHandle(zTarget, zRbu, zState); } /* ** Open a handle to begin or resume an RBU VACUUM operation. */ sqlite3rbu *sqlite3rbu_vacuum( const char *zTarget, const char *zState ){ if( zTarget==0 ){ return rbuMisuseError(); } /* TODO: Check that both arguments are non-NULL */ return openRbuHandle(0, zTarget, zState); } /* ** Return the database handle used by pRbu. */ |
︙ | ︙ | |||
3703 3704 3705 3706 3707 3708 3709 3710 3711 3712 3713 3714 3715 3716 | rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } return rc; } | > | 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 | rbuDeleteVfs(p); sqlite3_free(p->aBuf); sqlite3_free(p->aFrame); rbuEditErrmsg(p); rc = p->rc; *pzErrmsg = p->zErrmsg; sqlite3_free(p->zState); sqlite3_free(p); }else{ rc = SQLITE_NOMEM; *pzErrmsg = 0; } return rc; } |
︙ | ︙ |
Changes to ext/rbu/sqlite3rbu.h.
︙ | ︙ | |||
315 316 317 318 319 320 321 | ); /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** | | | | | | > > > > > > | 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 | ); /* ** Open an RBU handle to perform an RBU vacuum on database file zTarget. ** An RBU vacuum is similar to SQLite's built-in VACUUM command, except ** that it can be suspended and resumed like an RBU update. ** ** The second argument to this function identifies a database in which ** to store the state of the RBU vacuum operation if it is suspended. The ** first time sqlite3rbu_vacuum() is called, to start an RBU vacuum ** operation, the state database should either not exist or be empty ** (contain no tables). If an RBU vacuum is suspended by calling ** sqlite3rbu_close() on the RBU handle before sqlite3rbu_step() has ** returned SQLITE_DONE, the vacuum state is stored in the state database. ** The vacuum can be resumed by calling this function to open a new RBU ** handle specifying the same target and state databases. ** ** If the second argument passed to this function is NULL, then the ** name of the state database is "<database>-vacuum", where <database> ** is the name of the target database file. In this case, on UNIX, if the ** state database is not already present in the file-system, it is created ** with the same permissions as the target db is made. ** ** This function does not delete the state database after an RBU vacuum ** is completed, even if it created it. However, if the call to ** sqlite3rbu_close() returns any value other than SQLITE_OK, the contents ** of the state tables within the state database are zeroed. This way, ** the next call to sqlite3rbu_vacuum() opens a handle that starts a ** new RBU vacuum operation. |
︙ | ︙ |
Changes to ext/rbu/test_rbu.c.
︙ | ︙ | |||
236 237 238 239 240 241 242 | Tcl_Obj *CONST objv[] ){ sqlite3rbu *pRbu = 0; const char *zCmd; const char *zTarget; const char *zStateDb = 0; | | | | | 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | Tcl_Obj *CONST objv[] ){ sqlite3rbu *pRbu = 0; const char *zCmd; const char *zTarget; const char *zStateDb = 0; if( objc!=3 && objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "NAME TARGET-DB ?STATE-DB?"); return TCL_ERROR; } zCmd = Tcl_GetString(objv[1]); zTarget = Tcl_GetString(objv[2]); if( objc==4 ) zStateDb = Tcl_GetString(objv[3]); pRbu = sqlite3rbu_vacuum(zTarget, zStateDb); Tcl_CreateObjCommand(interp, zCmd, test_sqlite3rbu_cmd, (ClientData)pRbu, 0); Tcl_SetObjResult(interp, objv[1]); return TCL_OK; } |
︙ | ︙ |
Changes to src/os_unix.c.
︙ | ︙ | |||
5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 | } } unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. | > > > > > > > > > > > > > > > > > > > > > | 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 5549 5550 5551 5552 5553 5554 5555 5556 5557 5558 | } } unixLeaveMutex(); } #endif /* if !OS_VXWORKS */ return pUnused; } /* ** Find the mode, uid and gid of file zFile. */ static int getFileMode( const char *zFile, /* File name */ mode_t *pMode, /* OUT: Permissions of zFile */ uid_t *pUid, /* OUT: uid of zFile. */ gid_t *pGid /* OUT: gid of zFile. */ ){ struct stat sStat; /* Output of stat() on database file */ int rc = SQLITE_OK; if( 0==osStat(zFile, &sStat) ){ *pMode = sStat.st_mode & 0777; *pUid = sStat.st_uid; *pGid = sStat.st_gid; }else{ rc = SQLITE_IOERR_FSTAT; } return rc; } /* ** This function is called by unixOpen() to determine the unix permissions ** to create new files with. If no error occurs, then SQLITE_OK is returned ** and a value suitable for passing as the third argument to open(2) is ** written to *pMode. If an IO error occurs, an SQLite error code is ** returned and the value of *pMode is not modified. |
︙ | ︙ | |||
5560 5561 5562 5563 5564 5565 5566 | int rc = SQLITE_OK; /* Return Code */ *pMode = 0; *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ | < | 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 | int rc = SQLITE_OK; /* Return Code */ *pMode = 0; *pUid = 0; *pGid = 0; if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ char zDb[MAX_PATHNAME+1]; /* Database file path */ int nDb; /* Number of valid bytes in zDb */ /* zPath is a path to a WAL or journal file. The following block derives ** the path to the associated database file from zPath. This block handles ** the following naming conventions: ** ** "<path to db>-journal" ** "<path to db>-wal" |
︙ | ︙ | |||
5591 5592 5593 5594 5595 5596 5597 | if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; #endif nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; | | < < < < < < > > > > > > > > > | 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 5631 5632 5633 5634 5635 5636 | if( nDb==0 || zPath[nDb]=='.' ) return SQLITE_OK; #endif nDb--; } memcpy(zDb, zPath, nDb); zDb[nDb] = '\0'; rc = getFileMode(zDb, pMode, pUid, pGid); }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ *pMode = 0600; }else if( flags & SQLITE_OPEN_URI ){ /* If this is a main database file and the file was opened using a URI ** filename, check for the "modeof" parameter. If present, interpret ** its value as a filename and try to copy the mode, uid and gid from ** that file. */ const char *z = sqlite3_uri_parameter(zPath, "modeof"); if( z ){ rc = getFileMode(z, pMode, pUid, pGid); } } return rc; } /* ** Open the file zPath. ** |
︙ | ︙ |