From: dan Date: Thu, 21 Mar 2019 17:13:55 +0000 (+0000) Subject: Disable the feature on this branch in non-SQLITE_ENABLE_SHARED_SCHEMA builds. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6847647dc43ff029a63c304216afd1d596a09637;p=thirdparty%2Fsqlite.git Disable the feature on this branch in non-SQLITE_ENABLE_SHARED_SCHEMA builds. FossilOrigin-Name: b8e536089b0e6dec500a28556f826c99b78d979615ba3bc01ed31ead1b2112df --- diff --git a/manifest b/manifest index d62d786aa5..b8cb9f4b06 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Use\sthe\sIsReuseSchema()\smacro\smore\sconsistently.\sAlso,\srename\sit\sto\sIsSharedSchema(). -D 2019-03-20T20:02:03.478 +C Disable\sthe\sfeature\son\sthis\sbranch\sin\snon-SQLITE_ENABLE_SHARED_SCHEMA\sbuilds. +D 2019-03-21T17:13:55.850 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -461,8 +461,8 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 9bcd70009cac284622ef6816daca22fda99b4fb54ce0027b461dea52bcb299fa F src/btree.h 63b94fb38ce571c15eb6a3661815561b501d23d5948b2d1e951fbd7a2d04e8d3 F src/btreeInt.h 6111c15868b90669f79081039d19e7ea8674013f907710baa3c814dc3f8bfd3f -F src/build.c f570cb78948123fe0a91689fa9a9e1f49e7ab8234edfb7524b9a038283549973 -F src/callback.c 21d7b961db048f614a6db9c6500f59f05a4e4a720e266249387ecea3eec907ff +F src/build.c 83ab73704ba4040b58a68079d2e7190e33ac07b0c6cb0ad829816312055bbf39 +F src/callback.c 5a9a83d7cecce452902da0a24bf51f6e4d232b5dc54b67418276ca9ad82c5bde F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 @@ -481,7 +481,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 4ce12b5ba3bcbfa17ec37ce960d499fc287b6289df2c00b31201f716a3c7df45 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c e6f10875d52aca3b7e57ce1ec174aeafc9b6c00b43000cd30d791f9cb490b7a6 -F src/main.c 5ff1ca2b9c780d48ca13419e645ae7580dbd126ce5a054dea12b40a039c60776 +F src/main.c cfc789be51029ac70b040a78e0d49919f85e698aded32ebb80f6c0c11637fb4b F src/malloc.c 0f9da2a66b230a5785af94b9672126845099b57b70a32c987d04ac28c69da990 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -512,21 +512,21 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c a72804486dfa8e4b6bc30d666c97ecf1155f91a4351fc6e48ea4097e4eb304fb F src/pragma.c 13e40651f965e9ac6d4fd44d6c48c4152185209b677b253dc2141c32c14c8dd6 F src/pragma.h 9d7658a7be442c1149409aab8ebdde012f387de66fca20056fc9e0791e40dbda -F src/prepare.c d5e6339a34cb45036939918fa3ad1912cdcf37c5c2e162d01d5acdd3922185c8 +F src/prepare.c ed5110154bd7644665398b8e5801937f83af3a069c928244235462b5e3adcef3 F src/printf.c 93a3d539019264683a444bc043c875e9a6cca43fe935ae7bf6cfff0af3bba118 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c 09419ad5c432190b69be7c0c326e03abb548a97c2c50675b81b459e1b382d1d2 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 9263f5c30dd44c7ac2eb29f40a7ec64322a96885b71c00de6bc30b756c2e1c49 -F src/shell.c.in 84f22bfbceb3134db28da6f6cae75ef15f44b3c4615566597e5643f382e61d9b +F src/shell.c.in c82e5dce0bb03a63db6ce53070d1eb0692c50b9c2bcf8e2d6ade4a743a7a53bd F src/sqlite.h.in 1fa197fc89b9924531ab0b6b07e2f7ae3e2862509c32c136e547752cd6374e49 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 -F src/sqliteInt.h d2b17367c2159d754dac229d94ddf3292693ae96c5ee87c9f846ff83d2bb30ae +F src/sqliteInt.h 0d7cbc244dcc508a6bc6cf89a0af5f25ee5d28ac9c5cbe6c563290fdc0197d03 F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b -F src/status.c 28fcf86faee5cc030ca2d5d6b356fc59999cffb478457fe343ae0f9c39b41f6b +F src/status.c d9f7d66ae8bee9ffbe4cf7ae72a8d3d429a269336dee1e705ecb3dbea27fa5e2 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 -F src/tclsqlite.c 9514e43ebd89325e150fad84b164e2b9ba221050b392ab444f4e7f9e8af46082 +F src/tclsqlite.c 5947f3797410e213cde1d61f61fbfda706ee4ee2e1db6e0b2376e3206dabc71d F src/test1.c cfb303eeddd3670409af6b58d2ddb928b8e9e70822d681d3df88dfaabb7bea6a F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 @@ -542,7 +542,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0 F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857 F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274 -F src/test_config.c 5ebafbcd5c75ac1c16bb0c8fe926dc325cc03e780943a88ca50e0d9a4fc4d2f5 +F src/test_config.c 4f7a5aa4644ae47fb9de228f7b92cdddebbc1191b4a18f382af6ab48fb7b921e F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2 @@ -566,7 +566,7 @@ F src/test_quota.c 6cb9297115b551f433a9ad1741817a9831abed99 F src/test_quota.h 2a8ad1952d1d2ca9af0ce0465e56e6c023b5e15d F src/test_rtree.c 671f3fae50ff116ef2e32a3bf1fe21b5615b4b7b F src/test_schema.c f575932cb6274d12147a77e13ea4b49d52408513 -F src/test_schemapool.c a94030902625581c2c71c2a9989dd5895d3d0b77cc84419eea58f5b0efd6c7cd +F src/test_schemapool.c ae21a79f9bc7e9099ae78dbd46d5c28ee75330e62e3256a9fde25564ff9df492 F src/test_server.c a2615049954cbb9cfb4a62e18e2f0616e4dc38fe F src/test_sqllog.c 11e6ce7575f489155c604ac4b439f2ac1d3d5aef F src/test_superlock.c 4839644b9201da822f181c5bc406c0b2385f672e @@ -583,7 +583,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c d3615f0cbe4db5949503bf5916f3cd4fa5de855d5b4ef560f3b6dd5629423a1e F src/treeview.c c6ff90da4cc1813ff2d9bb11f17d4d927db62c47e552faa1835edc47269d753d -F src/trigger.c 665001b50b002aed08f01de55d125ed70552f9a19384a3a6dc50eeb8a9c854a3 +F src/trigger.c 020d7ad68bee5c3f0f2244eb8c2b53394f908a4f63fe0017dc8cd001e4998931 F src/update.c 0b973357d88092140531e07ff641139c26fb4380b0b9f5ed98c5f7691b4604d1 F src/upsert.c 0dd81b40206841814d46942a7337786932475f085716042d0cb2fc7791bf8ca4 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 @@ -598,7 +598,7 @@ F src/vdbeblob.c 08e58c6bef990008b8c2dbad4c99c56d3b622ee79433004484cce29b536e2ab F src/vdbemem.c 3e89e087df928eba80e520824078dc563c579a0848b1557ac36845ec14392923 F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f F src/vdbetrace.c 79d6dbbc479267b255a7de8080eee6e729928a0ef93ed9b0bfa5618875b48392 -F src/vtab.c e6309a17973c7148968b5070334849ece8d09592415cc5bd1c70e2d2fb46ce46 +F src/vtab.c b7214e9cc0925a646a3b4bca4d38e29c245aecb7807a2c70ee7b5e314f338ac8 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 3f4f653daf234fe713edbcbca3fec2350417d159d28801feabc702a22c4e213f F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a @@ -1229,12 +1229,12 @@ F test/reindex.test 44edd3966b474468b823d481eafef0c305022254 F test/releasetest.tcl 7712811e0f4e2f198ec786cb2e1352b3793d7395f48a3cceef0572d8823eb75e x F test/resetdb.test 8062cf10a09d8c048f8de7711e94571c38b38168db0e5877ba7561789e5eeb2b F test/resolver01.test f4022acafda7f4d40eca94dbf16bc5fc4ac30ceb -F test/reuse1.test 31c312375ccfcc5c2abc1fca5e4a89d6309c57ea6b1fa3179a5eee68016f9c74 -F test/reuse2.test 04d88621f0c51a8b3bf5512b9e61a5d7a61059e33097a1a6b1c6f6cf2d1f2a35 -F test/reuse3.test 75071034556d4915066adc249bfac364c6ed0fc62c997c4b02410fdacd3bfb9d -F test/reuse4.test 5a5aa075db13fb09299b68b43040f9e205c3ad8f84a0f083030dc8df32a7cac8 -F test/reuse5.test f3b8a355b9031205d614ad7e62db2186168539bb3fe56ea3b4ceac1b83e96e1e -F test/reusefault.test 5d60bfbcaccfaffa02132f2137d849dc4b3802da8a929054e23f483bf5dc06e4 +F test/reuse1.test faa2ce5ff566d936b8a10d9e22ba2ee66a54ce89fdcf8aef561df6b15b0ff3d3 +F test/reuse2.test 5dd9c98579358f0d5a90d25e36dd6e678a03e23446b6c7f2630a8da22ae7ca94 +F test/reuse3.test c7c57dc70e2e113dafbbfa5d4de3050df435f74f5e31ec5266f92a009f4345bd +F test/reuse4.test adaad66253aea6cc748674328abe69b650c5c78b8676ed1162d3de09742519f9 +F test/reuse5.test bbe6cf7384ef90f134392edd93d626385ef0bf6f40eefc3d993535cd0861d83b +F test/reusefault.test ef646a0fb51d50ddfb4b7cd872f88e7d36eaba64bde7797b3418c3774e1c8d14 F test/rollback.test 06680159bc6746d0f26276e339e3ae2f951c64812468308838e0a3362d911eaa F test/rollback2.test bc868d57899dc6972e2b4483faae0e03365a0556941474eec487ae21d8d38bb6 F test/rollbackfault.test 0e646aeab8840c399cfbfa43daab46fd609cf04a @@ -1375,7 +1375,7 @@ F test/tabfunc01.test 20e98ffe55f35d8d33fd834ca8bf9d4b637e560af8fcd00464b4154d90 F test/table.test eb3463b7add9f16a5bb836badf118cf391b809d09fdccd1f79684600d07ec132 F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 -F test/tclsqlite.test b30e975cf2dc1c53ff98018065ac120ae43a81fb4fc5a94ddc80b9bcc2c012d6 +F test/tclsqlite.test 7ea484c9fb74d47d48c62b18a97b287c418b0c3aeacc639133b04a7e426d58af F test/tempdb.test 4cdaa23ddd8acb4d79cbb1b68ccdfd09b0537aaba909ca69a876157c2a2cbd08 F test/tempdb2.test 2479226e4cb96f4c663eccd2d12c077cf6bda29ca5cc69a8a58a06127105dd62 F test/tempfault.test 0c0d349c9a99bf5f374655742577f8712c647900 @@ -1815,7 +1815,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a70fdaa3903835dca338d68e750716fd3ab9dedbdfb2be6d6e058fd5fcb415fa -R 03048eccd08d4cc9b57de50f5fa4d0a2 +P c1be211c0286a6ff3ef8ab6839136175efb000118ff8704d3cc01b2a23b841ab +R 29b54ab2e06b9087f7fabff74d0fd117 U dan -Z 2bc1d554630c6ff83c63ed8652224e04 +Z 22c9b5d8d7092496164e8327b898d8b0 diff --git a/manifest.uuid b/manifest.uuid index 74aafadfc8..fb6d213092 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c1be211c0286a6ff3ef8ab6839136175efb000118ff8704d3cc01b2a23b841ab \ No newline at end of file +b8e536089b0e6dec500a28556f826c99b78d979615ba3bc01ed31ead1b2112df \ No newline at end of file diff --git a/src/build.c b/src/build.c index 16510f7c7a..b98a5f0808 100644 --- a/src/build.c +++ b/src/build.c @@ -286,6 +286,7 @@ int sqlite3UserAuthTable(const char *zTable){ } #endif +#ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** If this database connection was opened with the SQLITE_OPEN_SHARED_SCHEMA ** flag specified, then ensure that the database schema for database iDb @@ -316,6 +317,7 @@ int sqlite3SchemaLoad(sqlite3 *db, int iDb, int *pbUnload, char **pzErr){ } return rc; } +#endif /* ** Locate the in-memory structure that describes a particular database diff --git a/src/callback.c b/src/callback.c index fa2b18f206..46e1cf9d4f 100644 --- a/src/callback.c +++ b/src/callback.c @@ -40,6 +40,7 @@ struct SchemaPool { SchemaPool *pNext; /* Next element in schemaPoolList */ }; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA #ifdef SQLITE_DEBUG static void assert_schema_state_ok(sqlite3 *db){ if( IsSharedSchema(db) && db->magic!=SQLITE_MAGIC_ZOMBIE ){ @@ -69,6 +70,7 @@ static void assert_schema_state_ok(sqlite3 *db){ #else # define assert_schema_state_ok(x) #endif +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Invoke the 'collation needed' callback to request a collation sequence @@ -529,13 +531,17 @@ void sqlite3SchemaClear(void *p){ */ void sqlite3SchemaClearOrDisconnect(sqlite3 *db, int iDb){ Db *pDb = &db->aDb[iDb]; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 && pDb->pSPool ){ sqlite3SchemaDisconnect(db, iDb, 1); - }else{ + }else +#endif + { sqlite3SchemaClear(pDb->pSchema); } } +#ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** Global linked list of SchemaPool objects. Read and write access must ** be protected by the SQLITE_MUTEX_STATIC_MASTER mutex. @@ -810,6 +816,8 @@ void sqlite3SchemaRelease(sqlite3 *db, int iDb){ sqlite3_mutex_leave( sqlite3_mutex_alloc(SQLITE_MUTEX_STATIC_MASTER) ); } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ + /* ** In most cases, this function finds and returns the schema associated ** with BTree handle pBt, creating a new one if necessary. However, if @@ -822,9 +830,7 @@ Schema *sqlite3SchemaGet(sqlite3 *db, Btree *pBt){ if( pBt && IsSharedSchema(db)==0 ){ p = (Schema*)sqlite3BtreeSchema(pBt, sizeof(Schema), sqlite3SchemaClear); }else{ - db->lookaside.bDisable++; - p = (Schema*)sqlite3DbMallocZero(db, sizeof(Schema)); - db->lookaside.bDisable--; + p = (Schema*)sqlite3DbMallocZero(0, sizeof(Schema)); } if( !p ){ sqlite3OomFault(db); diff --git a/src/main.c b/src/main.c index 3f33aae648..8c1b386033 100644 --- a/src/main.c +++ b/src/main.c @@ -1054,7 +1054,8 @@ static void disconnectAllVtab(sqlite3 *db){ if( IsVirtual(pTab) ) sqlite3VtabDisconnect(db, pTab); } } - if( i!=1 && IsSharedSchema(db) ){ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + if( IsSharedSchema(db) && i!=1 ){ VTable *pVTable; VTable *pNext; for(pVTable=db->aDb[i].pVTable; pVTable; pVTable=pNext){ @@ -1063,6 +1064,7 @@ static void disconnectAllVtab(sqlite3 *db){ } db->aDb[i].pVTable = 0; } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ } for(p=sqliteHashFirst(&db->aModule); p; p=sqliteHashNext(p)){ Module *pMod = (Module *)sqliteHashData(p); @@ -3632,14 +3634,18 @@ int sqlite3_table_column_metadata( /* Locate the table in question */ if( rc==SQLITE_OK ){ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA Parse sParse; /* Fake Parse object for FindTable */ Parse *pSaved = db->pParse; memset(&sParse, 0, sizeof(sParse)); db->pParse = &sParse; +#endif pTab = sqlite3FindTable(db, zTableName, zDbName); +#ifdef SQLITE_ENABLE_SHARED_SCHEMA sqlite3_free(sParse.zErrMsg); rc = sParse.rc; db->pParse = pSaved; +#endif } if( SQLITE_OK!=rc ) goto error_out; diff --git a/src/prepare.c b/src/prepare.c index d1a6650454..e848b8bd63 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -49,11 +49,12 @@ static void corruptSchema( } } +#ifdef SQLITE_ENABLE_SHARED_SCHEMA /* ** Update the Schema.cksum checksum to account for the database object ** specified by the three arguments following the first. */ -void schemaUpdateChecksum( +static void schemaUpdateChecksum( InitData *pData, /* Schema parse context */ const char *zName, /* Name of new database object */ const char *zRoot, /* Root page of new database object */ @@ -68,6 +69,7 @@ void schemaUpdateChecksum( if( zSql ) for(i=0; zSql[i]; i++) cksum += (cksum<<3) + zSql[i]; pData->cksum = cksum; } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Check to see if any sibling index (another index on the same table) @@ -141,8 +143,10 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ if( rc==SQLITE_NOMEM ){ sqlite3OomFault(db); }else if( rc!=SQLITE_INTERRUPT +#ifdef SQLITE_ENABLE_SHARED_SCHEMA && (rc&0xFF)!=SQLITE_LOCKED && (rc&0xFF)!=SQLITE_IOERR +#endif ){ corruptSchema(pData, argv[0], sqlite3_errmsg(db)); } @@ -169,9 +173,11 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){ } } - if( iDb!=1 && IsSharedSchema(db) ){ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + if( IsSharedSchema(db) && iDb!=1 ){ schemaUpdateChecksum(pData, argv[0], argv[1], argv[2]); } +#endif return 0; } @@ -203,6 +209,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ assert( iDb==1 || sqlite3BtreeHoldsMutex(db->aDb[iDb].pBt) ); pDb = &db->aDb[iDb]; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA assert( pDb->pSPool==0 || IsSharedSchema(db) ); if( pDb->pSPool ){ /* See if there is a free schema object in the schema-pool. If not, @@ -217,6 +224,7 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ if( rc!=SQLITE_OK ) goto error_out; assert( pDb->pSchema && pDb->pSPool==0 ); } +#endif db->init.busy = 1; @@ -425,6 +433,12 @@ error_out: return rc; } + +#ifdef SQLITE_ENABLE_SHARED_SCHEMA +/* +** If this is a SHARED_SCHEMA connection and the DBFLAG_SchemaInUse flag +** is not currently set, set it and return non-zero. Otherwise, return 0. +*/ int sqlite3LockReusableSchema(sqlite3 *db){ if( IsSharedSchema(db) && (db->mDbFlags & DBFLAG_SchemaInuse)==0 ){ db->mDbFlags |= DBFLAG_SchemaInuse; @@ -432,12 +446,21 @@ int sqlite3LockReusableSchema(sqlite3 *db){ } return 0; } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ + +#ifdef SQLITE_ENABLE_SHARED_SCHEMA +/* +** This function is a no-op for non-SHARED_SCHEMA connections, or if bRelease +** is zero. Otherwise, clear the DBFLAG_SchemaInuse flag and release all +** schema references currently held. +*/ void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease){ if( bRelease ){ db->mDbFlags &= ~DBFLAG_SchemaInuse; sqlite3SchemaReleaseAll(db); } } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ /* ** Initialize all database files - the main database file, the file diff --git a/src/shell.c.in b/src/shell.c.in index c646d93013..9371dee338 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1071,14 +1071,14 @@ struct ShellState { /* Allowed values for ShellState.openMode */ -#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ -#define SHELL_OPEN_NORMAL 1 /* Normal database file */ -#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ -#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ -#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ -#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ -#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */ -#define SHELL_OPEN_REUSESCHEMA 7 /* Open for schema reuse */ +#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ +#define SHELL_OPEN_NORMAL 1 /* Normal database file */ +#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ +#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ +#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ +#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ +#define SHELL_OPEN_HEXDB 6 /* Use "dbtotxt" output as data source */ +#define SHELL_OPEN_SHAREDSCHEMA 7 /* Open for schema reuse */ /* Allowed values for ShellState.eTraceType */ @@ -4301,7 +4301,7 @@ static void open_db(ShellState *p, int openFlags){ sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READONLY, 0); break; } - case SHELL_OPEN_REUSESCHEMA: { + case SHELL_OPEN_SHAREDSCHEMA: { sqlite3_open_v2(p->zDbFilename, &p->db, SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_SHARED_SCHEMA,0); break; @@ -7245,8 +7245,8 @@ static int do_meta_command(char *zLine, ShellState *p){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ p->openMode = SHELL_OPEN_READONLY; - }else if( optionMatch(z, "reuseschema") ){ - p->openMode = SHELL_OPEN_REUSESCHEMA; + }else if( optionMatch(z, "sharedschema") ){ + p->openMode = SHELL_OPEN_SHAREDSCHEMA; }else if( z[0]=='-' ){ #ifdef SQLITE_ENABLE_DESERIALIZE }else if( optionMatch(z, "deserialize") ){ @@ -9435,8 +9435,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; - }else if( strcmp(z,"-reuseschema")==0 ){ - data.openMode = SHELL_OPEN_REUSESCHEMA; + }else if( strcmp(z,"-sharedschema")==0 ){ + data.openMode = SHELL_OPEN_SHAREDSCHEMA; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) }else if( strncmp(z, "-A",2)==0 ){ /* All remaining command-line arguments are passed to the ".archive" @@ -9540,8 +9540,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; - }else if( strcmp(z,"-reuseschema")==0 ){ - data.openMode = SHELL_OPEN_REUSESCHEMA; + }else if( strcmp(z,"-sharedschema")==0 ){ + data.openMode = SHELL_OPEN_SHAREDSCHEMA; }else if( strcmp(z,"-ascii")==0 ){ data.mode = MODE_Ascii; sqlite3_snprintf(sizeof(data.colSeparator), data.colSeparator, diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a583583efe..99f7425211 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1203,8 +1203,10 @@ struct Db { u8 safety_level; /* How aggressive at syncing data to disk */ u8 bSyncSet; /* True if "PRAGMA synchronous=N" has been run */ Schema *pSchema; /* Pointer to database schema (possibly shared) */ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA SchemaPool *pSPool; /* For REUSE_SCHEMA mode */ VTable *pVTable; /* List of all VTable objects (REUSE_SCHEMA mode only) */ +#endif }; /* @@ -1236,7 +1238,9 @@ struct Schema { u8 enc; /* Text encoding used by this database */ u16 schemaFlags; /* Flags associated with this schema */ int cache_size; /* Number of pages to use in the cache */ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA Schema *pNext; /* Next Schema object SchemaPool (REUSE_SCHEMA) */ +#endif }; /* @@ -1505,7 +1509,11 @@ struct sqlite3 { #endif }; -#define IsSharedSchema(db) (((db)->openFlags & SQLITE_OPEN_SHARED_SCHEMA)!=0) +#ifdef SQLITE_ENABLE_SHARED_SCHEMA +# define IsSharedSchema(db) (((db)->openFlags & SQLITE_OPEN_SHARED_SCHEMA)!=0) +#else +# define IsSharedSchema(db) 0 +#endif /* ** A macro to discover the encoding of a database. @@ -1959,7 +1967,9 @@ struct VTable { u8 bConstraint; /* True if constraints are supported */ int iSavepoint; /* Depth of the SAVEPOINT stack */ VTable *pNext; /* Next in linked list (see above) */ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA char *zName; /* Table name (REUSE_SCHEMA mode) */ +#endif }; /* @@ -3267,9 +3277,11 @@ struct Trigger { the is stored here */ Schema *pSchema; /* Schema containing the trigger */ Schema *pTabSchema; /* Schema containing the table */ - char *zTabSchema; /* Temp triggers in IsSharedSchema() dbs only */ TriggerStep *step_list; /* Link list of trigger program steps */ Trigger *pNext; /* Next trigger associated with the table */ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + char *zTabSchema; /* Temp triggers in IsSharedSchema() dbs only */ +#endif }; /* @@ -4322,15 +4334,29 @@ void sqlite3DefaultRowEst(Index*); void sqlite3RegisterLikeFunctions(sqlite3*, int); int sqlite3IsLikeFunction(sqlite3*,Expr*,int*,char*); void sqlite3SchemaClear(void *); +void sqlite3SchemaClearOrDisconnect(sqlite3*, int); + +#ifdef SQLITE_ENABLE_SHARED_SCHEMA int sqlite3SchemaConnect(sqlite3*, int, u64); int sqlite3SchemaDisconnect(sqlite3 *, int, int); -void sqlite3SchemaClearOrDisconnect(sqlite3*, int); Schema *sqlite3SchemaExtract(SchemaPool*); int sqlite3SchemaLoad(sqlite3*, int, int*, char**); void sqlite3SchemaReleaseAll(sqlite3*); void sqlite3SchemaRelease(sqlite3*, int); void sqlite3SchemaAdjustUsed(sqlite3*, int, int, int*); void sqlite3SchemaWritable(Parse*, int); +void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease); +int sqlite3LockReusableSchema(sqlite3 *db); +#else +# define sqlite3SchemaWritable(x,y) +# define sqlite3UnlockReusableSchema(x,y) +# define sqlite3LockReusableSchema(x) 0 +# define sqlite3SchemaDisconnect(x,y,z) SQLITE_OK +# define sqlite3SchemaLoad(w,x,y,z) SQLITE_OK +# define sqlite3SchemaRelease(y,z) +# define sqlite3SchemaConnect(x,y,z) SQLITE_OK +#endif + Schema *sqlite3SchemaGet(sqlite3 *, Btree *); int sqlite3SchemaToIndex(sqlite3 *db, Schema *); KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int,int); @@ -4339,8 +4365,6 @@ KeyInfo *sqlite3KeyInfoRef(KeyInfo*); KeyInfo *sqlite3KeyInfoOfIndex(Parse*, Index*); KeyInfo *sqlite3KeyInfoFromExprList(Parse*, ExprList*, int, int); -void sqlite3UnlockReusableSchema(sqlite3 *db, int bRelease); -int sqlite3LockReusableSchema(sqlite3 *db); #ifdef SQLITE_DEBUG int sqlite3KeyInfoIsWriteable(KeyInfo*); diff --git a/src/status.c b/src/status.c index 54218e3f4e..670248fbaa 100644 --- a/src/status.c +++ b/src/status.c @@ -281,15 +281,17 @@ int sqlite3_db_status( bReleaseSchema = sqlite3LockReusableSchema(db); db->pnBytesFreed = &nByte; for(i=0; inDb; i++){ + Schema *pSchema; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA int bUnload = 0; int nUsed = nByte; - Schema *pSchema; if( db->aDb[i].pSPool ){ char *zDummy = 0; rc = sqlite3SchemaLoad(db, i, &bUnload, &zDummy); sqlite3_free(zDummy); if( rc ) break; } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ pSchema = db->aDb[i].pSchema; if( ALWAYS(pSchema!=0) ){ HashElem *p; @@ -312,10 +314,12 @@ int sqlite3_db_status( sqlite3DeleteTable(db, (Table *)sqliteHashData(p)); } } +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( db->aDb[i].pSPool ){ if( bUnload ) sqlite3SchemaRelease(db, i); sqlite3SchemaAdjustUsed(db, i, nUsed, &nByte); } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ } sqlite3UnlockReusableSchema(db, bReleaseSchema); db->pnBytesFreed = 0; diff --git a/src/tclsqlite.c b/src/tclsqlite.c index 58992f88bd..3b0ce2d94f 100644 --- a/src/tclsqlite.c +++ b/src/tclsqlite.c @@ -3593,7 +3593,9 @@ static int sqliteCmdUsage( Tcl_WrongNumArgs(interp, 1, objv, "HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN?" " ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" +#ifdef SQLITE_ENABLE_SHARED_SCHEMA " ?-shared-schema BOOLEAN?" +#endif #if defined(SQLITE_HAS_CODEC) && !defined(SQLITE_OMIT_CODEC_FROM_TCL) " ?-key CODECKEY?" #endif @@ -3728,6 +3730,7 @@ static int SQLITE_TCLAPI DbMain( }else{ flags &= ~SQLITE_OPEN_URI; } +#ifdef SQLITE_ENABLE_SHARED_SCHEMA }else if( strcmp(zArg, "-shared-schema")==0 ){ int b; if( Tcl_GetBooleanFromObj(interp, objv[i], &b) ) return TCL_ERROR; @@ -3736,6 +3739,7 @@ static int SQLITE_TCLAPI DbMain( }else{ flags &= ~SQLITE_OPEN_SHARED_SCHEMA; } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ }else{ Tcl_AppendResult(interp, "unknown option: ", zArg, (char*)0); return TCL_ERROR; diff --git a/src/test_config.c b/src/test_config.c index 05002349bd..1b372b9fb0 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -774,6 +774,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "1", TCL_GLOBAL_ONLY); #endif +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "sharedschema", "0", TCL_GLOBAL_ONLY); +#endif + #define LINKVAR(x) { \ static const int cv_ ## x = SQLITE_ ## x; \ Tcl_LinkVar(interp, "SQLITE_" #x, (char *)&(cv_ ## x), \ diff --git a/src/test_schemapool.c b/src/test_schemapool.c index 6d7173a491..4f90916267 100644 --- a/src/test_schemapool.c +++ b/src/test_schemapool.c @@ -19,9 +19,12 @@ */ #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) -#include "sqliteInt.h" #include +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + +#include "sqliteInt.h" + /* The code in this file defines a sqlite3 virtual-table module with ** the following schema. */ @@ -253,12 +256,14 @@ static int SQLITE_TCLAPI register_schemapool_module( return TCL_OK; } -#endif +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ +#endif /* !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_TEST) */ /* ** Register commands with the TCL interpreter. */ int Sqlitetestschemapool_Init(Tcl_Interp *interp){ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA static struct { char *zName; Tcl_ObjCmdProc *xProc; @@ -271,6 +276,7 @@ int Sqlitetestschemapool_Init(Tcl_Interp *interp){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, aObjCmd[i].clientData, 0); } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ return TCL_OK; } diff --git a/src/trigger.c b/src/trigger.c index f692908798..36ab0b828d 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -57,18 +57,24 @@ Trigger *sqlite3TriggerList(Parse *pParse, Table *pTab){ if( pTmpSchema!=pTab->pSchema ){ sqlite3 *db = pParse->db; HashElem *p; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA char *zSchema = 0; if( IsSharedSchema(db) ){ zSchema = db->aDb[sqlite3SchemaToIndex(db, pTab->pSchema)].zDbSName; } +#endif assert( sqlite3SchemaMutexHeld(db, 0, pTmpSchema) ); for(p=sqliteHashFirst(&pTmpSchema->trigHash); p; p=sqliteHashNext(p)){ Trigger *pTrig = (Trigger *)sqliteHashData(p); + +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( (zSchema==0 && pTrig->pTabSchema==pTab->pSchema) - || (zSchema!=0 && 0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)) - ){ - if( 0==sqlite3StrICmp(pTrig->table, pTab->zName) - ){ + || (zSchema!=0 && 0==sqlite3StrICmp(pTrig->zTabSchema, zSchema)) ) +#else + if( pTrig->pTabSchema==pTab->pSchema ) +#endif + { + if( 0==sqlite3StrICmp(pTrig->table, pTab->zName) ){ pTrig->pTabSchema = pTab->pSchema; pTrig->pNext = (pList ? pList : pTab->pTrigger); pList = pTrig; @@ -253,10 +259,12 @@ void sqlite3BeginTrigger( pTrigger->zName = zName; zName = 0; pTrigger->table = sqlite3DbStrDup(db, pTableName->a[0].zName); +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb==1 ){ int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTrigger->zTabSchema = sqlite3DbStrDup(db, db->aDb[iTabDb].zDbSName); } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ pTrigger->pSchema = db->aDb[iDb].pSchema; pTrigger->pTabSchema = pTab->pSchema; pTrigger->op = (u8)op; @@ -554,7 +562,9 @@ void sqlite3DeleteTrigger(sqlite3 *db, Trigger *pTrigger){ sqlite3DeleteTriggerStep(db, pTrigger->step_list); sqlite3DbFree(db, pTrigger->zName); sqlite3DbFree(db, pTrigger->table); +#ifdef SQLITE_ENABLE_SHARED_SCHEMA sqlite3DbFree(db, pTrigger->zTabSchema); +#endif sqlite3ExprDelete(db, pTrigger->pWhen); sqlite3IdListDelete(db, pTrigger->pColumns); sqlite3DbFree(db, pTrigger); diff --git a/src/vtab.c b/src/vtab.c index e22e9c9e22..8cfa29aa62 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -144,6 +144,7 @@ void sqlite3VtabLock(VTable *pVTab){ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ VTable *pVtab; assert( IsVirtual(pTab) ); +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); if( iDb!=1 ){ @@ -153,6 +154,7 @@ VTable *sqlite3GetVTable(sqlite3 *db, Table *pTab){ return pVtab; } } +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ for(pVtab=pTab->pVTable; pVtab && pVtab->db!=db; pVtab=pVtab->pNext); return pVtab; } @@ -534,7 +536,10 @@ static int vtabCallConstructor( return SQLITE_NOMEM_BKPT; } - nByte = sizeof(VTable) + sqlite3Strlen30(pTab->zName) + 1; + nByte = sizeof(VTable); +#ifdef SQLITE_ENABLE_SHARED_SCHEMA + nByte += sqlite3Strlen30(pTab->zName) + 1; +#endif pVTable = (VTable*)sqlite3MallocZero(nByte); if( !pVTable ){ sqlite3OomFault(db); @@ -543,8 +548,10 @@ static int vtabCallConstructor( } pVTable->db = db; pVTable->pMod = pMod; +#ifdef SQLITE_ENABLE_SHARED_SCHEMA pVTable->zName = (char*)&pVTable[1]; memcpy(pVTable->zName, pTab->zName, nByte-sizeof(VTable)); +#endif iDb = sqlite3SchemaToIndex(db, pTab->pSchema); pTab->azModuleArg[1] = db->aDb[iDb].zDbSName; @@ -591,10 +598,13 @@ static int vtabCallConstructor( ** Then loop through the columns of the table to see if any of them ** contain the token "hidden". If so, set the Column COLFLAG_HIDDEN flag ** and remove the token from the type string. */ +#ifdef SQLITE_ENABLE_SHARED_SCHEMA if( IsSharedSchema(db) && iDb!=1 ){ pVTable->pNext = db->aDb[iDb].pVTable; db->aDb[iDb].pVTable = pVTable; - }else{ + }else +#endif /* ifdef SQLITE_ENABLE_SHARED_SCHEMA */ + { pVTable->pNext = pTab->pVTable; pTab->pVTable = pVTable; } diff --git a/test/reuse1.test b/test/reuse1.test index c489cd337e..5fcd3a47a8 100644 --- a/test/reuse1.test +++ b/test/reuse1.test @@ -16,7 +16,10 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse1 -if 1 { +ifcapable !sharedschema { + finish_test + return +} forcedelete test.db2 sqlite3 db2 test.db2 @@ -124,8 +127,6 @@ breakpoint } {1 aux1 2 aux2 3 aux3} } -} - #------------------------------------------------------------------------- # reset_db diff --git a/test/reuse2.test b/test/reuse2.test index 50e03c1ac7..26ffc2da76 100644 --- a/test/reuse2.test +++ b/test/reuse2.test @@ -16,6 +16,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse2 +ifcapable !sharedschema { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); diff --git a/test/reuse3.test b/test/reuse3.test index f155bf7cbb..377302ef20 100644 --- a/test/reuse3.test +++ b/test/reuse3.test @@ -16,6 +16,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse3 +ifcapable !sharedschema { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX i1 ON t1(z); diff --git a/test/reuse4.test b/test/reuse4.test index 0f32d56592..3635bc61fd 100644 --- a/test/reuse4.test +++ b/test/reuse4.test @@ -15,6 +15,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reuse4 +ifcapable !sharedschema { + finish_test + return +} + foreach {tn sharedschema} { 1 0 2 1 diff --git a/test/reuse5.test b/test/reuse5.test index d5368f1fec..e6cfd1bb93 100644 --- a/test/reuse5.test +++ b/test/reuse5.test @@ -16,6 +16,11 @@ source $testdir/tester.tcl set testprefix reuse5 set CLI [test_find_cli] +ifcapable !sharedschema { + finish_test + return +} + do_execsql_test 1.0 { CREATE TABLE t1(x, y); CREATE TABLE t2(a, b, c); diff --git a/test/reusefault.test b/test/reusefault.test index fabc5aedc4..66699f8f6b 100644 --- a/test/reusefault.test +++ b/test/reusefault.test @@ -15,6 +15,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix reusefault +ifcapable !sharedschema { + finish_test + return +} + do_execsql_test 1.0 { PRAGMA cache_size = 10; CREATE TABLE t1(a UNIQUE, b UNIQUE); diff --git a/test/tclsqlite.test b/test/tclsqlite.test index f5b9866171..705e6b7ca1 100644 --- a/test/tclsqlite.test +++ b/test/tclsqlite.test @@ -25,7 +25,10 @@ set testprefix tcl # Check the error messages generated by tclsqlite # -set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN? ?-shared-schema BOOLEAN?" +set r "sqlite_orig HANDLE ?FILENAME? ?-vfs VFSNAME? ?-readonly BOOLEAN? ?-create BOOLEAN? ?-nomutex BOOLEAN? ?-fullmutex BOOLEAN? ?-uri BOOLEAN?" +ifcapable sharedschema { + append r " ?-shared-schema BOOLEAN?" +} if {[sqlite3 -has-codec]} { append r " ?-key CODECKEY?" }