diff --git a/documentation/RELEASE_NOTES.md b/documentation/RELEASE_NOTES.md index 343de180f4..4625ed9a1b 100644 --- a/documentation/RELEASE_NOTES.md +++ b/documentation/RELEASE_NOTES.md @@ -22,6 +22,13 @@ should also be read to understand what has changed since earlier releases: ## Changes made on the 7.0 branch since 7.0.8.1 +### Allow to load the same alias multiple times + +Aliases can now be defined multiple times as long as they still refer to the +same record, unless the shell variable dbRecordsOnceOnly is set. +This allows to load database files multiple times, even if they contain +alias definitions. + ### Allow users to delete previously created records from the database From this release, record instances and aliases that have already been loaded diff --git a/modules/database/src/ioc/dbStatic/dbLexRoutines.c b/modules/database/src/ioc/dbStatic/dbLexRoutines.c index 1b60095fb0..301bb5b983 100644 --- a/modules/database/src/ioc/dbStatic/dbLexRoutines.c +++ b/modules/database/src/ioc/dbStatic/dbLexRoutines.c @@ -1263,24 +1263,50 @@ static void dbRecordInfo(char *name, char *value) } } +static long createAlias(DBENTRY *pdbentry, const char *alias) +{ + DBENTRY tempEntry; + long status; + dbRecordNode *precnode = pdbentry->precnode; + + if (precnode->aliasedRecnode) precnode = precnode->aliasedRecnode; + dbInitEntry(pdbentry->pdbbase, &tempEntry); + status = dbFindRecord(&tempEntry, alias); + if (status == 0) { + if (tempEntry.precnode->aliasedRecnode != precnode) { + if (tempEntry.precnode->aliasedRecnode) + fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by an alias for \"%s\"\n", + alias, dbGetRecordName(pdbentry), + tempEntry.precnode->aliasedRecnode->recordname); + else + fprintf(stderr, ERL_ERROR ": Alias \"%s\" for \"%s\": name already used by a record\n", + alias, dbGetRecordName(pdbentry)); + status = S_dbLib_recExists; + } else if (dbRecordsOnceOnly) { + fprintf(stderr, ERL_ERROR ": Alias \"%s\" already defined and dbRecordsOnceOnly set.\n", + alias); + status = S_dbLib_recExists; + } + } else { + status = dbCreateAlias(pdbentry, alias); + } + dbFinishEntry(&tempEntry); + return status; +} + static void dbRecordAlias(char *name) { DBENTRY *pdbentry; tempListNode *ptempListNode; - long status; - if(dbRecordNameValidate(name)) return; if (duplicate) return; ptempListNode = (tempListNode *)ellFirst(&tempList); pdbentry = ptempListNode->item; - status = dbCreateAlias(pdbentry, name); - if (status) { - fprintf(stderr, "Can't create alias \"%s\" for \"%s\"\n", - name, dbGetRecordName(pdbentry)); + + if (createAlias(pdbentry, name) != 0) { yyerror(NULL); - return; } } @@ -1298,9 +1324,7 @@ static void dbAlias(char *name, char *alias) alias, name); yyerror(NULL); } - else if (dbCreateAlias(pdbEntry, alias)) { - fprintf(stderr, "Can't create alias \"%s\" referring to \"%s\"\n", - alias, name); + else if (createAlias(pdbEntry, alias) != 0) { yyerror(NULL); } dbFinishEntry(pdbEntry); diff --git a/modules/database/test/ioc/db/Makefile b/modules/database/test/ioc/db/Makefile index f66d3db320..4395c291e1 100644 --- a/modules/database/test/ioc/db/Makefile +++ b/modules/database/test/ioc/db/Makefile @@ -36,6 +36,7 @@ dbTestIoc_DBD += xLink.dbd dbTestIoc_DBD += devx.dbd dbTestIoc_DBD += jlinkz.dbd dbTestIoc_DBD += dbLinkdset.dbd +dbTestIoc_DBD += dbCore.dbd TESTFILES += $(COMMON_DIR)/dbTestIoc.dbd ../xRecord.db testHarness_SRCS += dbTestIoc_registerRecordDeviceDriver.cpp @@ -183,6 +184,11 @@ testHarness_SRCS += dbStaticTest.c TESTFILES += ../dbStaticTest.db TESTFILES += ../dbStaticTestAlias1.db TESTFILES += ../dbStaticTestAlias2.db +TESTFILES += ../dbStaticTestAliasAgain1.db +TESTFILES += ../dbStaticTestAliasAgain2.db +TESTFILES += ../dbStaticTestAliasAgain3.db +TESTFILES += ../dbStaticTestAliasAgainError1.db +TESTFILES += ../dbStaticTestAliasAgainError2.db TESTFILES += ../dbStaticTestRemove.db TESTS += dbStaticTest diff --git a/modules/database/test/ioc/db/dbStaticTest.c b/modules/database/test/ioc/db/dbStaticTest.c index 0ead118036..0df14337e8 100644 --- a/modules/database/test/ioc/db/dbStaticTest.c +++ b/modules/database/test/ioc/db/dbStaticTest.c @@ -14,6 +14,7 @@ #include #include #include +#include static void testEntryRemoved(const char *pv) @@ -321,16 +322,19 @@ static void testDbVerify(const char *record) dbFinishEntry(&entry); } -static void testWrongAliasRecord(const char *filename) +static void testReadDatabase(const char *filename, int expectToFail) { FILE *fp = NULL; + long status; dbPath(pdbbase,"." OSI_PATH_LIST_SEPARATOR ".."); dbOpenFile(pdbbase, filename, &fp); if(!fp) { - testAbort("Unable to read %s", filename); + testAbort("Unable to open %s", filename); } - testOk(dbReadDatabaseFP(&pdbbase, fp, NULL, NULL) != 0, - "Wrong alias record in %s is expected to fail", filename); + status = dbReadDatabaseFP(&pdbbase, fp, NULL, NULL); + testOk(!status == !expectToFail, + "Reading %s%s", filename, + expectToFail ? " is expected to fail" : ""); } void dbTestIoc_registerRecordDeviceDriver(struct dbBase *); @@ -340,8 +344,9 @@ MAIN(dbStaticTest) const char *ldir; char *ldirDup; FILE *fp = NULL; + const iocshVarDef *pdbRecordsOnceOnlyDef; - testPlan(340); + testPlan(350); testdbPrepare(); testdbReadDatabase("dbTestIoc.dbd", NULL, NULL); @@ -370,8 +375,24 @@ MAIN(dbStaticTest) } free(ldirDup); - testWrongAliasRecord("dbStaticTestAlias1.db"); - testWrongAliasRecord("dbStaticTestAlias2.db"); + testReadDatabase("dbStaticTestAlias1.db", 1); + testReadDatabase("dbStaticTestAlias2.db", 1); + + /* Test re-defining aliases */ + testReadDatabase("dbStaticTestAliasAgain1.db", 0); + testReadDatabase("dbStaticTestAliasAgain1.db", 0); + testReadDatabase("dbStaticTestAliasAgain2.db", 0); + testReadDatabase("dbStaticTestAliasAgain2.db", 0); + testReadDatabase("dbStaticTestAliasAgain3.db", 0); + testReadDatabase("dbStaticTestAliasAgain3.db", 0); + testReadDatabase("dbStaticTestAliasAgainError1.db", 1); + testReadDatabase("dbStaticTestAliasAgainError2.db", 1); + pdbRecordsOnceOnlyDef = iocshFindVariable("dbRecordsOnceOnly"); + if (!pdbRecordsOnceOnlyDef || pdbRecordsOnceOnlyDef->type != iocshArgInt) { + testAbort("Cannot find dbRecordsOnceOnly int variable"); + *(int*)pdbRecordsOnceOnlyDef->pval = 1; + testReadDatabase("dbStaticTestAliasAgain2.db", 1); + testReadDatabase("dbStaticTestAliasAgain3.db", 1); testEntry("testrec.VAL"); testEntry("testalias.VAL"); diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db new file mode 100644 index 0000000000..bc7cc1b654 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain1.db @@ -0,0 +1,4 @@ +# Test re-load alias in record +record(x, "testrecAgain") { + alias("testaliasAgain1") +} diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db new file mode 100644 index 0000000000..b6709f24f6 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain2.db @@ -0,0 +1,2 @@ +# Test re-load alias for record +alias("testrecAgain", "testaliasAgain2") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db b/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db new file mode 100644 index 0000000000..8dcbc40573 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgain3.db @@ -0,0 +1,2 @@ +# Test re-load alias for alias +alias("testaliasAgain2", "testaliasAgain3") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db b/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db new file mode 100644 index 0000000000..150c09e203 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgainError1.db @@ -0,0 +1,2 @@ +# ERROR: alias using name of exising alias for different record +alias("testrec", "testaliasAgain1") diff --git a/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db b/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db new file mode 100644 index 0000000000..0fb8447773 --- /dev/null +++ b/modules/database/test/ioc/db/dbStaticTestAliasAgainError2.db @@ -0,0 +1,2 @@ +# ERROR: alias using name of exising record fails +alias("testrecAgain", "testrec")