diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..1a63292b080f182821935cb5b20b7500bfcf8f63
--- /dev/null
+++ b/.docker/docker-compose.yml
@@ -0,0 +1,23 @@
+version: '3.6'
+services:
+  sqldb:
+    image: mariadb:10.5
+    volumes:
+      - type: volume
+        source: "caosdb-sqldata"
+        target: /var/lib/mysql
+    environment:
+      MYSQL_ROOT_PASSWORD: caosdb1234
+    networks:
+      # available on port 3306, host name 'sqldb'
+      - caosnet
+    ports:
+      - 3306:3306
+
+
+# A well-defined network for caosdb
+volumes:
+    caosdb-sqldata:
+networks:
+  caosnet:
+    driver: bridge
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 01d806ef3b90b375f11903630ccc32e3a61c02eb..3878ddb5d95b9319fc6c44481efe9a63d284da41 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -62,21 +62,6 @@ unittests-mariadb:
   script:
     - make pipeline-test SQL_HOST=mariadb
 
-# Run the unit tests with MySQL 8
-unittests-mysql-8:
-  tags: [ docker ]
-  stage: test
-  # Should not stop the pipeline from continuing.
-  allow_failure: true
-  services:
-    - name: mysql:8.0
-      command: ["--default-authentication-plugin=mysql_native_password"]
-
-  script:
-    - sed "s/NO_AUTO_CREATE_USER,//" -i tests/example.dump.sql
-    - rm tests/test_autotap.sql
-    - make pipeline-test SQL_HOST=mysql
-
 # Run the unit tests with MySQL 5
 unittests-mysql-5:
   tags: [ docker ]
@@ -84,7 +69,7 @@ unittests-mysql-5:
   # Should not stop the pipeline from continuing.
   allow_failure: true
   services:
-    - name: mysql:5.7
+    - name: mysql:5.7.36
       command: ["--default-authentication-plugin=mysql_native_password"]
 
   script:
diff --git a/.gitlab/issue_templates/Default.md b/.gitlab/issue_templates/Default.md
new file mode 100644
index 0000000000000000000000000000000000000000..aa1a65aca363b87aff50280e1a86824009d2098b
--- /dev/null
+++ b/.gitlab/issue_templates/Default.md
@@ -0,0 +1,28 @@
+## Summary
+
+*Please give a short summary of what the issue is.*
+
+## Expected Behavior
+
+*What did you expect how the software should behave?*
+
+## Actual Behavior
+
+*What did the software actually do?*
+
+## Steps to Reproduce the Problem
+
+*Please describe, step by step, how others can reproduce the problem.  Please try these steps for yourself on a clean system.*
+
+1.
+2.
+3.
+
+## Specifications
+
+- Version: *Which version of this software?*
+- Platform: *Which operating system, which other relevant software versions?*
+
+## Possible fixes
+
+*Do you have ideas how the issue can be resolved?*
diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md
new file mode 100644
index 0000000000000000000000000000000000000000..3629e0ca3695000863d8c254516f64bf59a7bf60
--- /dev/null
+++ b/.gitlab/merge_request_templates/Default.md
@@ -0,0 +1,56 @@
+# Summary
+
+*Insert a meaningful description for this merge request here:  What is the new/changed behavior?
+Which bug has been fixed? Are there related issues?*
+
+
+# Focus
+
+*Point the reviewer to the core of the code change. Where should they start reading? What should
+they focus on (e.g. security, performance, maintainability, user-friendliness, compliance with the
+specs, finding more corner cases, concrete questions)?*
+
+
+# Test Environment
+
+*How to set up a test environment for manual testing?*
+
+
+# Check List for the Author
+
+Please, prepare your MR for a review. Be sure to write a summary and a focus and create gitlab
+comments for the reviewer. They should guide the reviewer through the changes, explain your changes
+and also point out open questions. For further good practices have a look at [our review
+guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md)
+
+- [ ] All automated tests pass
+- [ ] Reference related issues
+- [ ] Up-to-date CHANGELOG.md (or not necessary)
+- [ ] Up-to-date JSON schema (or not necessary)
+- [ ] Appropriate user and developer documentation (or not necessary)
+  - Update / write published documentation (`make doc`).
+  - How do I use the software?  Assume "stupid" users.
+  - How do I develop or debug the software?  Assume novice developers.
+- [ ] Annotations in code (Gitlab comments)
+  - Intent of new code
+  - Problems with old code
+  - Why this implementation?
+
+
+# Check List for the Reviewer
+
+- [ ] I understand the intent of this MR
+- [ ] All automated tests pass
+- [ ] Up-to-date CHANGELOG.md (or not necessary)
+- [ ] Appropriate user and developer documentation (or not necessary), also in published
+      documentation.
+- [ ] The test environment setup works and the intended behavior is reproducible in the test
+  environment
+- [ ] In-code documentation and comments are up-to-date.
+- [ ] Check: Are there specifications? Are they satisfied?
+
+For further good practices have a look at [our review guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md).
+
+
+/assign me
+/target_branch dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2e41b4611e97316a25933db6ecaf0c51b79f00be..7d27a320296ed0c308a20a3b12fefda78f6d0e42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -19,16 +19,124 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 
 ### Security ###
 
-## [5.0.0] - 2021-10-28 ##
+## [7.0.2] - 2023-12-12 ##
+(Timm Fitschen)
+
+### Fixed ###
+
+* make install: Could not connect to MariaDB in local docker
+  container
+  [linkahead-mariadbbackend](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues/33)
+* Wrong ids in data_type table due to a bug in the `linkahead-server < v0.11.0`
+  which has been fixed but left broken data. This resulted in server errors
+  [linkahead-mariadbbackend#34](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues/34)
+
+## [7.0.1] - 2023-11-01
+(Timm Fitschen)
 
 ### Added ###
 
-* #33 CI pipeline for MySQL (was only MariaDB before).
+* Sanity checks during `make install` and `make upgrade`.
+
+## [7.0.0] - 2023-10-25 ##
+(Timm Fitschen)
 
 ### Changed ###
 
+* Change signature of procedure `insertEntityDataType`: expect the data type ID
+  instead of the name.
+* Change result set of procedure `retrieveEntity`: Rename column `Datatype` to
+  `DatatypeName` and add column  `DatatypeID`.
+* Change result set of procedure `retrieveOverrides`: Rename column
+  `type_override` to `type_name_override` and add `type_id_override`.
+* Change signature of procedure `updateEntity`: expect the data type ID instead
+  to the name.
+* Internal ids, when returned by `retrieveEntityProperties`,
+  `registerReplacementIds`, or `retrieveOverrides`, are prefixed by a special
+  character which serves as a ephemeral marker. Currently this is `$` but this
+  may change in the future if there is a more suitable candidate.
+
 ### Deprecated ###
 
+* MySQL Support. Last version which is known to work well with LinkAhead is MySQL 5.7.36
+
+### Fixed ###
+
+* Unknown Server Error when inserting an Entity.
+  [linkahead-mariadbbackend#48](https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/48).
+* Fix broken `initEntity` procedure (and change the first parameters type from
+  INT UNSIGNED to VARCHAR(255) which is non-breaking).
+
+## [6.0.1 2023-10-18] ##
+
+### Fixed ###
+* Old passwords table is removed from dumps where it still exists.
+
+## [6.0.0 2023-10-17] ##
+
+This is a major update. Switching from integer ids for internal and external use to string ids for the external use while keeping the old integer ids for internal use.
+
+### Added ###
+
+* Table `entity_ids`
+* Procedure `getIdByName`
+* Procedure `insertEntityDataType` and `insertEntityCollection`
+* Procedure `setFileProperties`.
+
+### Changed ###
+
+* Rename PROCEDURE `registerSubdomain` to `registerReplacementIds`.
+* Change column `entities.role` datatype: replace 'DOMAIN' enum value with `_REPLACEMENT`.
+* Change column `transactions_log.entity_id` to VARCHAR(255)
+* Change column `user_info.entity` to VARCHAR(255)
+* Change signature of procedure `applyIDFilter` - `EntityID VARCHAR(255)`
+* Change signature of procedure `initBackreference` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)`
+* Change signature of procedure `initPOVPropertiesTable` - `PropertyID VARCHAR(255)`
+* Change signature of procedure `initPOVRefidsTable` - `PropertyID VARCHAR(255)`
+* Change signature of procedure `initSubEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `deleteEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `deleteEntityProperties` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_primary_parent_version` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_version_timestamp` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_head_version` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_head_relative` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_version_history` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveQueryTemplateDef` - `EntityID VARCHAR(255)`
+* Change signature of procedure `getDependentEntities` - `EntityID VARCHAR(255)`
+* Change signature of procedure `insertEntity` - Add parameter `EntityID VARCHAR(255)`
+* Change signature of procedure `insertEntityProperty` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)`, `DomainID VARCHAR(255)`, `DatatypeOverride VARCHAR(255)`
+* Change signature of procedure `insertIsa` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`.
+* Change signature of procedure `isSubtype` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`.
+* Change signature of procedure `retrieveEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveOverrides` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)`
+* Change signature of procedure `retrieveEntityParents` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveEntityProperties` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)`
+* Change signature of procedure `updateEntity` - `EntityID VARCHAR(255)`
+
+### Removed ###
+
+* Deactivate procedure `delete_all_entity_versions`. This might be used in the
+  future, that is why we keep the code in a comment.
+* Drop procedure `retrieveSubEntity`
+* Drop procedure `retrieveDatatype`
+* Drop procedure `retrieveGroup`
+* Drop procedure `getInfo`
+* Drop procedure `getRole`
+* Drop procedure `setPassword`
+* Drop procedure `initAutoIncrement`
+* Delete special entity 50 (SQLite Datatype)
+* Delete special entity 99 (Work-around for the auto-increment)
+
+### Fixed ###
+
+* Change signature of procedure `getFileIdByPath` - `FilePath TEXT` - this length is needed for the path column of `file_entities`.
+
+## [5.0.0] - 2021-10-28 ##
+
+### Added ###
+
+* #33 CI pipeline for MySQL (was only MariaDB before).
+
 ### Removed ###
 
 * `getRules` procedure and the `rules` table. The jobs rules are being
@@ -41,8 +149,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * #32 Removed unused `groups` table from installation routines which prevented
   the installation with MySQL 8.
 
-### Security ###
-
 ## [4.1.0] - 2021-06-11 ##
 
 ### Added ###
@@ -80,8 +186,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
     * `createTmpTable`
 * Added a `direct` column to `archive_isa` table
 
-### Deprecated ###
-
 ### Removed ###
 
 * unused procedures:
@@ -107,8 +211,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   version resultet in an error. See corresponding test in `caosdb-pyinttest`
   `tests/test_versioning.py::test_datatype_without_name`
 
-### Security ###
-
 ## [3.0.0] - 2020-09-01 ##
 
 ### Added ###
@@ -162,5 +264,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * Bug in `updateEntity.sql` (when updating the primary name without a prior call
   to `deleteEntityProperties`). Same thing for `deleteEntity`.
 * #21 Bug which prevented deletion of deeply inheriting entities, if versioning was enabled.
-
-### Security ###
diff --git a/Makefile b/Makefile
index 544c0b6abc7627bb7a78f5312ee05d70b2d4d5ac..7c1ec3effb5cea166649aedcba188d6974d2cb6f 100644
--- a/Makefile
+++ b/Makefile
@@ -34,6 +34,7 @@ test-connection:
 .PHONY: upgrade
 upgrade:
 	@cd patches; ./applyPatches.sh --env=../.config
+	@./utils/make_db sanity_check
 
 .PHONY: install
 install: _install _grant upgrade
@@ -85,7 +86,9 @@ pipeline-test:
 	echo 'DATABASE_USER_HOST_LIST="%,"' >> .config
 	echo "MYSQL_USER_PASSWORD=$(MYSQL_ROOT_PASSWORD)" >> .config
 	echo "MYSQL_HOST=$(SQL_HOST)" >> .config
+	echo "MYSQL_OPTS=--protocol=TCP" >> .config
 	sleep 10
 	make install
 	./utils/make_db restore_db tests/example.dump.sql
+	make upgrade
 	./tests/test_utils.sh
diff --git a/README.md b/README.md
index c68256b11d292f26f27d410e1bebbee82e625726..7094464dae407a9eff280f2312a7b582f5f29a2b 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,8 @@
 
 ## Welcome
 
-This is the **CaosDB MySQL Backend** repository and a part of the
-CaosDB project.
+This is the **LinkAhead MySQL Backend** repository and a part of the
+LinkAhead project.
 
 ## Setup
 
@@ -18,24 +18,26 @@ Please refer to the [official documentation](https://docs.indiscale.com/caosdb-m
 
 ## Contributing
 
-Thank you very much to all contributers—[past, present](https://gitlab.com/caosdb/caosdb/-/blob/dev/HUMANS.md), and prospective ones.
+Thank you very much to all contributers—[past,
+present](https://gitlab.com/linkahead/linkahead/-/blob/main/HUMANS.md), and prospective
+ones.
 
 ### Code of Conduct
 
-By participating, you are expected to uphold our [Code of Conduct](https://gitlab.com/caosdb/caosdb/-/blob/dev/CODE_OF_CONDUCT.md).
+By participating, you are expected to uphold our [Code of
+Conduct](https://gitlab.com/linkahead/linkahead/-/blob/main/CODE_OF_CONDUCT.md).
 
 ### How to Contribute
 
-* You found a bug, have a question, or want to request a feature? Please
-[create an issue](https://gitlab.com/caosdb/caosdb-mysqlbackend/-/issues).
-* You want to contribute code? Please fork the repository and create a merge
-request in GitLab and choose this repository as target. Make sure to select
-"Allow commits from members who can merge the target branch" under Contribution
-when creating the merge request. This allows our team to work with you on your request.
-- If you have a suggestion for the [documentation](https://docs.indiscale.com/caosdb-mysqlbackend/),
-the preferred way is also a merge request as describe above (the documentation resides in `src/doc`).
-However, you can also create an issue for it.
-- You can also contact us at **info (AT) caosdb.org**.
+* You found a bug, have a question, or want to request a feature? Please 
+[create an issue](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues).
+* You want to contribute code?
+    * **Forking:** Please fork the repository and create a merge request in GitLab and choose this repository as
+      target. Make sure to select "Allow commits from members who can merge the target branch" under
+      Contribution when creating the merge request. This allows our team to work with you on your
+      request.
+* You can also  join the LinkAhead community on
+  [#linkahead:matrix.org](https://matrix.to/#/!unwwlTfOznjEnMMXxf:matrix.org).
 
 ## License
 
diff --git a/README_SETUP.md b/README_SETUP.md
index 1b88d56636ccbbbfa3ed616ff323d8e9fdf4835c..581cc31411a6b6e510f10414c21ce6304697cb85 100644
--- a/README_SETUP.md
+++ b/README_SETUP.md
@@ -1,9 +1,9 @@
 # Setup of the CaosDB SQL back end
 
 ## Dependencies
-* `MariaDB Client 10.1`, `MySQL Client 5.5`, or later versions.  In the case of
-  MySQL, version 5.6 is recommended.
-- make
+
+* `MariaDB Client 10.1` or later, `MySQL Client >=5.5, <=5.7.36`.
+* make
 
 ## Create the configuration
 * Create an empty `.config` file. For the default values and the meaning of
@@ -87,6 +87,19 @@ with the then current version of the stored entities.
     * Alternatively, to run the tests in a containerized MariaDB instance, run `make test-docker`,
       followed by `make test-docker-stop`.
 
+
+### Running in a Docker Container
+
+You can use `.docker/docker-compose.yml` to start a docker container
+(`docker-compose -f .docker/docker-compose.yml up -d`) that runs mariadb. You
+need appropriate settings in `.config`:
+* `MYSQL_OPTS="--protocol=TCP"` and
+* `DATABASE_USER_HOST_LIST=%,`
+After the first start, you need to install the database: `make install`.
+Then, you can connect to it with `mariadb --protocol=TCP -u caosdb -prandom1234
+caosdb`.
+
+
 ### Troubleshooting
 
 #### MySQL has failing tests
diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md
index a5eeca10024f9d69b80192de3f8431a55b7f1a81..3497909d850c646a220c36188b3760df5d659f3b 100644
--- a/RELEASE_GUIDELINES.md
+++ b/RELEASE_GUIDELINES.md
@@ -2,7 +2,7 @@
 
 This document specifies release guidelines in addition to the general release
 guidelines of the CaosDB Project
-([RELEASE_GUIDELINES.md](https://gitlab.com/caosdb/caosdb/blob/dev/RELEASE_GUIDELINES.md))
+([RELEASE_GUIDELINES.md](https://gitlab.com/caosdb/caosdb-meta/-/blob/dev/RELEASE_GUIDELINES.md))
 
 ## General Prerequisites
 
@@ -19,10 +19,20 @@ guidelines of the CaosDB Project
 
 2. Check all general prerequisites.
 
-4. Merge the release branch into the main branch.
+3. Assure that the latest patch actually updates the CaosDBVersion() procedure
+   and that the version matches the version you are about to release.
 
-5. Tag the latest commit of the main branch with `v<VERSION>`.
+4. Update version in `doc/conf.py`.
 
-6. Delete the release branch.
+5. Merge the release branch into the main branch.
 
-7. Merge the main branch back into the dev branch.
+6. Wait for the main branch pipeline to pass.
+
+7. Tag the latest commit of the main branch with `v<VERSION>`.
+
+8. Delete the release branch.
+
+9. Merge the main branch back into the dev branch and add the `[UNRELEASED]`
+   section to the CHANGELOG.
+
+10. Create a release at the [gitlab repo](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/releases)
diff --git a/config.defaults b/config.defaults
index f12278dcf0f5ce772c4cb77e54b149d3f6880921..1860377976c3bf0d9f389570dc0e981f47aa1609 100644
--- a/config.defaults
+++ b/config.defaults
@@ -40,6 +40,12 @@ MYSQL_PORT=3306
 # which will then be used by the CaosDB Server.
 MYSQL_USER=root
 MYSQL_USER_PASSWORD=caosdb1234
+# Additional options for the connection
+# e.g. if you want to connect a dockerized MariaDB at localhost you need to put
+# "--protocol=TCP" here because when host=localhost the connection defaults to
+# SOCKET.
+# MYSQL_OPTS='--protocol=TCP'
+MYSQL_OPTS=
 
 # # DATABASE
 # The name of the SQL database.
diff --git a/doc/conf.py b/doc/conf.py
index c649f342a691a8a52fdf45654925da5b1e378533..5fdc05d730471fc610d2b3c5971ced9cfc14f192 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -26,9 +26,9 @@ copyright = '2021, IndiScale GmbH'
 author = 'Daniel Hornung'
 
 # The short X.Y version
-version = '5.1'
+version = '7.0.2'
 # The full version, including alpha/beta/rc tags
-release = '5.1.0-SNAPSHOT'
+release = '7.0.2'
 
 
 # -- General configuration ---------------------------------------------------
@@ -46,7 +46,7 @@ extensions = [
     'sphinx.ext.todo',
     "sphinx.ext.autodoc",
     "recommonmark",            # For markdown files.
-     # 'autoapi.extension',
+    # 'autoapi.extension',
     # 'sphinx.ext.intersphinx',
     # 'sphinx.ext.napoleon',     # For Google style docstrings
     "sphinx_rtd_theme",
diff --git a/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql b/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql
new file mode 100644
index 0000000000000000000000000000000000000000..41297c918f0213017ebba22e1871ece2f515f782
--- /dev/null
+++ b/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql
@@ -0,0 +1,63 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2022-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2022-2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+-- a little bit of house keeping
+DROP PROCEDURE IF EXISTS retrieveSubEntity;
+DROP PROCEDURE IF EXISTS retrieveDatatype;
+DROP PROCEDURE IF EXISTS retrieveGroup;
+DROP PROCEDURE IF EXISTS getInfo;
+DROP PROCEDURE IF EXISTS getRole;
+DROP PROCEDURE IF EXISTS setPassword;
+DROP PROCEDURE IF EXISTS initAutoIncrement;
+DELETE FROM name_data WHERE entity_id=50;
+DELETE FROM entities WHERE id=50;
+DELETE FROM entities WHERE id=99;
+
+-- this simply is the more appropriate name
+ALTER TABLE entities MODIFY COLUMN
+  `role` enum('RECORDTYPE','RECORD','FILE','DOMAIN','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', '_REPLACEMENT') COLLATE utf8_unicode_ci NOT NULL;
+ALTER TABLE archive_entities MODIFY COLUMN
+  `role` enum('RECORDTYPE','RECORD','FILE','DOMAIN','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', '_REPLACEMENT') COLLATE utf8_unicode_ci NOT NULL;
+UPDATE entities SET role = "_REPLACEMENT" WHERE role="DOMAIN";
+UPDATE archive_entities SET role = "_REPLACEMENT" WHERE role="DOMAIN";
+ALTER TABLE entities MODIFY COLUMN
+  `role` enum('RECORDTYPE','RECORD','FILE','_REPLACEMENT','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE') COLLATE utf8_unicode_ci NOT NULL;
+ALTER TABLE archive_entities MODIFY COLUMN
+  `role` enum('RECORDTYPE','RECORD','FILE','_REPLACEMENT','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE') COLLATE utf8_unicode_ci NOT NULL;
+
+
+
+-- new entity_ids table
+DROP TABLE IF EXISTS `entity_ids`;
+CREATE TABLE `entity_ids` (
+    `id` VARCHAR(255) NOT NULL,
+    `internal_id` int(10) unsigned NOT NULL COMMENT 'Internal ID of an entity. This id is used internally in the *_data tables and elsewhere. This ID is never exposed via the CaosDB API.',
+    PRIMARY KEY `entity_ids_pk` (`id`),
+    CONSTRAINT `entity_ids_internal_id` FOREIGN KEY (`internal_id`) REFERENCES `entities` (`id`)
+) ENGINE=InnoDB COLLATE utf8mb4_bin;
+
+-- fill all existing entities into the new entity_ids table.
+INSERT INTO entity_ids (id, internal_id) SELECT id, id FROM entities WHERE id>0 AND role!="_REPLACEMENT";
+
+ALTER TABLE transaction_log MODIFY COLUMN `entity_id` VARCHAR(255) COLLATE utf8mb4_bin NOT NULL;
+
+ALTER TABLE user_info DROP FOREIGN KEY `subjects_ibfk_1`;
+ALTER TABle user_info MODIFY COLUMN `entity` VARCHAR(255) COLLATE utf8mb4_bin DEFAULT NULL;
+ALTER TABLE user_info ADD CONSTRAINT `subjects_ibfk_2` FOREIGN KEY (`entity`) REFERENCES `entity_ids` (`id`);
diff --git a/patches/patch20221122-6.0-SNAPSHOT/patch.sh b/patches/patch20221122-6.0-SNAPSHOT/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9833f5ad953799afc33133014ec4db2ac6320beb
--- /dev/null
+++ b/patches/patch20221122-6.0-SNAPSHOT/patch.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+# Update mysql schema to version v5.0.0
+# Drop the 'rules' table.
+
+NEW_VERSION="v6.0.0-SNAPSHOT-EXTIDS"
+OLD_VERSION="v5.0.0"
+
+DROP_TABLE_PASSWORDS='DROP TABLE IF EXISTS passwords;'
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+mysql_execute "$DROP_TABLE_PASSWORDS"
+mysql_execute_file $PATCH_DIR/create_entity_ids_table.sql
+
+update_version $NEW_VERSION
+
+
+success
+
diff --git a/patches/patch20231018-6.1.0/patch.sh b/patches/patch20231018-6.1.0/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..e91f487216ce254fb3b1a78a911f38fcc263d8c7
--- /dev/null
+++ b/patches/patch20231018-6.1.0/patch.sh
@@ -0,0 +1,42 @@
+#!/bin/bash
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+# Update mysql schema to version v6.1.0
+# No migration of the schema, updating procedures only
+
+NEW_VERSION="v6.1.0"
+OLD_VERSION="v6.0.0-SNAPSHOT-EXTIDS"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+# Drop insertUser procedure
+mysql_execute "DROP PROCEDURE IF EXISTS insertUser;"
+
+update_version $NEW_VERSION
+
+success
+
diff --git a/patches/patch20231025-7.0.0/patch.sh b/patches/patch20231025-7.0.0/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..06a7dc85c75897b7c47e6094f634b5421f92c794
--- /dev/null
+++ b/patches/patch20231025-7.0.0/patch.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+# Update mysql schema to version v7.0.0
+# No migration of the schema, updating procedures only
+
+NEW_VERSION="v7.0.0"
+OLD_VERSION="v6.1.0"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+update_version $NEW_VERSION
+
+success
+
diff --git a/patches/patch20231101-7.0.1/patch.sh b/patches/patch20231101-7.0.1/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..869a014317b3a51246562052560adcecb841eebe
--- /dev/null
+++ b/patches/patch20231101-7.0.1/patch.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+# Update mysql schema to version v7.0.1
+# Removing remnant tables. This patch version also adds new sanity checks
+# during installation/upgrade
+
+NEW_VERSION="v7.0.1"
+OLD_VERSION="v7.0.0"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+mysql_execute "DROP TABLE IF EXISTS groups";
+mysql_execute "DROP TABLE IF EXISTS passwords";
+mysql_execute "DROP TABLE IF EXISTS logging";
+mysql_execute "DROP TABLE IF EXISTS isa";
+
+update_version $NEW_VERSION
+
+success
diff --git a/patches/patch20231211-7.0.2/patch.sh b/patches/patch20231211-7.0.2/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..422fc00b9083808446d74776b446c072bdfd73bc
--- /dev/null
+++ b/patches/patch20231211-7.0.2/patch.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# This file is a part of the CaosDB Project.
+#
+# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as
+# published by the Free Software Foundation, either version 3 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+
+# Update mysql schema to version v7.0.2
+# Patch the broken data_type table (fix id for file references as per
+# https://gitlab.com/linkahead/linkahead-server/-/issues/246)
+
+NEW_VERSION="v7.0.2"
+OLD_VERSION="v7.0.1"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+mysql_execute "UPDATE data_type SET datatype=17 WHERE datatype=3"
+
+update_version $NEW_VERSION
+
+success
diff --git a/patches/patch20220110-6.0-SNAPSHOT/patch.sh b/patches/patch20240127-8.0-SNAPSHOT/patch.sh
similarity index 96%
rename from patches/patch20220110-6.0-SNAPSHOT/patch.sh
rename to patches/patch20240127-8.0-SNAPSHOT/patch.sh
index 739a6b835f02df72f1594c9cc49a459d603e65b6..32efac1319e58a8cb60fa6f7ac688b3244a790d0 100755
--- a/patches/patch20220110-6.0-SNAPSHOT/patch.sh
+++ b/patches/patch20240127-8.0-SNAPSHOT/patch.sh
@@ -25,8 +25,8 @@
 # Refactors the files and archive_files tables and all affected procedures for
 # the new file back-end
 # Update mysql schema to version v5.0.0-rc1
-NEW_VERSION="v6.0-SNAPSHOT"
-OLD_VERSION="v5.0.0"
+NEW_VERSION="v8.0-SNAPSHOT"
+OLD_VERSION="v7.0.2"
 
 if [ -z "$UTILSPATH" ]; then
  UTILSPATH="../utils"
diff --git a/patches/patch20220110-6.0-SNAPSHOT/patch.sql b/patches/patch20240127-8.0-SNAPSHOT/patch.sql
similarity index 95%
rename from patches/patch20220110-6.0-SNAPSHOT/patch.sql
rename to patches/patch20240127-8.0-SNAPSHOT/patch.sql
index 2a707e001a607cb21a1ccda28bef9513473d83c0..38ea11f5063bb65b8878e94fa406b35e977c4edf 100644
--- a/patches/patch20220110-6.0-SNAPSHOT/patch.sql
+++ b/patches/patch20240127-8.0-SNAPSHOT/patch.sql
@@ -1,10 +1,5 @@
 -- USE _caosdb_schema_unit_tests;
 
-
--- REMOVE SQLITE datatype (obsolete)
-DELETE FROM name_data WHERE entity_id = 50;
-DELETE FROM entities WHERE id = 50;
-
 /*
 -- Create file_hashes table.
 -- This table is necessary because not all FSO objects have hashes (e.g.
@@ -40,7 +35,7 @@ ALTER TABLE archive_files DROP COLUMN hash;
 
 -- Add new fields to files table...
 ALTER TABLE files ADD COLUMN IF NOT EXISTS (
-    hash_algorithm VARBINARY(255) NULL DEFAULT NULL,
+    hash_algorithm VARBINARY(255) NULL DEFAULT 'SHA-512',
     parent_directory INT UNSIGNED DEFAULT NULL,
     mimetype VARBINARY(255) DEFAULT NULL,
     file_storage_id VARBINARY(255) NOT NULL DEFAULT "DEFAULT",
@@ -51,7 +46,7 @@ ALTER TABLE files ADD COLUMN IF NOT EXISTS (
 -- ... and to the corresponding archive_files table.
 ALTER TABLE archive_files ADD COLUMN IF NOT EXISTS (
     checked_timestamp BIGINT NOT NULL DEFAULT 0,
-    hash_algorithm VARBINARY(255) NULL DEFAULT NULL,
+    hash_algorithm VARBINARY(255) NULL DEFAULT 'SHA-512',
     parent_directory INT UNSIGNED DEFAULT NULL,
     mimetype VARBINARY(255) DEFAULT NULL,
     file_storage_id VARBINARY(255) NOT NULL DEFAULT "DEFAULT",
@@ -66,11 +61,12 @@ ALTER TABLE files ADD FOREIGN KEY (parent_directory) REFERENCES entities (id);
 ALTER TABLE archive_files ADD FOREIGN KEY (parent_directory) REFERENCES entities (id) ON DELETE CASCADE;
 
 
-ALTER TABLE entities MODIFY COLUMN `role` enum('RECORDTYPE','RECORD','FILE','DOMAIN','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', 'DIRECTORY', 'LINK') COLLATE utf8_unicode_ci NOT NULL;
+ALTER TABLE entities MODIFY COLUMN `role` enum('RECORDTYPE','RECORD','FILE','_REPLACEMENT','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', 'DIRECTORY', 'LINK') COLLATE utf8_unicode_ci NOT NULL;
 
 -- Add a new special role "DIRECTORY"
 INSERT IGNORE INTO entities (id, description, role, acl) VALUES (9, "The directory role.", "ROLE", 0);
 INSERT IGNORE INTO name_data (domain_id, entity_id, property_id, value, status, pidx) VALUES (0, 9, 20, "DIRECTORY", "FIX", 0);
+INSERT IGNORE INTO entity_ids (id, internal_id) VALUES (9,9);
 
 -- Add a new special role "LINK"
 INSERT IGNORE INTO entities (id, description, role, acl) VALUES (10, "The link role.", "ROLE", 0);
@@ -97,6 +93,7 @@ ALTER TABLE archive_files MODIFY COLUMN path VARCHAR(16000) NOT NULL;
 -- Add a special nameless directory which is used as the root directory of the
 -- internal file system.
 INSERT IGNORE INTO entities (id, description, role, acl) VALUES (51, "The root directory of the internal files system", "DIRECTORY", 0);
+INSERT IGNORE INTO entity_ids (id, internal_id) VALUES (51,51);
 INSERT IGNORE INTO files
     (file_id, path, checked_timestamp, mimetype, file_storage_id,
         file_key, parent_directory)
@@ -152,9 +149,7 @@ BEGIN
                 -- this is the case when all parent directories of the current file have been processed.
                 SET dir_exists = FALSE;
                 SET done = FALSE;
-                LEAVE loop2;
-            END IF;
-
+                LEAVE loop2; END IF;
             -- remove the trailing slash for convenience.
             SET dir_path_no_trailing_slash = LEFT(dir_path, CHAR_LENGTH(dir_path)-1);
 
diff --git a/procedures/deleteEntity.sql b/procedures/deleteEntity.sql
index 859f43cad7e6951f7eec94b99b5e2a2cc34dac10..6b3fc99460cbfd8fe85f4255caaa05b16e31fc99 100644
--- a/procedures/deleteEntity.sql
+++ b/procedures/deleteEntity.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 /* Delete a (sparse) Entity from the database.
@@ -31,38 +29,44 @@ have been deleted before.  This can be done for example with the
 Parameters
 ==========
 
-EntityID : UNSIGNED
-The ID of the Entity.
+EntityID : VARCHAR(255)
+    The ID of the Entity.
 */
 
 DROP PROCEDURE IF EXISTS db_5_0.deleteEntity;
 delimiter //
 
-CREATE PROCEDURE db_5_0.deleteEntity(in EntityID INT UNSIGNED)
+CREATE PROCEDURE db_5_0.deleteEntity(in EntityID VARCHAR(255))
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
     -- detele file properties
-    DELETE FROM files where file_id=EntityID;
-    DELETE FROM files where parent_directory=EntityID;
+    DELETE FROM files where file_id=InternalEntityID;
+    DELETE FROM files where parent_directory=InternalEntityID;
 
     -- delete datatype stuff
     DELETE FROM data_type
         WHERE ( domain_id = 0
             AND entity_id = 0
-            AND property_id = EntityID )
-        OR datatype = EntityID;
+            AND property_id = InternalEntityID )
+        OR datatype = InternalEntityID;
     DELETE FROM collection_type
         WHERE domain_id = 0
         AND entity_id = 0
-        AND property_id = EntityID;
+        AND property_id = InternalEntityID;
 
     -- delete primary name (in case this is called without a prior call to deleteEntityProperties)
     DELETE FROM name_data
         WHERE domain_id = 0
-        AND entity_id = EntityID
+        AND entity_id = InternalEntityID
         AND property_id = 20;
 
-    DELETE FROM entities where id=EntityID;
+    DELETE FROM entity_ids
+        WHERE internal_id = InternalEntityID;
+
+    DELETE FROM entities where id=InternalEntityID;
 
     -- clean up unused acl
     DELETE FROM entity_acl
diff --git a/procedures/deleteEntityProperties.sql b/procedures/deleteEntityProperties.sql
index 147959df5f24dc8e67f1fbce97c609da1e31e09a..71b5651c58f5162752a4728c935a4a1a4ce66736 100644
--- a/procedures/deleteEntityProperties.sql
+++ b/procedures/deleteEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,23 +18,34 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.deleteEntityProperties;
 delimiter //
 
-CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID INT UNSIGNED)
+/*
+ * Delete all properties of an entity (i.e. remove them from the *_data tables
+ * and the isa_cache table).
+ *
+ * Parameters
+ * ==========
+ *
+ * EntityID : VARCHAR(255)
+ *    The entity's id.
+ */
+CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID VARCHAR(255))
 BEGIN
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
-    CALL deleteIsa(EntityID);
+    CALL deleteIsa(InternalEntityID);
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         SELECT max(e._iversion) INTO IVersion -- What's the latest version?
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID;
+            WHERE e.entity_id = InternalEntityID;
 
         -- Copy the rows from *_data to archive_*_data ---------------------
         INSERT INTO archive_reference_data (domain_id, entity_id,
@@ -43,142 +53,142 @@ BEGIN
             SELECT domain_id, entity_id, property_id, value, value_iversion,
                 status, pidx, IVersion AS _iversion
             FROM reference_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_null_data (domain_id, entity_id,
                 property_id, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, status,
                 pidx, IVersion AS _iversion
             FROM null_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_text_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM text_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_name_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM name_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_enum_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM enum_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_integer_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion, unit_sig)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion, unit_sig
             FROM integer_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_double_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion, unit_sig)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion, unit_sig
             FROM double_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_datetime_data (domain_id, entity_id,
                 property_id, value, value_ns, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, value_ns,
                 status, pidx, IVersion AS _iversion
             FROM datetime_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_date_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM date_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_name_overrides (domain_id, entity_id,
                 property_id, name, _iversion)
             SELECT domain_id, entity_id, property_id, name,
                 IVersion AS _iversion
             FROM name_overrides
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_desc_overrides (domain_id, entity_id,
                 property_id, description, _iversion)
             SELECT domain_id, entity_id, property_id, description,
                 IVersion AS _iversion
             FROM desc_overrides
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_data_type (domain_id, entity_id,
                 property_id, datatype, _iversion)
             SELECT domain_id, entity_id, property_id, datatype,
                 IVersion AS _iversion
             FROM data_type
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_collection_type (domain_id, entity_id,
                 property_id, collection, _iversion)
             SELECT domain_id, entity_id, property_id, collection,
                 IVersion AS _iversion
             FROM collection_type
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_query_template_def (id, definition, _iversion)
             SELECT id, definition, IVersion AS _iversion
             FROM query_template_def
-            WHERE id = EntityID;
+            WHERE id = InternalEntityID;
 
     END IF;
 
     DELETE FROM reference_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM null_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM text_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM name_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM enum_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM integer_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM double_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM datetime_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM date_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
     DELETE FROM name_overrides
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM desc_overrides
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
     DELETE FROM data_type
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM collection_type
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
-    DELETE FROM query_template_def WHERE id=EntityID;
+    DELETE FROM query_template_def WHERE id=InternalEntityID;
 
 END;
 //
diff --git a/procedures/deleteIsaCache.sql b/procedures/deleteIsaCache.sql
index fd78d3fd8a23a93b91cacedbcc28f91966c59d90..dcfb68cf694458b56401720da8c939baae770247 100644
--- a/procedures/deleteIsaCache.sql
+++ b/procedures/deleteIsaCache.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 SET GLOBAL log_bin_trust_function_creators = 1;
 
@@ -38,30 +35,30 @@ parameter entity is a child or inside the rpath.
 Parameters
 ==========
 
-EntityID : UNSIGNED
-Child entity for which all parental relations should be deleted.
+InternalEntityID : UNSIGNED
+    Child entity for which all parental relations should be deleted.
 */
-CREATE PROCEDURE db_5_0.deleteIsa(IN EntityID INT UNSIGNED)
+CREATE PROCEDURE db_5_0.deleteIsa(IN InternalEntityID INT UNSIGNED)
 BEGIN
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         SELECT max(_iversion) INTO IVersion
             FROM entity_version
-            WHERE entity_id = EntityID;
+            WHERE entity_id = InternalEntityID;
 
         -- move to archive_isa before deleting
         INSERT IGNORE INTO archive_isa (child, child_iversion, parent, direct)
-            SELECT e.child, IVersion AS child_iversion, e.parent, rpath = EntityID
+            SELECT e.child, IVersion AS child_iversion, e.parent, rpath = InternalEntityID
             FROM isa_cache AS e
-            WHERE e.child = EntityID;
+            WHERE e.child = InternalEntityID;
     END IF;
 
     DELETE FROM isa_cache
-        WHERE child = EntityID
-        OR rpath = EntityID
-        OR rpath LIKE concat('%>', EntityID)
-        OR rpath LIKE concat('%>', EntityID, '>%');
+        WHERE child = InternalEntityID
+        OR rpath = InternalEntityID
+        OR rpath LIKE concat('%>', InternalEntityID)
+        OR rpath LIKE concat('%>', InternalEntityID, '>%');
 
 END;
 //
diff --git a/procedures/entityVersioning.sql b/procedures/entityVersioning.sql
index 591556759bc1c3424140942c943b85c24f61e86f..b474d0121130a1695d69616e1de4cc54468b5e64 100644
--- a/procedures/entityVersioning.sql
+++ b/procedures/entityVersioning.sql
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -27,23 +27,23 @@ DROP PROCEDURE IF EXISTS db_5_0.insert_single_child_version //
  *
  * Parameters
  * ----------
- * EntityID
- *   The ID of the versioned entity.
- * Hash
+ * InternalEntityID : INT UNSIGNED
+ *   The internal ID of the versioned entity.
+ * Hash : VARBINARY(255)
  *   A hash of the entity. This is currently not implemented properly and only
  *   there for future use.
- * Version
+ * Version : VARBINARY(255)
  *   The new version ID of the entity, must be produced by the caller.  Must be unique for each
  *   EntityID.
- * Parent
+ * Parent : VARBINARY(255)
  *   The version ID of the primary parent (i.e. predecessor).  May be NULL; but if given, it must
  *   exist.
- * Transaction
+ * Transaction : VARBINARY(255)
  *   The transaction ID which created this entity version (by inserting
  *   or updating an entity).
  */
 CREATE PROCEDURE db_5_0.insert_single_child_version(
-    in EntityID INT UNSIGNED,
+    in InternalEntityID INT UNSIGNED,
     in Hash VARBINARY(255),
     in Version VARBINARY(255),
     in Parent VARBINARY(255),
@@ -57,12 +57,12 @@ BEGIN
     IF Parent IS NOT NULL THEN
         SELECT e._iversion INTO newipparent
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             AND e.version = Parent;
         IF newipparent IS NULL THEN
             -- throw error;
             SELECT concat("This parent does not exists: ", Parent)
-            FROM nonexisting;
+            FROM parent_version_does_not_exist;
         END IF;
     END IF;
 
@@ -70,7 +70,7 @@ BEGIN
     -- generate _iversion
     SELECT max(e._iversion)+1 INTO newiversion
         FROM entity_version AS e
-        WHERE e.entity_id=EntityID;
+        WHERE e.entity_id=InternalEntityID;
     IF newiversion IS NULL THEN
         SET newiversion = 1;
     END IF;
@@ -78,7 +78,7 @@ BEGIN
     INSERT INTO entity_version
         (entity_id, hash, version, _iversion, _ipparent, srid)
         VALUES
-        (EntityID, Hash, Version, newiversion, newipparent, Transaction);
+        (InternalEntityID, Hash, Version, newiversion, newipparent, Transaction);
 
 
 
@@ -87,22 +87,28 @@ END;
 
 DROP PROCEDURE IF EXISTS db_5_0.delete_all_entity_versions //
 
+/* THIS PROCEDURE HAS NEVER BEEN USED (outside of the tests). Reactivate when
+ * versioning's FORGET is being implemented. */
 /**
  * Remove all records in the entity_version table for the given entity.
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The id of the versioned entity.
  */
-CREATE PROCEDURE db_5_0.delete_all_entity_versions(
-    in EntityID INT UNSIGNED)
+/* CREATE PROCEDURE db_5_0.delete_all_entity_versions(
+    in EntityID VARCHAR(255))
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
 
-    DELETE FROM entity_version WHERE entity_id = EntityID;
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
+    DELETE FROM entity_version WHERE entity_id = InternalEntityID;
 
 END;
 //
+*/
 
 DROP FUNCTION IF EXISTS db_5_0.get_iversion //
 
@@ -111,9 +117,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity's id.
- * Version
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
+ * Version : VARBINARY(255)
  *   The (official, externally used) version id.
  *
  * Returns
@@ -121,7 +127,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion //
  * The internal version id.
  */
 CREATE FUNCTION db_5_0.get_iversion(
-    EntityID INT UNSIGNED,
+    InternalEntityID INT UNSIGNED,
     Version VARBINARY(255))
 RETURNS INT UNSIGNED
 READS SQL DATA
@@ -129,7 +135,7 @@ BEGIN
     RETURN (
         SELECT e._iversion
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
                 AND e.version = Version
         );
 END;
@@ -143,9 +149,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Version
+ * Version : VARBINARY(255)
  *   The version id.
  *
  * Returns
@@ -153,17 +159,21 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version //
  * The id of the given version's primary parent version.
  */
 CREATE FUNCTION db_5_0.get_primary_parent_version(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Version VARBINARY(255))
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     RETURN (
         SELECT p.version
             FROM entity_version AS e INNER JOIN entity_version AS p
                 ON (e._ipparent = p._iversion
                     AND e.entity_id = p.entity_id)
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
                 AND e.version = Version
         );
 END;
@@ -177,9 +187,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Version
+ * Version : VARBINARY(255)
  *   The version id.
  *
  * Returns
@@ -188,16 +198,20 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp //
  * Note that the dot `.` here is not necessarily a decimal separator.
  */
 CREATE FUNCTION db_5_0.get_version_timestamp(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Version VARBINARY(255))
 RETURNS VARCHAR(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     RETURN (
         SELECT concat(t.seconds, '.', t.nanos)
             FROM entity_version AS e INNER JOIN transactions AS t
                 ON ( e.srid = t.srid )
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             AND e.version = Version
     );
 END;
@@ -210,7 +224,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
  *
  * Returns
@@ -218,7 +232,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version //
  * The version id of the HEAD.
  */
 CREATE FUNCTION db_5_0.get_head_version(
-    EntityID INT UNSIGNED)
+    EntityID VARCHAR(255))
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
@@ -233,15 +247,15 @@ DROP FUNCTION IF EXISTS db_5_0._get_head_iversion //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity id.
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
  *
  * Returns
  * -------
  * The _iversion of the HEAD.
  */
 CREATE FUNCTION db_5_0._get_head_iversion(
-    EntityID INT UNSIGNED)
+    InternalEntityID INT UNSIGNED)
 RETURNS INT UNSIGNED
 READS SQL DATA
 BEGIN
@@ -252,7 +266,7 @@ BEGIN
     RETURN (
         SELECT e._iversion
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             ORDER BY e._iversion DESC
             LIMIT 1
         );
@@ -267,9 +281,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Offset
+ * Offset : INT UNSIGNED
  *   Distance in the sequence of primary parents of the entity. E.g. `0` is the
  *   HEAD itself. `1` is the primary parent of the HEAD. `2` is the primary
  *   parent of the primary parent of the HEAD, and so on.
@@ -279,11 +293,15 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative //
  * The version id of the HEAD.
  */
 CREATE FUNCTION db_5_0.get_head_relative(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Offset INT UNSIGNED)
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     -- This implementation assumes that the distance from the head equals the
     -- difference between the _iversion numbers. This will not be correct anymore
     -- as soon as branches may split and merge. Then, a walk over the primary
@@ -291,7 +309,7 @@ BEGIN
     RETURN (
         SELECT e.version
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             ORDER BY e._iversion DESC
             LIMIT 1 OFFSET Offset
         );
@@ -304,24 +322,24 @@ DROP FUNCTION IF EXISTS db_5_0._get_version //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity id.
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
  * IVersion
  *   Internal version id (integer).
  *
  * Returns
  * -------
- * The version id.
+ * The (external) version id.
  */
 CREATE FUNCTION db_5_0._get_version(
-    EntityID INT UNSIGNED,
+    InternalEntityID INT UNSIGNED,
     IVersion INT UNSIGNED)
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
     RETURN (
         SELECT version FROM entity_version
-            WHERE entity_id = EntityID
+            WHERE entity_id = InternalEntityID
             AND _iversion = IVersion
         );
 END;
@@ -335,7 +353,7 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
  *
  * Selects
@@ -344,8 +362,12 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history //
  *   child_realm). `child` and `parent` are version IDs.
  */
 CREATE PROCEDURE db_5_0.get_version_history(
-    in EntityID INT UNSIGNED)
+    in EntityID VARCHAR(255))
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     -- retrieve root(s) (initial versions)
     SELECT c.version AS child,
             NULL as parent,
@@ -355,7 +377,7 @@ BEGIN
             t.realm AS child_realm
         FROM entity_version AS c INNER JOIN transactions as t
         ON ( c.srid = t.srid )
-        WHERE c.entity_id = EntityID
+        WHERE c.entity_id = InternalEntityID
         AND c._ipparent is Null
 
     -- TODO This first SELECT statement is necessary because the second one
@@ -375,7 +397,7 @@ BEGIN
             ON (c._ipparent = p._iversion
                 AND c.entity_id = p.entity_id
                 AND t.srid = c.srid)
-        WHERE p.entity_id = EntityID;
+        WHERE p.entity_id = InternalEntityID;
 END;
 //
 
@@ -412,75 +434,6 @@ BEGIN
 END //
 
 
-
-DROP PROCEDURE IF EXISTS setFileProperties //
-/**
- * Insert/Update file properties.
- *
- * If ENTITY_VERSIONING is enabled the old file properties are moved to
- * `archive_files`.
- *
- * Parameters
- * ----------
- * FileID
- *   The entity's id.
- * FileHash
- *   The SHA512 Hash of the file (or NULL for directories).
- * FileCheckedTimestamp
- *   The timestamp when the hash was last checked.
- * FileSize
- *   The byte size (or NULL for directories).
- * FilePath
- *   The path of the object.
- * FileMimeType
- *   The mimetype (use "inode/directory" for directories, use NULL for unknown)
- * FileStorageID
- *   The ID of the back-end file storage where this object is located.
- * FileKey
- *   The file storage key of this object.
- * FileParentID
- *   The entity id of the parent directory (or NULL).
- */
-CREATE PROCEDURE setFileProperties (
-    in FileID INT UNSIGNED,
-    in FilePath VARCHAR(5000),
-    in FileSize BIGINT UNSIGNED,
-    in FileHash VARCHAR(255),
-    in FileChecked BIGINT,
-    in FileMimeType VARBINARY(255),
-    in FileStorageId VARBINARY(255),
-    in FileKey VARBINARY(40000),
-    in FileParentID INT UNSIGNED,
-    in FileHashAlgo VARCHAR(255)
-)
-BEGIN
-    DECLARE IVersion INT UNSIGNED DEFAULT NULL;
-    IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
-        SELECT max(e._iversion) INTO IVersion
-            FROM entity_version AS e
-            WHERE e.entity_id = FileID;
-
-        INSERT INTO archive_files (file_id, path, size, hash,
-                checked_timestamp, mimetype, file_storage_id, file_key,
-                _iversion, hash_algorithm)
-            SELECT file_id, path, size, hash, checked_timestamp, mimetype,
-                file_storage_id, file_key, IVersion AS _iversion, hash_algorithm
-            FROM files
-            WHERE file_id = FileID;
-    END IF;
-
-    DELETE FROM files WHERE file_id = FileID;
-
-    IF FilePath IS NOT NULL THEN
-        INSERT INTO files (file_id, path, size, hash, checked_timestamp,
-                mimetype, file_storage_id, file_key, hash_algorithm)
-            VALUES (FileID, FilePath, FileSize, unhex(FileHash), FileChecked,
-                FileMimeType, FileStorageId, FileKey, FileHashAlgo);
-    END IF;
-
-END //
-
-
 DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef //
 
 /**
@@ -488,9 +441,9 @@ DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The QueryTemplate's id.
- * Version
+ * Version : VARBINARY(255)
  *   The QueryTemplate's version's id.
  *
  * Returns
@@ -499,12 +452,16 @@ DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef //
  * QueryTemplate.
  */
 CREATE PROCEDURE retrieveQueryTemplateDef (
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveQueryTemplateDefBody: BEGIN
 
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         -- Are we at the head?
@@ -513,11 +470,7 @@ retrieveQueryTemplateDefBody: BEGIN
         END IF;
 
         IF IsHead IS FALSE THEN
-            -- TODO Use get_iversion(EntityID, Version) instead?  Or will that be much slower?
-            SELECT e._iversion INTO IVersion
-                FROM entity_version as e
-                WHERE e.entity_id = EntityID
-                AND e.version = Version;
+            SET IVersion = get_iversion(InternalEntityID, Version);
 
             IF IVersion IS NULL THEN
                 -- RETURN EARLY - Version does not exist.
@@ -526,7 +479,7 @@ retrieveQueryTemplateDefBody: BEGIN
 
             SELECT definition
             FROM archive_query_template_def
-            WHERE id = EntityID
+            WHERE id = InternalEntityID
             AND _iversion = IVersion;
 
             LEAVE retrieveQueryTemplateDefBody;
@@ -535,7 +488,7 @@ retrieveQueryTemplateDefBody: BEGIN
 
     SELECT definition
     FROM query_template_def
-    WHERE id = EntityID;
+    WHERE id = InternalEntityID;
 
 END //
 
diff --git a/procedures/getDependentEntities.sql b/procedures/getDependentEntities.sql
index fecf96e133dbbf649474564cfcfd2e45f5c929b4..908095e96ccb9cc71a79f6aacc88fcdf3848d935 100644
--- a/procedures/getDependentEntities.sql
+++ b/procedures/getDependentEntities.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale.com>
- * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2022-2024 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2022-2024 IndiScale GmbH <info@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -20,58 +19,78 @@
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
  *
- * ** end header
  */
 
 
-
 DROP PROCEDURE IF EXISTS db_5_0.getDependentEntities;
 delimiter //
 
-CREATE PROCEDURE db_5_0.getDependentEntities(in EntityID INT UNSIGNED)
+/*
+ * Return all entities which either reference the given entity, use the given
+ * reference as data type, or are direct children of the given entity.
+ *
+ * This function used to make sure that no entity can be deleted which
+ * is still needed by others.
+ *
+ * Parameters
+ * ----------
+ * EntityID : VARCHAR(255)
+ *    The entity id.
+ *
+ * ResultSet
+ * ---------
+ * EntityID : VARCHAR(255)
+ *
+ */
+CREATE PROCEDURE db_5_0.getDependentEntities(in EntityID VARCHAR(255))
 BEGIN
 
-DROP TEMPORARY TABLE IF EXISTS refering;
-CREATE TEMPORARY TABLE refering (
-    id INT UNSIGNED UNIQUE
-);
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    DROP TEMPORARY TABLE IF EXISTS referring;
+    CREATE TEMPORARY TABLE referring (
+        id INT UNSIGNED UNIQUE
+    );
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM reference_data WHERE (value=EntityID OR property_id=EntityID) AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM reference_data WHERE (value=EntityID OR property_id=EntityID) AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM reference_data WHERE (value=InternalEntityID OR property_id=InternalEntityID) AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM reference_data WHERE (value=InternalEntityID OR property_id=InternalEntityID) AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM text_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM text_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM text_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM text_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM enum_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM enum_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM enum_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM enum_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM name_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM name_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM name_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM name_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM integer_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM integer_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM integer_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM integer_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM double_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM double_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM double_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM double_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM datetime_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM datetime_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM datetime_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM datetime_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM date_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM date_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM date_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM date_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM null_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM null_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; 
+    INSERT IGNORE INTO referring (id) SELECT file_id FROM files WHERE parent_directory=InternalEntityID;
 
-INSERT IGNORE INTO refering (id) SELECT entity_id FROM data_type WHERE datatype=EntityID AND domain_id=0 AND entity_id!=EntityID;
-INSERT IGNORE INTO refering (id) SELECT domain_id FROM data_type WHERE datatype=EntityID;
+    INSERT IGNORE INTO referring (id) SELECT entity_id FROM null_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id FROM null_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0;
 
-INSERT IGNORE INTO refering (id) SELECT file_id FROM files WHERE parent_directory=EntityID;
+    INSERT IGNORE INTO referring (id) SELECT entity_id from data_type WHERE datatype=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID;
+    INSERT IGNORE INTO referring (id) SELECT domain_id from data_type WHERE datatype=InternalEntityID;
 
+    INSERT IGNORE INTO referring (id) SELECT child FROM isa_cache WHERE parent = InternalEntityID AND rpath = child;
 
-SELECT id FROM refering WHERE id!=0 AND id!=EntityID;
+    SELECT e.id FROM referring AS r LEFT JOIN entity_ids AS e ON r.id = e.internal_id WHERE r.id!=0 AND e.internal_id!=InternalEntityID;
 
-DROP TEMPORARY TABLE refering;
+    DROP TEMPORARY TABLE referring;
 
 END;
 //
diff --git a/procedures/getIdByName.sql b/procedures/getIdByName.sql
new file mode 100644
index 0000000000000000000000000000000000000000..781594eff9fba3b3582e2e2a4a828f3c7a98a10c
--- /dev/null
+++ b/procedures/getIdByName.sql
@@ -0,0 +1,63 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+DROP PROCEDURE IF EXISTS db_5_0.getIdByName;
+DELIMITER //
+
+/*
+ * Return the Entity id(s) for a given name. Optionally, filter by role and set
+ * a limit.
+ *
+ * Parameters
+ * ----------
+ * Name : VARCHAR(255)
+ *    The entity's name.
+ * Role : VARCHAR(255)
+ *    E.g. RecordType, Record, Property,...
+ * Lmt : INT UNSIGNED
+ *    Limit the number of returned entity ids.
+ *
+ * Returns
+ * -------
+ * EntityID : VARCHAR(255)
+ */
+CREATE PROCEDURE db_5_0.getIdByName(in Name VARCHAR(255), in Role VARCHAR(255), in Lmt INT UNSIGNED)
+BEGIN
+
+    SET @stmtStr = "SELECT e.id AS id FROM name_data AS n JOIN entity_ids AS e ON (n.domain_id=0 AND n.property_id=20 AND e.internal_id = n.entity_id) JOIN entities AS i ON (i.id = e.internal_id) WHERE n.value = ?";
+
+    IF Role IS NULL THEN
+        SET @stmtStr = CONCAT(@stmtStr, " AND i.role!='ROLE'");
+    ELSE
+        SET @stmtStr = CONCAT(@stmtStr, " AND i.role='", Role, "'");
+    END IF;
+
+    IF Lmt IS NOT NULL THEN
+        SET @stmtStr = CONCAT(@stmtStr, " LIMIT ", Lmt);
+    END IF;
+
+    SET @vName = Name;
+    PREPARE stmt FROM @stmtStr;
+    EXECUTE stmt USING @vName;
+    DEALLOCATE PREPARE stmt;
+
+END;
+//
+DELIMITER ;
diff --git a/procedures/getInfo.sql b/procedures/getInfo.sql
deleted file mode 100644
index 03c75b4e1df37400596c85d20e5421abc43c6f10..0000000000000000000000000000000000000000
--- a/procedures/getInfo.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-#-- old procedure.
-Drop Procedure if exists db_5_0.getInfo;
diff --git a/procedures/getRole.sql b/procedures/getRole.sql
deleted file mode 100644
index bea96fcfbf14d7ad8ec62b88c272ab22c5d94258..0000000000000000000000000000000000000000
--- a/procedures/getRole.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-
-
-
-
-
-DROP PROCEDURE IF EXISTS db_5_0.getRole;
-delimiter //
-CREATE PROCEDURE db_5_0.getRole(in RoleName VARCHAR(255))
-BEGIN
-
-Select e.id INTO @RoleID from entities e where e.name=RoleName AND e.role=RoleName LIMIT 1;
-
-call retrieveEntity(@RoleID);
-
-
-
-
-END;
-//
-delimiter ;
diff --git a/procedures/initAutoIncrement.sql b/procedures/initAutoIncrement.sql
deleted file mode 100644
index 54cb54525ee7d8b864c1e979dfda6ab9471fcfb5..0000000000000000000000000000000000000000
--- a/procedures/initAutoIncrement.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-DROP PROCEDURE IF EXISTS db_5_0.initAutoIncrement;
-delimiter //
-
-CREATE PROCEDURE db_5_0.initAutoIncrement()
-BEGIN
-
-    SELECT @max := MAX(entity_id)+ 1 FROM transaction_log; 
-    IF @max IS NOT NULL THEN
-        SET @stmtStr = CONCAT('ALTER TABLE entities AUTO_INCREMENT=',@max);
-        PREPARE stmt FROM @stmtStr;
-        EXECUTE stmt;
-        DEALLOCATE PREPARE stmt;
-    END IF;
-
-END;
-//
-delimiter ;
diff --git a/procedures/insertEntity.sql b/procedures/insertEntity.sql
index d5f237cc172099ddbbcfe2accc6f1f11707c8148..ab0723af6f2e21a4ba8dc8b81207cf7c8367f9e8 100644
--- a/procedures/insertEntity.sql
+++ b/procedures/insertEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -31,12 +28,14 @@ delimiter //
 Parameters
 ==========
 
+EntityID : VARCHAR(255)
+    The entity id.
 EntityName : VARCHAR(255)
 
 EntityDesc : TEXT
 
 EntityRole : VARCHAR(255)
-Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'DOMAIN', 'PROPERTY',
+Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'PROPERTY',
 'DATATYPE', 'ROLE', 'QUERYTEMPLATE'
 
 ACL : VARBINARY(65525)
@@ -44,22 +43,23 @@ ACL : VARBINARY(65525)
 Select
 ======
 
-A tuple (EntityID, Version)
+(Version)
 */
 CREATE PROCEDURE db_5_0.insertEntity(
+    in EntityID VARCHAR(255),
     in EntityName VARCHAR(255),
     in EntityDesc TEXT,
     in EntityRole VARCHAR(255),
     in ACL VARBINARY(65525)
 )
 BEGIN
-    DECLARE NewEntityID INT UNSIGNED DEFAULT NULL;
     DECLARE NewACLID INT UNSIGNED DEFAULT NULL;
     DECLARE Hash VARBINARY(255) DEFAULT NULL;
     DECLARE Version VARBINARY(255) DEFAULT NULL;
     DECLARE Transaction VARBINARY(255) DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
 
-    -- insert the acl. the new acl id is being written (c-style) into the
+    -- insert the acl. The new acl id is written (c-style) into the
     -- variable NewACLID.
     call entityACL(NewACLID, ACL);
 
@@ -68,13 +68,15 @@ BEGIN
         VALUES (EntityDesc, EntityRole, NewACLID);
 
     -- ... and return the generated id
-    SET NewEntityID = LAST_INSERT_ID();
+    SET InternalEntityID = LAST_INSERT_ID();
+
+    INSERT INTO entity_ids (internal_id, id) VALUES (InternalEntityID, EntityID);
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         -- TODO this is transaction-scoped variable. Is this a good idea?
         SET Transaction = @SRID;
         SET Version = SHA1(UUID());
-        CALL insert_single_child_version(NewEntityID, Hash, Version, Null, Transaction);
+        CALL insert_single_child_version(InternalEntityID, Hash, Version, Null, Transaction);
     END IF;
 
     -- insert the name of the entity into name_data table
@@ -82,10 +84,10 @@ BEGIN
     IF EntityName IS NOT NULL THEN
         INSERT INTO name_data
             (domain_id, entity_id, property_id, value, status, pidx)
-            VALUES (0, NewEntityID, 20, EntityName, "FIX", 0);
+            VALUES (0, InternalEntityID, 20, EntityName, "FIX", 0);
     END IF;
 
-    SELECT NewEntityID as EntityID, Version as Version;
+    SELECT Version as Version, InternalEntityID as InternalEntityID;
 
 END;
 //
diff --git a/procedures/insertEntityDataType.sql b/procedures/insertEntityDataType.sql
new file mode 100644
index 0000000000000000000000000000000000000000..bd75099ba5317d997ca7a6bc9b4ae00d5f0a04c7
--- /dev/null
+++ b/procedures/insertEntityDataType.sql
@@ -0,0 +1,71 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+DROP PROCEDURE IF EXISTS db_5_0.insertEntityDataType;
+DELIMITER //
+
+/*
+ * Insert the (default) datatype of a property.
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *   The property id.
+ * DataTypeID : VARCHAR(255)
+ *   The data type id (not the name!)
+ */
+CREATE PROCEDURE db_5_0.insertEntityDataType(in PropertyID VARCHAR(255), in DataTypeID VARCHAR(255))
+BEGIN
+    DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id=PropertyID;
+
+    INSERT INTO data_type (domain_id, entity_id, property_id, datatype) SELECT 0, 0, InternalPropertyID, ( SELECT internal_id FROM entity_ids WHERE id = DataTypeID);
+
+
+END;
+//
+DELIMITER ;
+
+
+DROP PROCEDURE IF EXISTS db_5_0.insertEntityCollection;
+DELIMITER //
+
+/*
+ * Insert the (default) collection type of a property.
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *   The property id.
+ * Collection : VARCHAR(255)
+ *   The collection, e.g. "LIST"
+ */
+CREATE PROCEDURE db_5_0.insertEntityCollection(in PropertyID VARCHAR(255), in Collection VARCHAR(255))
+BEGIN
+    DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id=PropertyID;
+
+    INSERT INTO collection_type (domain_id, entity_id, property_id, collection) SELECT 0, 0, InternalPropertyID, Collection;
+
+END;
+//
+DELIMITER ;
diff --git a/procedures/insertEntityProperty.sql b/procedures/insertEntityProperty.sql
index 1cfd38bac3f0bd455779d7398d46f3dcf3df1243..cd26e62bade4fbb59c45e9c5af90bd7cca19ba43 100644
--- a/procedures/insertEntityProperty.sql
+++ b/procedures/insertEntityProperty.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,112 +18,166 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.insertEntityProperty;
 delimiter //
+
+
+/*
+ * Insert the property of an entity (level 1 and 2, only one *_data table entry at a time).
+ *
+ * Parameters
+ * ----------
+ * DomainID : VARCHAR(255)
+ *     The domain id (0 or the entity's id for level-2-data)
+ * EntityID : VARCHAR(255)
+ *     The entity id (or the property's id for level-2-data)
+ * PropertyID : VARCHAR(255)
+ *     The property id (or the sub-property's id for level-2-data)
+ * Datatable : VARCHAR(255)
+ *     Name of the *_data table, e.g. 'double_data'.
+ * PropertyValue : TEXT
+ *     The property's value
+ * PropertyUnitSig : BIGINT
+ *     The unit signature.
+ * PropertyStatus : VARCHAR(255)
+ *     E.g. OBLIGATORY, FIX,...
+ * NameOverride : VARCHAR(255)
+ *     The overridden name
+ * DescOverride : TEXT
+ *     The overridden description
+ * DatatypeOverride : VARCHAR(255)
+ *     The overridden datatype
+ * Collection : VARCHAR(255)
+ *     The overridden collection (only if DatatypeOverride is present).
+ * PropertyIndex : INT UNSIGNED
+ *     The property's index (for ordering of properties and values).
+ */
 CREATE PROCEDURE db_5_0.insertEntityProperty(
-    in DomainID INT UNSIGNED,
-    in EntityID INT UNSIGNED,
-    in PropertyID INT UNSIGNED,
+    in DomainID VARCHAR(255),
+    in EntityID VARCHAR(255),
+    in PropertyID VARCHAR(255),
     in Datatable VARCHAR(255),
     in PropertyValue TEXT,
     in PropertyUnitSig BIGINT,
     in PropertyStatus VARCHAR(255),
     in NameOverride VARCHAR(255),
     in DescOverride TEXT,
-    in DatatypeOverride INT UNSIGNED,
+    in DatatypeOverride VARCHAR(255),
     in Collection VARCHAR(255),
     in PropertyIndex INT UNSIGNED)
 BEGIN
     DECLARE ReferenceValueIVersion INT UNSIGNED DEFAULT NULL;
     DECLARE ReferenceValue INT UNSIGNED DEFAULT NULL;
     DECLARE AT_PRESENT INTEGER DEFAULT NULL;
+    DECLARE InternalDataTypeID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalDomainID INT UNSIGNED DEFAULT 0;
+
+    SELECT internal_id INTO InternalDomainID FROM entity_ids WHERE id = DomainID;
+    -- When DomainID != 0 the EntityID could possibly be a 'replacement id'
+    -- which are internal ids by definition (and do not have external
+    -- equivalents).
+    IF LOCATE("$", EntityID) = 1 THEN
+        SET InternalEntityID=SUBSTRING(EntityID, 2);
+    ELSE
+        SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+    END IF;
+    IF LOCATE("$", PropertyID) = 1 THEN
+        SET InternalPropertyID=SUBSTRING(PropertyID, 2);
+    ELSE
+        SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id = PropertyID;
+    END IF;
 
     CASE Datatable
     WHEN 'double_data' THEN
         INSERT INTO double_data
         (domain_id, entity_id, property_id, value, unit_sig, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex);
     WHEN 'integer_data' THEN
         INSERT INTO integer_data
         (domain_id, entity_id, property_id, value, unit_sig, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex);
     WHEN 'datetime_data' THEN
         INSERT INTO datetime_data
         (domain_id, entity_id, property_id, value, value_ns, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, SUBSTRING_INDEX(PropertyValue, 'UTC', 1), IF(SUBSTRING_INDEX(PropertyValue, 'UTC', -1)='',NULL,SUBSTRING_INDEX(PropertyValue, 'UTC', -1)), PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, SUBSTRING_INDEX(PropertyValue, 'UTC', 1), IF(SUBSTRING_INDEX(PropertyValue, 'UTC', -1)='',NULL,SUBSTRING_INDEX(PropertyValue, 'UTC', -1)), PropertyStatus, PropertyIndex);
     WHEN 'reference_data' THEN
 
         -- special handling if versioning enabled and specific version of referenced entity is given.
         SET AT_PRESENT=LOCATE("@", PropertyValue);
         IF is_feature_config("ENTITY_VERSIONING", "ENABLED") AND AT_PRESENT > 0 THEN
-            SET ReferenceValue = SUBSTRING_INDEX(PropertyValue, '@', 1);
+            SELECT internal_id INTO ReferenceValue FROM entity_ids WHERE id = SUBSTRING_INDEX(PropertyValue, '@', 1);
             SET ReferenceValueIVersion = get_iversion(ReferenceValue,
                 SUBSTRING_INDEX(PropertyValue, '@', -1));
-            -- TODO raise error when @ present but iversion is null
             IF ReferenceValueIVersion IS NULL THEN
+                -- Raise error when @ present but iversion is null
                 SELECT 0 from `ReferenceValueIVersion_WAS_NULL`;
             END IF;
 
+        ELSEIF LOCATE("$", PropertyValue) = 1 THEN
+            SET ReferenceValue = SUBSTRING(PropertyValue, 2);
         ELSE
-            SET ReferenceValue = PropertyValue;
+            SELECT internal_id INTO ReferenceValue FROM entity_ids WHERE id = PropertyValue;
         END IF;
 
+
         INSERT INTO reference_data
             (domain_id, entity_id, property_id, value, value_iversion, status,
                 pidx)
         VALUES
-            (DomainID, EntityID, PropertyID, ReferenceValue,
+            (InternalDomainID, InternalEntityID, InternalPropertyID, ReferenceValue,
                 ReferenceValueIVersion, PropertyStatus, PropertyIndex);
     WHEN 'enum_data' THEN
         INSERT INTO enum_data
         (domain_id, entity_id, property_id, value, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex);
     WHEN 'date_data' THEN
         INSERT INTO date_data
         (domain_id, entity_id, property_id, value, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, SUBSTRING_INDEX(PropertyValue, '.', 1), PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, SUBSTRING_INDEX(PropertyValue, '.', 1), PropertyStatus, PropertyIndex);
     WHEN 'text_data' THEN
         INSERT INTO text_data
         (domain_id, entity_id, property_id, value, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex);
     WHEN 'null_data' THEN
         INSERT INTO null_data
         (domain_id, entity_id, property_id, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyStatus, PropertyIndex);
     WHEN 'name_data' THEN
         INSERT INTO name_data
         (domain_id, entity_id, property_id, value, status, pidx)
         VALUES
-        (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex);
+        (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex);
 
     ELSE
+        -- raise error
         SELECT * FROM table_does_not_exist;
     END CASE;
 
     IF DatatypeOverride IS NOT NULL THEN
-        call overrideType(DomainID, EntityID, PropertyID, DatatypeOverride);
+        SELECT internal_id INTO InternalDataTypeID from entity_ids WHERE id = DatatypeOverride;
+        call overrideType(InternalDomainID, InternalEntityID, InternalPropertyID, InternalDataTypeID);
         IF Collection IS NOT NULL THEN
-            INSERT INTO collection_type (domain_id, entity_id, property_id, collection) VALUES (DomainID, EntityID, PropertyID, Collection);
+            INSERT INTO collection_type (domain_id, entity_id, property_id, collection) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Collection);
         END IF;
     END IF;
 
     IF NameOverride IS NOT NULL THEN
-        call overrideName(DomainID, EntityID, PropertyID, NameOverride);
+        call overrideName(InternalDomainID, InternalEntityID, InternalPropertyID, NameOverride);
     END IF;
 
     IF DescOverride IS NOT NULL THEN
-        call overrideDesc(DomainID, EntityID, PropertyID, DescOverride);
+        call overrideDesc(InternalDomainID, InternalEntityID, InternalPropertyID, DescOverride);
     END IF;
 
 END;
diff --git a/procedures/insertFSODescriptor.sql b/procedures/insertFSODescriptor.sql
index 57060bff7177a57a094b4935ceed140e192bcf58..b29f91ad0873e2b80c3bc32b834fb1c8dd10694f 100644
--- a/procedures/insertFSODescriptor.sql
+++ b/procedures/insertFSODescriptor.sql
@@ -64,9 +64,15 @@ CREATE PROCEDURE db_5_0.insertFSODescriptor(
     IN FileMimeType VARCHAR(255),
     IN FileStorageId VARCHAR(255),
     IN FileKey VARCHAR(16000),
-    IN LinkTarget INT UNSIGNED)
+    IN LinkTarget VARCHAR(255))
 insertFSODescriptorBody: BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalParentID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalLinkTargetID INT UNSIGNED DEFAULT NULL;
 
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+    SELECT internal_id INTO InternalParentID FROM entity_ids WHERE id = FileParentID;
+    SELECT internal_id INTO InternalLinkTargetID FROM entity_ids WHERE id = LinkTarget;
     INSERT INTO files (
             file_id,
             hash,
@@ -79,7 +85,7 @@ insertFSODescriptorBody: BEGIN
             file_key,
             parent_directory,
             link_target
-        ) VALUES (EntityID, unhex(FileHash), FileHashAlgo, FileCheckedTimestamp, FileSize, FilePath, FileMimeType, FileStorageId, FileKey, FileParentID, LinkTarget);
+        ) VALUES (InternalEntityID, unhex(FileHash), FileHashAlgo, FileCheckedTimestamp, FileSize, FilePath, FileMimeType, FileStorageId, FileKey, InternalParentID, InternalLinkTargetID);
 
 END;
 //
diff --git a/procedures/insertIsaCache.sql b/procedures/insertIsaCache.sql
index 9d1bf1c529e8b33d33cd6c6eb794afc09e65dbea..f08ff610c9cb68fcfde4a305b770a3ba254f5329 100644
--- a/procedures/insertIsaCache.sql
+++ b/procedures/insertIsaCache.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DROP PROCEDURE IF EXISTS db_5_0.insertIsa;
 DELIMITER //
@@ -32,16 +30,22 @@ DELIMITER //
  *
  * Parameters
  * ==========
- * 
- * c : UNSIGNED
- * The child entity
- * 
- * p : UNSIGNED
- * The parent entity
+ *
+ * ChildID : VARCHAR(255)
+ *     The child entity.
+ *
+ * ParentID : VARCHAR(255)
+ *     The parent entity.
  */
-CREATE PROCEDURE db_5_0.insertIsa(IN c INT UNSIGNED, IN p INT UNSIGNED)
+CREATE PROCEDURE db_5_0.insertIsa(IN ChildID VARCHAR(255), IN ParentID VARCHAR(255))
 insert_is_a_proc: BEGIN
 
+    DECLARE c INT UNSIGNED DEFAULT NULL;
+    DECLARE p INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO c FROM entity_ids WHERE id = ChildID;
+    SELECT internal_id INTO p FROM entity_ids WHERE id = ParentID;
+
     INSERT INTO isa_cache (child, parent, rpath) VALUES (c, p, c);
 
     IF p = c THEN
@@ -69,17 +73,17 @@ insert_is_a_proc: BEGIN
     INSERT IGNORE INTO isa_cache SELECT
         l.child,    -- Descendant as found in isa_cache
         r.parent,   -- Ancestor as found in isa_cache
-        if(l.rpath=l.child and r.rpath=c,  -- if distance=1 for left and right:
+        IF(l.rpath=l.child AND r.rpath=c,  -- if distance=1 for left and right:
            c,                              -- rpath = current child
-           concat(if(l.rpath=l.child,        -- if dist=1 for descendant:
+           concat(IF(l.rpath=l.child,        -- if dist=1 for descendant:
                      c,                         -- rpath starts with c
                      concat(l.rpath, '>', c)),  -- rpath starts with "desc.rpath > c"
-                  if(r.rpath=c,              -- if dist=1 for ancestor
+                  IF(r.rpath=c,              -- if dist=1 for ancestor
                      '',                        -- rpath is finished
                      concat('>', r.rpath))))    -- rpath continuees with " > ancest.rpath"
             AS rpath
         FROM
-            isa_cache as l INNER JOIN isa_cache as r
+            isa_cache AS l INNER JOIN isa_cache AS r
             ON (l.parent = c AND c = r.child AND l.child != l.parent); -- Left: descendants of c, right: ancestors
 
 END;
diff --git a/procedures/insertUser.sql b/procedures/insertUser.sql
deleted file mode 100644
index 4f2f01eea78fd5190c7ab1fbf106fa435b0da2ef..0000000000000000000000000000000000000000
--- a/procedures/insertUser.sql
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-Drop Procedure if exists db_5_0.insertUser;
-Delimiter //
-Create Procedure db_5_0.insertUser(in Name VARCHAR(255), in Password VARCHAR(255))
-
-BEGIN 
-
-
-INSERT INTO entities (name, role, acl) VALUES (Name, 'USER', 0);
-
-SET @LAST_UserID = LAST_INSERT_ID();
-
-INSERT INTO passwords VALUES (@LAST_UserID, Password);
-
-Select @LAST_UserID as UserID; 
-
-END;
-//
-
-
-delimiter ;
diff --git a/procedures/isSubtype.sql b/procedures/isSubtype.sql
index f97c13f8f6ac75900ceca96e12cb285979a90a28..3a25612ef5121b4d644555e7a81b05f5ac0750b3 100644
--- a/procedures/isSubtype.sql
+++ b/procedures/isSubtype.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,18 +18,37 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
 DROP PROCEDURE IF EXISTS db_5_0.isSubtype;
 delimiter //
 
-CREATE PROCEDURE db_5_0.isSubtype(in c INT UNSIGNED, in p INT UNSIGNED)
+/*
+ * Return TRUE if the given Child is indeed a (direct or indirect) child of the
+ * given Parent.
+ *
+ * Parameters
+ * ----------
+ * ChildID : VARCHAR(255)
+ *     The entity id of the child.
+ * ParentID : VARCHAR(255)
+ *     The entity id of the parent.
+ *
+ * Returns
+ * -------
+ * ISA : BOOLEAN
+ */
+CREATE PROCEDURE db_5_0.isSubtype(in ChildID VARCHAR(255), in ParentID VARCHAR(255))
 BEGIN
-	DECLARE ret BOOLEAN DEFAULT FALSE;
-	SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1;
+    DECLARE c INT UNSIGNED DEFAULT NULL;
+    DECLARE p INT UNSIGNED DEFAULT NULL;
+    DECLARE ret BOOLEAN DEFAULT FALSE;
+
+    SELECT internal_id INTO c from entity_ids WHERE id = ChildID;
+    SELECT internal_id INTO p from entity_ids WHERE id = ParentID;
+
+    SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1;
     SELECT ret as ISA;
 END;
 //
diff --git a/procedures/listFSODescriptorByParentDirectory.sql b/procedures/listFSODescriptorByParentDirectory.sql
index c1f70e4c5b90f15295752c35028735d9b231a47d..902d23b62b34cfa454fe8104e07da5770734cceb 100644
--- a/procedures/listFSODescriptorByParentDirectory.sql
+++ b/procedures/listFSODescriptorByParentDirectory.sql
@@ -39,12 +39,15 @@ DROP PROCEDURE IF EXISTS db_5_0.listFSODescriptorByParentDirectory //
  *            LinkTarget)
  */
 CREATE PROCEDURE db_5_0.listFSODescriptorByParentDirectory(
-    IN ParentDirectory INT UNSIGNED)
+    IN ParentDirectory VARCHAR(255))
 listFSODescriptorByParentDirectoryBody: BEGIN
+    DECLARE InternalParentID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalParentID from entity_ids WHERE id = ParentDirectory;
 
     SELECT hash_algorithm AS FileHashAlgo,
-            file_id AS FileId,
-            parent_directory AS FileParentID,
+            (SELECT id FROM entity_ids WHERE internal_id = file_id) AS FileId,
+            ParentDirectory AS FileParentID,
             path AS FilePath,
             size AS FileSize,
             hex(hash) AS FileHash,
@@ -54,7 +57,7 @@ listFSODescriptorByParentDirectoryBody: BEGIN
             file_key AS FileKey,
             link_target AS LinkTarget
         FROM files
-        WHERE parent_directory = ParentDirectory;
+        WHERE parent_directory = InternalParentID;
 
 END;
 //
diff --git a/procedures/overrideName.sql b/procedures/overrideName.sql
index ace102b25a72f0f4159a0769efce4209449d5bc4..cbd74fd00de550630e8a402b048cbc242479389c 100644
--- a/procedures/overrideName.sql
+++ b/procedures/overrideName.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.overrideName;
@@ -26,21 +25,61 @@ DROP PROCEDURE IF EXISTS db_5_0.overrideDesc;
 DROP PROCEDURE IF EXISTS db_5_0.overrideType;
 
 DELIMITER //
-CREATE PROCEDURE db_5_0.overrideName(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Name VARCHAR(255))
+/*
+ * Insert a name override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * Name : VARCHAR(255)
+ */
+CREATE PROCEDURE db_5_0.overrideName(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Name VARCHAR(255))
 BEGIN
-	INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (DomainID, EntityID, PropertyID, Name);
+    INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Name);
 END;
 //
 
-CREATE PROCEDURE db_5_0.overrideDesc(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Description TEXT)
+/*
+ * Insert a description override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * Description : TEXT
+ */
+CREATE PROCEDURE db_5_0.overrideDesc(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Description TEXT)
 BEGIN
-	INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (DomainID, EntityID, PropertyID, Description);
+    INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Description);
 END;
 //
 
-CREATE PROCEDURE db_5_0.overrideType(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Datatype INT UNSIGNED)
+/*
+ * Insert a data type override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * InternalDatatypeID : INT UNSIGNED
+ *     The *internal* id of the data type.
+ */
+CREATE PROCEDURE db_5_0.overrideType(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in InternalDataTypeID INT UNSIGNED)
 BEGIN
-	INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (DomainID, EntityID, PropertyID, Datatype);
+    INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, InternalDataTypeID);
 END;
 //
 
diff --git a/procedures/query/applyIDFilter.sql b/procedures/query/applyIDFilter.sql
index b1c26b7ca63442c2d6b1b8dbc41fbb22d17f6d95..2b249471a0e70c673be1159eaffda7b0fa519ec2 100644
--- a/procedures/query/applyIDFilter.sql
+++ b/procedures/query/applyIDFilter.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.applyIDFilter;
@@ -32,71 +31,114 @@ DELIMITER //
  *
  * The `versioned` flag currently only has the effect that an `_iversion` column is also copied to
  * the target.
+ *
+ * Parameters
+ * ----------
+ * sourceSet : VARCHAR(255)
+ *     The name of the table from where we start.
+ * targetSet : VARCHAR(255)
+ *     The name of the table where we collect all the "good" ids (or NULL or same as sourceSet).
+ * o : CHAR(2)
+ *     The operator used for filtering, e.g. '=', '!=', '>', ...
+ * EntityID : VARCHAR(255)
+ *     An entity id, existing or non-existing, which we use to compare the
+ *     existing entities to using the operator.
+ * agg : CHAR(3)
+ *     An aggregate function, e.g. 'max' or 'min'. This only makes sense for number-based ids.
+ * versioned : BOOLEAN
+ *     The filter belongs to a version-aware query (e.g. FIND ANY VERSION OF
+ *     ...) and hence the sourceSet and targetSet have an `_iversion` column.
  */
 CREATE PROCEDURE db_5_0.applyIDFilter(in sourceSet VARCHAR(255), in targetSet VARCHAR(255),
-    in o CHAR(2), in vInt BIGINT, in agg CHAR(3), in versioned BOOLEAN)
+    in o CHAR(2), in EntityID VARCHAR(255), in agg CHAR(3), in versioned BOOLEAN)
 IDFILTER_LABEL: BEGIN
 DECLARE data VARCHAR(20000) DEFAULT NULL;
 DECLARE aggVal VARCHAR(255) DEFAULT NULL;
+DECLARE direction CHAR(4) DEFAULT NULL;
+DECLARE entity_id_type VARCHAR(255) DEFAULT "eids.id ";
 
 #-- get aggVal if possible
 IF agg IS NOT NULL THEN
     IF versioned THEN
         -- TODO versioned queries
         SELECT 1 FROM id_agg_with_versioning_not_implemented;
+    ELSEIF agg = "max" THEN
+        SET direction = "DESC";
+    ELSEIF agg = "min" THEN
+        SET direction = "ASC ";
+    ELSE
+        SELECT 1 FROM unknown_agg_parameter;
     END IF;
+
     SET @stmtIDAggValStr = CONCAT(
-        "SELECT ",
-        agg,
-        "(id) INTO @sAggVal FROM `",
+        "SELECT e.internal_id INTO @sAggVal FROM `",
         sourceSet,
-        "`");
+        "` AS s LEFT JOIN entity_ids AS e ON (s.id=e.internal_id) WHERE s.id>99 ORDER BY CAST(e.id AS UNSIGNED INT) ",
+        direction,
+        " LIMIT 1");
+
     PREPARE stmtIDAggVal FROM @stmtIDAggValStr;
     EXECUTE stmtIDAggVal;
     DEALLOCATE PREPARE stmtIDAggVal;
     SET aggVal = @sAggVal;
 END IF;
 
+IF o = ">" OR o = ">=" OR o = "<" or o = "<=" THEN
+    SET entity_id_type = "CAST(eids.id AS UNSIGNED INT) ";
+END IF;
+
 #-- generate stmt string
 IF targetSet IS NULL OR targetSet = sourceSet THEN
     SET data = CONCAT(
         "DELETE FROM `",
         sourceSet,
         "` WHERE ",
-        IF(o IS NULL OR vInt IS NULL,
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("NOT id",
+            CONCAT("NOT EXISTS (SELECT 1 FROM entity_ids AS eids WHERE ",
+                entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '" ',
+                " AND eids.internal_id = `",
+                sourceSet,
+                "`.id)"
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id!=",
+            CONCAT(" AND `", sourceSet, "`.id!=",
                 aggVal)));
 ELSEIF versioned AND sourceSet = "entities" THEN
-
     -- ################# VERSIONING #####################
     SET data = CONCAT(
         "INSERT IGNORE INTO `",
         targetSet,
-        '` (id, _iversion) SELECT id, _get_head_iversion(id) FROM `entities` WHERE ',
-        IF(o IS NULL OR vInt IS NULL,
+        '` (id, _iversion) SELECT e.id, _get_head_iversion(e.id) FROM `entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ',
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id=",
+            CONCAT(" AND e.id=",
                 aggVal)),
-        ' UNION SELECT id, _iversion FROM `archive_entities` WHERE ',
-        IF(o IS NULL OR vInt IS NULL,
+        ' UNION SELECT e.id, _iversion FROM `archive_entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ',
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id=",
+            CONCAT(" AND e.id=",
                 aggVal)));
     -- ##################################################
 
@@ -108,12 +150,15 @@ ELSE
             '` (id, _iversion) SELECT data.id, data._iversion FROM `',
             '` (id) SELECT data.id FROM `'),
         sourceSet,
-        "` AS data WHERE ",
-        IF(o IS NULL OR vInt IS NULL,
+        "` AS data JOIN entity_ids AS eids ON (eids.internal_id = data.id) WHERE ",
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("data.id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
             CONCAT(" AND data.id=",
diff --git a/procedures/query/applyPOV.sql b/procedures/query/applyPOV.sql
index 993ee9615a4e28f5351b20daf490c03c68baeac4..47532bca6b4e8a70ab7f24ba0fc5fa2bf371b76d 100644
--- a/procedures/query/applyPOV.sql
+++ b/procedures/query/applyPOV.sql
@@ -1,5 +1,4 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 /* Documentation including (?) has to be checked by an expert. */
@@ -37,30 +34,31 @@ DELIMITER //
  * ----------
  *
  * versioned : boolean
- *   If True, sourceSet and targetSet have an _iversion column, otherwise that column will be
-*    ignored (or only HEAD will be inserted into targetSet).
+ * If True, sourceSet and targetSet have an _iversion column, otherwise that column will be ignored
+ * (or only HEAD will be inserted into targetSet).
  */
-CREATE PROCEDURE db_5_0.applyPOV(in sourceSet VARCHAR(255), /* (?) Name of the table that the POV will be applied to. This can be a temporary table. */
-                                 in targetSet VARCHAR(255), /* (?) Name of the result table of this POV. */
+CREATE PROCEDURE db_5_0.applyPOV(in sourceSet VARCHAR(255), /* Name of the table that the POV will be applied to. This can be a temporary table or the `entities` table */
+                                 in targetSet VARCHAR(255), /* Name of the result table of this POV. After the filter has been applied this table only contains matching
+                                entity ids. This may be NULL or same as sourceSet. In that case the filter is applied in-place (delete non-matching). Otherwise the filter is applied by copying only the matching ids from the *source* set to the *target* set. */
                                  in propertiesTable VARCHAR(255),
-                                 in refIdsTable VARCHAR(255),
+                                 in refIdsTable VARCHAR(255), /* Name of a tmp table that contains all ids of children of the value interpreted as entity name or id */
                                  in o CHAR(4), /* The operator for this operation. can be one of:
                                                     0   check for "equals NULL"
                                                     !0  check for "not NULL"
                                                     ->  check whether a reference exists
-                                                    (   (?) check for datetime intervals
-                                                    !(  (?) check for being outside of datetime intervals
-                                                    other operators (all SQL operators (?))
+                                                    (   check for datetime interval (say "in")
+                                                    !(  check for being outside of datetime intervals (say "not in")
+                                                    other operators (all valid SQL operators)
                                                       these other operators can be used either with or without an aggregation
                                                       to use an aggregation set agg to non-zero
                                                       all SQL aggregations can be used
                                                */
-                                 in vText VARCHAR(255),  /* (?) the text value to be checked against using operator o */
+                                 in vText VARCHAR(255),  /* the text value to be checked against using operator o */
                                  in vInt INT,  /* the integer value to be checked against using operator o */
                                  in vDouble DOUBLE,  /* the double value to be checked against using operator o */
-                                 in unit_sig BIGINT,
+                                 in unit_sig BIGINT, /* signatur of the unit given by the user. used when we need to convert units. */
                                  in vDoubleStdUnit DOUBLE, /* The numeric value, converted according to the unit rules. */
-                                 in stdUnit_sig BIGINT,
+                                 in stdUnit_sig BIGINT, /* signatur of the normalized/standardized unit, e.g when unit_sig is "km/h" this might be "m/s". */
                                  in vDateTime VARCHAR(255),
                                  in vDateTimeDotNotation VARCHAR(255),
                                  in agg CHAR(3), /* an SQL aggregate function or NULL when no aggregation should be used */
@@ -84,6 +82,10 @@ POV_LABEL: BEGIN
     DECLARE keepTabl VARCHAR(255) DEFAULT NULL;
     DECLARE existence_op VARCHAR(255) DEFAULT "EXISTS";
 
+        #-- ######### HINT ##############
+        #-- first the appropriate statement is created which in the end prepared and executed
+        #-- #############################
+
     IF o = '->' THEN
         #-- special case: pure reference property
         call applyRefPOV(sourceSet,targetSet, propertiesTable, refIdsTable, versioned);
@@ -232,6 +234,8 @@ POV_LABEL: BEGIN
             IF o = "!=" AND refIdsTable IS NOT NULL THEN
                 SET existence_op = "NOT EXISTS";
             END IF;
+			/* select all entities that reference the entity or a child of the
+			 * value interpreted as ID*/
             SET sRefData = IF(vText IS NULL,
                 ' UNION ALL SELECT DISTINCT domain_id, entity_id, property_id FROM `reference_data`',
                 IF(refIdsTable IS NULL,
@@ -246,6 +250,7 @@ POV_LABEL: BEGIN
 
     END IF;
 
+    #-- create array of statement parts (and replace null with empty string) (?)
     SET data = CONCAT('(',sTextData,
                 IF(sNameData IS NULL, '', sNameData),
                 IF(sEnumData IS NULL, '', sEnumData),
@@ -262,6 +267,7 @@ POV_LABEL: BEGIN
     call createTmpTable(keepTabl, versioned);
     IF versioned THEN
         #-- generate statement from statement parts
+        #--  (versioned section)
         SET @stmtPOVkeepTblStr = CONCAT(
             'INSERT IGNORE INTO `', keepTabl, '` (id, _iversion) SELECT entity_id AS id, _iversion FROM ', data,
             ' as data', IF(propertiesTable IS NULL, '', CONCAT(
@@ -302,7 +308,14 @@ POV_LABEL: BEGIN
         DEALLOCATE PREPARE stmtPOVkeepTbl;
     ELSE
         #-- generate statement from statement parts
-        SET @stmtPOVkeepTblStr = CONCAT('INSERT IGNORE INTO `', keepTabl, '` (id) SELECT DISTINCT entity_id AS id FROM ', data, ' as data', IF(propertiesTable IS NULL, '', CONCAT(' WHERE EXISTS (Select 1 from `', propertiesTable, '` AS prop WHERE prop.id = data.property_id AND (prop.id2=data.entity_id OR prop.id2=0))')));
+        SET @stmtPOVkeepTblStr = CONCAT(
+            'INSERT IGNORE INTO `', keepTabl,
+            '` (id) SELECT DISTINCT entity_id AS id FROM ', data, ' as data',
+            IF(propertiesTable IS NULL, '',
+                CONCAT(' WHERE EXISTS (Select 1 from `', propertiesTable,
+                        '` AS prop WHERE prop.id = data.property_id AND
+                        (prop.id2=data.entity_id OR prop.id2=0))')));
+        #--  (unversioned section)
 
         SET @stmtPOVStr = CONCAT(
                 IF(targetSet IS NULL,
diff --git a/procedures/query/applyTransactionFilter.sql b/procedures/query/applyTransactionFilter.sql
index 7a428b0702352677826efce0cc60bb794415102d..89b22258646740f6e8cc6138256227a168f5cbfe 100644
--- a/procedures/query/applyTransactionFilter.sql
+++ b/procedures/query/applyTransactionFilter.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,37 +18,65 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DROP PROCEDURE IF EXISTS db_5_0.applyTransactionFilter;
 DELIMITER //
 
+
+/*
+ * Apply a transaction filter to the sourceSet and collect the remaining
+ * entities in the targetSet.
+ *
+ * Parameters
+ * ----------
+ * sourceSet : VARCHAR(255)
+ *     The name of the table from where we start.
+ * targetSet : VARCHAR(255)
+ *     The name of the table where we collect all the "good" ids (or NULL or same as sourceSet).
+ * transaction : VARCHAR(255)
+ *     The transaction's type (INSERT, UPDATE,...)
+ * operator_u : CHAR(2)
+ *     The operator used for filtering by the user, e.g. '=', '!='.
+ * realm : VARCHAR(255)
+ *     The user's realm (if filtering by the user).
+ * userName : VARCHAR(255)
+ *     The user's name (if filtering by the user).
+ * ilb : BIGINT
+ *     Inclusive Lower Bound of seconds for the transactions time.
+ * ilb_nanos : BIGINT
+ *     Inclusive Lower Bound of nanoseconds for the transactions time.
+ * eub : BIGINT
+ *     Exclusive Upper Bound of seconds for the transactions time.
+ * eub_nanos : BIGINT
+ *     Exclusive Upper Bound of nanoseconds for the transactions time.
+ * operator_t : CHAR(2)
+ *     The operator used for filtering by the transaction time, e.g. '=', '!=', '<', '>='.
+ */
 CREATE PROCEDURE db_5_0.applyTransactionFilter(in sourceSet VARCHAR(255), targetSet VARCHAR(255), in transaction VARCHAR(255), in operator_u CHAR(2), in realm VARCHAR(255), in userName VARCHAR(255), in ilb BIGINT, in ilb_nanos INT UNSIGNED, in eub BIGINT, in eub_nanos INT UNSIGNED, in operator_t CHAR(2))
 BEGIN
-	DECLARE data TEXT default CONCAT('(SELECT entity_id FROM transaction_log AS t WHERE t.transaction=\'', 
-		transaction, 
-		'\'',
-		IF(userName IS NOT NULL, 
-			CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'),
-			'' 
-		),
-		IF(ilb IS NOT NULL, 
-			CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)),
-			""
-		),
-		')'
-	);
+    DECLARE data TEXT default CONCAT("(SELECT internal_id AS entity_id FROM transaction_log AS t JOIN entity_ids AS eids ON ( t.entity_id = eids.id ) WHERE t.transaction='",
+        transaction,
+        "'",
+        IF(userName IS NOT NULL,
+            CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'),
+            ''
+        ),
+        IF(ilb IS NOT NULL,
+            CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)),
+            ""
+        ),
+        ')'
+    );
 
-	SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE);
-	PREPARE stmtTransactionFilter from @stmtTransactionStr;
-	IF userName IS NOT NULL THEN
-		SET @userName = userName;
-		SET @realm = realm;
-		EXECUTE stmtTransactionFilter USING @realm, @userName;
-	ELSE
-		EXECUTE stmtTransactionFilter;
-	END IF;
+    SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE);
+    PREPARE stmtTransactionFilter from @stmtTransactionStr;
+    IF userName IS NOT NULL THEN
+        SET @userName = userName;
+        SET @realm = realm;
+        EXECUTE stmtTransactionFilter USING @realm, @userName;
+    ELSE
+        EXECUTE stmtTransactionFilter;
+    END IF;
 
 END;
 //
diff --git a/procedures/query/initBackReference.sql b/procedures/query/initBackReference.sql
index c425dbcc6ec6c20e9b5cb2e73c0b6e1dedad1cf0..2999fb999615ffc47879dfda2a9f89e6b2b387d5 100644
--- a/procedures/query/initBackReference.sql
+++ b/procedures/query/initBackReference.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,27 +18,52 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.initBackReference;
 DELIMITER //
-CREATE PROCEDURE db_5_0.initBackReference(in pid INT UNSIGNED, in pname VARCHAR(255), in entity_id INT UNSIGNED, in ename VARCHAR(255))
+
+/*
+ * Create and initialize two new temporary tables.
+ *
+ * This is used to initialize the filterin for backreferences to a
+ * particular entity (specified by EntityID or EntityName) or using a
+ * particular property (specified by PropertyID or PropertyName).
+ *
+ * The propertiesTable contains all properties matching the PropertyID or
+ * PropertyName. The entitiesTable contains all entities matching EntityID or
+ * EntityName.
+
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ * EntityID : VARCHAR(255)
+ *     The entity's (external) id.
+ * EntityName : VARCHAR(255)
+ *     The entity's name.
+ *
+ * Select
+ * ------
+ * Tuple (propertiesTable, entitiesTable)
+ */
+CREATE PROCEDURE db_5_0.initBackReference(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in EntityID VARCHAR(255), in EntityName VARCHAR(255))
 BEGIN
     DECLARE propertiesTable VARCHAR(255) DEFAULT NULL;
     DECLARE entitiesTable VARCHAR(255) DEFAULT NULL;
 
-    IF pname IS NOT NULL THEN
+    IF PropertyName IS NOT NULL THEN
         -- TODO versioning for properties
         call createTmpTable(propertiesTable, FALSE);
-        call initSubEntity(pid, pname, propertiesTable);
+        call initSubEntity(PropertyID, PropertyName, propertiesTable);
     END IF;
 
-    IF ename IS NOT NULL THEN
+    IF EntityName IS NOT NULL THEN
         -- TODO versioning for referencing entities
         call createTmpTable(entitiesTable, FALSE);
-        call initSubEntity(entity_id, ename, entitiesTable);
+        call initSubEntity(EntityID, EntityName, entitiesTable);
     END IF;
 
     SELECT propertiesTable, entitiesTable;
diff --git a/procedures/query/initEntity.sql b/procedures/query/initEntity.sql
index 65d03b818f68991acabd82890c1730572ecc822c..d63c7773867cb9e5c29bdc4f95cbe866c3b426c4 100644
--- a/procedures/query/initEntity.sql
+++ b/procedures/query/initEntity.sql
@@ -30,7 +30,7 @@ DELIMITER //
  * If `versioned` is `TRUE`, also add archived entities (for example if the name was changed in the
  * past).
  */
-CREATE PROCEDURE db_5_0.initEntity(in eid INT UNSIGNED, in ename VARCHAR(255),
+CREATE PROCEDURE db_5_0.initEntity(in eid VARCHAR(255), in ename VARCHAR(255),
                                    in enameLike VARCHAR(255), in enameRegexp VARCHAR(255),
                                    in resultset VARCHAR(255), in versioned BOOLEAN)
 initEntityLabel: BEGIN
@@ -78,9 +78,9 @@ initEntityLabel: BEGIN
             'INSERT IGNORE INTO `',
             resultset,
             IF(versioned,
-                '` (id, _iversion) SELECT id, _get_head_iversion(id) ',
-                '` (id) SELECT id '),
-            'FROM entities WHERE id=',eid,';');
+                '` (id, _iversion) SELECT eids.internal_id, _get_head_iversion(eids.internal_id) ',
+                '` (id) SELECT eids.internal_id '),
+            'FROM entity_ids AS eids WHERE eids.id=',eid,';');
         PREPARE initEntityStmt FROM @initEntityStmtStr;
         EXECUTE initEntityStmt;
         DEALLOCATE PREPARE initEntityStmt;
diff --git a/procedures/query/initPOV.sql b/procedures/query/initPOV.sql
index 52d6a26279c1d25cd605c3a1883db31bf6326150..2afdc9cdfc77906725a24ab593151e0ee7834e02 100644
--- a/procedures/query/initPOV.sql
+++ b/procedures/query/initPOV.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,15 +18,32 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DELIMITER //
 
 
 DROP PROCEDURE IF EXISTS db_5_0.initPOVPropertiesTable//
 
-CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in pid INT UNSIGNED, in pname VARCHAR(255), in sourceSet VARCHAR(255))
+/*
+ * Create and initialize a new temporary table.
+ *
+ * This is used to initialize the POV filtering. The resulting table
+ * contains all properties matching the Property component of the POV filter.
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ * sourceSet : VARCHAR(255)
+ *     The name of the table which will be filtered by the POV filter.
+ *
+ * Select
+ * ------
+ * Tuple (propertiesTable, ... and a lot of debug output)
+ */
+CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in sourceSet VARCHAR(255))
 BEGIN
     DECLARE propertiesTable VARCHAR(255) DEFAULT NULL; /*table for property ids*/
     DECLARE replTbl VARCHAR(255) DEFAULT NULL;
@@ -38,24 +56,31 @@ BEGIN
     DECLARE t6 BIGINT DEFAULT 0;
 
 
-    IF pname is NOT NULL THEN 
+    IF PropertyName is NOT NULL THEN 
         SELECT conv( concat( substring(uid,16,3), substring(uid,10,4), substring(uid,1,8)),16,10) div 10000 - (141427 * 24 * 60 * 60 * 1000) as current_mills INTO t1 from (select uuid() uid) as alias;
         call createTmpTable2(propertiesTable);
 
-        -- fill in all properties named "pname"
+        -- Fill in all properties (plus the domain id and entity id) named
+        -- "PropertyName", be it their default name or their overridden name.
+        -- We need *all* properties (mind, the properties of entities not
+        -- abstract properties) with the given name. If an abstract
+        -- property has the name "person" it might have the name "author" in
+        -- the "Article" record type. Now, if I want to collect all properties
+        -- of the Article named "author" I need to look into the name_overrides
+        -- table.
         SET @initPOVPropertiesTableStmt1 = CONCAT('INSERT IGNORE INTO `', propertiesTable, '` (id, id2, domain) SELECT property_id, entity_id, domain_id from name_overrides WHERE name = ? UNION ALL SELECT entity_id, domain_id, 0 FROM name_data WHERE value = ?;');
         PREPARE stmt FROM @initPOVPropertiesTableStmt1;
-        SET @pname = pname;
-        EXECUTE stmt USING @pname, @pname;
+        SET @PropertyName = PropertyName;
+        EXECUTE stmt USING @PropertyName, @PropertyName;
         SET ecount = ROW_COUNT();
 
-        -- fill in all properties with id="pid"
+        -- fill in all properties with id="PropertyID"
         SELECT conv( concat( substring(uid,16,3), substring(uid,10,4), substring(uid,1,8)),16,10) div 10000 - (141427 * 24 * 60 * 60 * 1000) as current_mills INTO t2 from (select uuid() uid) as alias;
-        IF pid IS NOT NULL THEN
+        IF PropertyID IS NOT NULL THEN
             SET @initPOVPropertiesTableStmt2 = CONCAT('INSERT IGNORE INTO `', propertiesTable, '` (id, id2, domain) VALUES (?, 0, 0)');
             PREPARE stmt FROM @initPOVPropertiesTableStmt2;
-            SET @pid = pid;
-            EXECUTE stmt USING @pid;
+            SET @PropertyID = PropertyID;
+            EXECUTE stmt USING @PropertyID;
             SET ecount = ecount + ROW_COUNT();
         END IF;
 
@@ -91,15 +116,33 @@ END //
 
 DROP PROCEDURE IF EXISTS db_5_0.initPOVRefidsTable //
 
-CREATE PROCEDURE db_5_0.initPOVRefidsTable(in vInt INT UNSIGNED, in vText VARCHAR(255))
+/*
+ * Create and initialize a new temporary table.
+ *
+ * This used to initialize the POV filtering. The resulting table
+ * contains all entities matching the Value component of the POV filter (i.e.
+ * the referenced entities).
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ *
+ * Select
+ * ------
+ * Tuple (refIdsTable)
+ */
+CREATE PROCEDURE db_5_0.initPOVRefidsTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255))
 BEGIN
     DECLARE refIdsTable VARCHAR(255) DEFAULT NULL; /*table for referenced entity ids*/
 
     #-- for reference properties: the value is interpreted as a record type name.
-    IF vText IS NOT NULL THEN
+    IF PropertyName IS NOT NULL THEN
         -- TODO versioned queries
         call createTmpTable(refIdsTable, FALSE);
-        call initSubEntity(vInt, vText, refIdsTable);
+        call initSubEntity(PropertyID, PropertyName, refIdsTable);
         #-- now, all ids are in the refIdsTable
     END IF;
     SELECT refIdsTable;
diff --git a/procedures/query/initSubEntity.sql b/procedures/query/initSubEntity.sql
index a2f5ea67e495e4cc8cc52f0248389bc44792451f..d542b3387a9aa8a1c23c5db74d459a3c51861ccf 100644
--- a/procedures/query/initSubEntity.sql
+++ b/procedures/query/initSubEntity.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,20 +18,35 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
 DROP PROCEDURE IF EXISTS db_5_0.initSubEntity;
 
 DELIMITER //
-
-CREATE PROCEDURE db_5_0.initSubEntity(in e_id INT UNSIGNED, in ename VARCHAR(255), in tableName VARCHAR(255))
+/*
+ * Initialize a new temporary table by loading an entity (by name or by id or
+ * both) and all of its children into the table (i.e. their internal ids).
+ *
+ * The table name has to be provided.
+ *
+ * This is used by initPOVRefidsTable and initBackReference for sub-property filtering.
+ *
+ * Parameters
+ * ----------
+ * EntityID : VARCHAR(255)
+ *     The entity's (external) id.
+ * EntityName : VARCHAR(255)
+ *     The entity's name.
+ * tableName : VARCHAR(255)
+ *     The table which is to be initialized.
+ */
+CREATE PROCEDURE db_5_0.initSubEntity(in EntityID VARCHAR(255), in ename VARCHAR(255), in tableName VARCHAR(255))
 BEGIN
     DECLARE ecount INT DEFAULT 0;
     DECLARE op VARCHAR(255) DEFAULT '=';
 
+
     IF LOCATE("%", ename) > 0 THEN
         SET op = "LIKE";
     END IF;
@@ -47,10 +63,11 @@ BEGIN
     SET ecount = ROW_COUNT();
     DEALLOCATE PREPARE stmt;
 
-    IF e_id IS NOT NULL THEN
-        SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) VALUES (', e_id, ')');
+    IF EntityID IS NOT NULL THEN
+        SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) SELECT internal_id FROM entity_ids WHERE id = ?');
         PREPARE stmt FROM @stmtStr;
-        EXECUTE stmt;
+        SET @eid = EntityID;
+        EXECUTE stmt USING @eid;
         SET ecount = ecount + ROW_COUNT();
         DEALLOCATE PREPARE stmt;
     END IF;
diff --git a/procedures/registerSubdomain.sql b/procedures/registerReplacementIds.sql
similarity index 70%
rename from procedures/registerSubdomain.sql
rename to procedures/registerReplacementIds.sql
index 4cb18e46be422e6cc65db5b33913cf06b77c18d2..fed8835d632c3334771318e29640a0ba5d425833 100644
--- a/procedures/registerSubdomain.sql
+++ b/procedures/registerReplacementIds.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <www.indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,33 +18,25 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
-
-
-
-
-
-
-
-
 DROP PROCEDURE IF EXISTS db_5_0.registerSubdomain;
+DROP PROCEDURE IF EXISTS db_5_0.registerReplacementIds;
 delimiter //
 
-CREATE PROCEDURE db_5_0.registerSubdomain(in amount INT UNSIGNED)
+CREATE PROCEDURE db_5_0.registerReplacementIds(in amount INT UNSIGNED)
 BEGIN
     DECLARE ED INTEGER DEFAULT NULL;
 
-    SELECT COUNT(id) INTO ED FROM entities WHERE Role='DOMAIN' AND id!=0;
+    SELECT COUNT(id) INTO ED FROM entities WHERE Role='_REPLACEMENT' AND id!=0;
 
     WHILE ED < amount DO
         INSERT INTO entities (description, role, acl) VALUES
-            (NULL, 'DOMAIN', 0);
+            (NULL, '_REPLACEMENT', 0);
+
         SET ED = ED + 1;
     END WHILE;
 
-    SELECT id as DomainID FROM entities WHERE Role='DOMAIN' and id!=0;
+    SELECT CONCAT("$", e.id) as ReplacementID FROM entities AS e WHERE e.Role='_REPLACEMENT' and e.id!=0;
 
 END;
 //
diff --git a/procedures/retrieveDatatype.sql b/procedures/retrieveDatatype.sql
deleted file mode 100644
index c0ed52c30ffd506d9f0a214d2b59fd4691c4c510..0000000000000000000000000000000000000000
--- a/procedures/retrieveDatatype.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-
-
-
-
-
-DROP PROCEDURE IF EXISTS db_5_0.retrieveDatatype;
-delimiter //
-CREATE PROCEDURE db_5_0.retrieveDatatype(in DatatypeName VARCHAR(255))
-BEGIN
-
-Select e.id INTO @DatatypeID from entities e where e.name=DatatypeName AND e.role='DATATYPE' LIMIT 1;
-
-call retrieveEntity(@DatatypeID);
-
-
-
-
-END;
-//
-delimiter ;
diff --git a/procedures/retrieveEntity.sql b/procedures/retrieveEntity.sql
index 5ae6b6623ada2765ba0d4923b6426a51adec3443..a2b6b12a7ca9b448100b435c431bdbcb779aa5b2 100644
--- a/procedures/retrieveEntity.sql
+++ b/procedures/retrieveEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -36,27 +33,27 @@ drop procedure if exists db_5_0.retrieveEntity //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity's id.
- * Version
+ * Version : VARBINARY(255)
  *   The version id.  In this procedure only, the version may also be given as
  *   `HEAD` for the latest version or as `HEAD~n`, which retrieves the n-th
  *   ancestor of `HEAD`.
  *
  * ResultSet
  * ---------
- * Tuple of (DatatypeID, Collection, EntityID, EntityName, EntityDesc,
- *           EntityRole, FileSize, FilePath, FileHash, FileHashAlgo,
- *           FileHashChecked, FileMimeType, FileStorageID, FileKey,
- *           FileParentID, LinkTarget, ACL, Version)
+ * Tuple of (DatatypeID, DatatypeName, Collection, EntityID, EntityName,
+ *           EntityDesc, EntityRole, FileSize, FilePath, FileHash,
+ *           FileHashAlgo, FileHashChecked, FileMimeType, FileStorageID,
+ *           FileKey, FileParentID, ACL, Version, LinkTarget)
  */
 create procedure db_5_0.retrieveEntity(
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveEntityBody: BEGIN
-    DECLARE LinkTarget INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalLinkTargetID INT UNSIGNED DEFAULT NULL;
     DECLARE FilePath VARCHAR(15920) DEFAULT NULL;
-    DECLARE FileParentID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalParentDirID INT UNSIGNED DEFAULT NULL;
     DECLARE FileSize BIGINT UNSIGNED DEFAULT NULL;
     DECLARE FileHash VARCHAR(255) DEFAULT NULL;
     DECLARE FileHashAlgo VARCHAR(255) DEFAULT NULL;
@@ -64,11 +61,20 @@ retrieveEntityBody: BEGIN
     DECLARE FileMimeType VARBINARY(255) DEFAULT NULL;
     DECLARE FileStorageID VARBINARY(255) DEFAULT NULL;
     DECLARE FileKey VARBINARY(15920) DEFAULT NULL;
-    DECLARE DatatypeID INT UNSIGNED DEFAULT NULL;
+    DECLARE DatatypeID VARCHAR(255) DEFAULT NULL;
+    DECLARE InternalDatatypeID INT UNSIGNED DEFAULT NULL;
     DECLARE CollectionName VARCHAR(255) DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
+    IF InternalEntityID IS NULL THEN
+        -- RETURN EARLY - Entity does not exist.
+        SELECT 0 FROM entities WHERE 0 = 1;
+        LEAVE retrieveEntityBody;
+    END IF;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         -- Find out head-ness and version
@@ -82,7 +88,7 @@ retrieveEntityBody: BEGIN
         END IF;
 
         IF IsHead IS FALSE THEN
-            SET IVersion=get_iversion(EntityID, Version);
+            SET IVersion=get_iversion(InternalEntityID, Version);
 
             IF IVersion IS NULL THEN
                 -- RETURN EARLY - Version does not exist.
@@ -91,18 +97,18 @@ retrieveEntityBody: BEGIN
             END IF;
 
             SELECT path, parent_directory, size, hex(hash), hash_algorithm, checked_timestamp,  mimetype, file_storage_id, file_key, link_target
-                INTO FilePath, FileParentID, FileSize, FileHash, FileHashAlgo, FileHashChecked, FileMimeType, FileStorageID, FileKey, LinkTarget
+                INTO FilePath, InternalParentDirID, FileSize, FileHash, FileHashAlgo, FileHashChecked, FileMimeType, FileStorageID, FileKey, InternalLinkTargetID
                 FROM archive_files
-                WHERE file_id = EntityID
+                WHERE file_id = InternalEntityID
                 AND _iversion = IVersion
                 LIMIT 1;
 
             SELECT datatype
-                INTO DatatypeID
+                INTO InternalDatatypeID
                 FROM archive_data_type
                 WHERE domain_id = 0
                 AND entity_id = 0
-                AND property_id = EntityID
+                AND property_id = InternalEntityID
                 AND _iversion = IVersion
                 LIMIT 1;
 
@@ -111,7 +117,7 @@ retrieveEntityBody: BEGIN
                 FROM archive_collection_type
                 WHERE domain_id = 0
                 AND entity_id = 0
-                AND property_id = EntityID
+                AND property_id = InternalEntityID
                 AND _iversion = IVersion
                 LIMIT 1;
 
@@ -120,15 +126,15 @@ retrieveEntityBody: BEGIN
                 ( SELECT value FROM
                     ( SELECT value FROM name_data
                         WHERE domain_id = 0
-                        AND entity_ID = DatatypeID
+                        AND entity_id = InternalDatatypeID
                         AND property_id = 20
-                        UNION SELECT DatatypeID AS value
-                    ) AS tmp LIMIT 1 ) AS Datatype,
+                    ) AS tmp LIMIT 1 ) AS DatatypeName,
+                ( SELECT id FROM entity_ids WHERE internal_id=InternalDatatypeID ) AS DatatypeID,
                 CollectionName AS Collection,
                 EntityID AS EntityID,
                 ( SELECT value FROM archive_name_data
                     WHERE domain_id = 0
-                    AND entity_ID = EntityID
+                    AND entity_ID = InternalEntityID
                     AND property_id = 20
                     AND _iversion = IVersion
                     ) AS EntityName,
@@ -144,7 +150,7 @@ retrieveEntityBody: BEGIN
                 (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL,
                 Version AS Version
             FROM archive_entities AS e
-            WHERE e.id = EntityID
+            WHERE e.id = InternalEntityID
             AND e._iversion = IVersion
             LIMIT 1;
 
@@ -155,35 +161,36 @@ retrieveEntityBody: BEGIN
     END IF;
 
     SELECT path, parent_directory, size, hex(hash), hash_algorithm, checked_timestamp, mimetype, file_storage_id, file_key, link_target
-        INTO FilePath, FileParentID, FileSize, FileHash, FileHashAlgo, FileHashChecked, FileMimeType, FileStorageID, FileKey, LinkTarget
+        INTO FilePath, InternalParentDirID, FileSize, FileHash, FileHashAlgo, FileHashChecked, FileMimeType, FileStorageID, FileKey, InternalLinkTargetID
         FROM files
-        WHERE file_id = EntityID
+        WHERE file_id = InternalEntityID
         LIMIT 1;
 
-    SELECT datatype INTO DatatypeID
-        FROM data_type
-        WHERE domain_id=0
-        AND entity_id=0
-        AND property_id=EntityID
+    SELECT dt.datatype INTO InternalDatatypeID
+        FROM data_type as dt
+        WHERE dt.domain_id=0
+        AND dt.entity_id=0
+        AND dt.property_id=InternalEntityID
         LIMIT 1;
 
     SELECT collection INTO CollectionName
         FROM collection_type
         WHERE domain_id=0
         AND entity_id=0
-        AND property_id=EntityID
+        AND property_id=InternalEntityID
         LIMIT 1;
 
     SELECT
         ( SELECT value FROM name_data
             WHERE domain_id = 0
-            AND entity_ID = DatatypeID
-            AND property_id = 20 LIMIT 1 ) AS Datatype,
+            AND entity_id = InternalDatatypeID
+            AND property_id = 20 LIMIT 1 ) AS DatatypeName,
+        ( SELECT id FROM entity_ids WHERE internal_id=InternalDatatypeID ) AS DatatypeID,
         CollectionName AS Collection,
         EntityID AS EntityID,
         ( SELECT value FROM name_data
             WHERE domain_id = 0
-            AND entity_ID = EntityID
+            AND entity_ID = InternalEntityID
             AND property_id = 20 LIMIT 1) AS EntityName,
         e.description AS EntityDesc,
         e.role AS EntityRole,
@@ -195,11 +202,11 @@ retrieveEntityBody: BEGIN
         FileMimeType AS FileMimeType,
         FileStorageID AS FileStorageID,
         FileKey AS FileKey,
-        FileParentID AS FileParentID,
-        LinkTarget AS LinkTarget,
+        (SELECT id FROM entity_ids WHERE internal_id = InternalParentDirID) AS FileParentID,
+        (SELECT id FROM entity_ids WHERE internal_id = InternalLinkTargetID) AS LinkTarget,
         (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL,
         Version AS Version
-    FROM entities e WHERE id = EntityID LIMIT 1;
+    FROM entities e WHERE id = InternalEntityID LIMIT 1;
 END;
 //
 
diff --git a/procedures/retrieveEntityACL.sql b/procedures/retrieveEntityACL.sql
index 5e0958b5449b3e3f4279a565b87d45cf6772cf37..e7833d24199165755bac27468aafc2c6dd8c3f80 100644
--- a/procedures/retrieveEntityACL.sql
+++ b/procedures/retrieveEntityACL.sql
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2022 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2022 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,7 +19,6 @@
  */
 
 
-
 DELIMITER //
 
 DROP PROCEDURE IF EXISTS db_5_0.retrieveEntityACL //
@@ -29,7 +28,7 @@ DROP PROCEDURE IF EXISTS db_5_0.retrieveEntityACL //
  *
  * Parameters
  * ----------
- * EntityID : INT UNSIGNED
+ * EntityID : VARCHAR(255)
  *   The entity's id.
  *
  * ResultSet
@@ -40,7 +39,7 @@ CREATE PROCEDURE db_5_0.retrieveEntityACL(
     IN EntityID INT UNSIGNED)
 retrieveEntityACLBody: BEGIN
 
-    SELECT a.acl AS ACL FROM entity_acl AS a JOIN entities AS e ON (e.acl = a.id) WHERE e.id = EntityID;
+    SELECT a.acl AS ACL FROM entity_acl AS a JOIN entities AS e ON (e.acl = a.id) JOIN entity_ids as eids ON (e.id = eids.internal_id) WHERE eids.id = EntityID;
 
 END;
 //
diff --git a/procedures/retrieveEntityOverrides.sql b/procedures/retrieveEntityOverrides.sql
index 696447527b8c05f3b9aa57193a26c3d8fa48c874..4852cccbb85ce4857c43e715183c7065e44b84e7 100644
--- a/procedures/retrieveEntityOverrides.sql
+++ b/procedures/retrieveEntityOverrides.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 Indiscale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 Indiscale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,25 +18,61 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.retrieveOverrides;
 delimiter //
 
+/*
+ * Retrieve the overridden (overriding the Abstract Property's) name, description, and datatype.
+ *
+ * Parameters
+ * ----------
+ *
+ * DomainID : VARCHAR(255)
+ *     The domain id (0 or the entity'id for level-2-data)
+ * EntityID : VARCHAR(255)
+ *     The entity id (or the property'id for level-2-data)
+ * Version : VARBINARY(255)
+ *     The version of the entity. Optional
+ *
+ * ResultSet
+ * ---------
+ * collection_override, # e.g. LIST
+ * name_override,       # the name
+ * desc_override,       # the description
+ * type_name_override,  # the datatype, e.g. DOUBLE
+ * type_id_override,    # data type id.
+ * entity_id,           # same as input EntityID
+ * InternalPropertyID,  # internal property id, to be used when property_id
+ *                      # is NULL because a replacement is used.
+ * property_id,         # the property id
+ */
 CREATE PROCEDURE db_5_0.retrieveOverrides(
-    in DomainID INT UNSIGNED,
-    in EntityID INT UNSIGNED,
+    in DomainID VARCHAR(255),
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveOverridesBody: BEGIN
 
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalDomainID INT UNSIGNED DEFAULT 0;
+
+    -- When DomainID != 0 the EntityID could possibly be a 'replacement id'
+    -- which are internal ids by definition (and do not have external
+    -- equivalents).
+    IF LOCATE("$", EntityID) = 1 THEN
+        SET InternalEntityID=SUBSTRING(EntityID, 2);
+    ELSE
+        SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+    END IF;
+    -- DomainID != 0 are always normal (i.e. external) Entity ids.
+    SELECT internal_id INTO InternalDomainID from entity_ids WHERE id = DomainID;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         IF Version IS NOT NULL THEN
-            IF DomainID = 0 THEN
+            IF InternalDomainID = 0 THEN
                 SELECT get_head_version(EntityID) = Version INTO IsHead;
             ELSE
                 SELECT get_head_version(DomainID) = Version INTO IsHead;
@@ -47,8 +82,8 @@ retrieveOverridesBody: BEGIN
         IF IsHead IS FALSE THEN
             SELECT e._iversion INTO IVersion
                 FROM entity_version as e
-                WHERE ((e.entity_id = EntityID AND DomainID = 0)
-                    OR (e.entity_id = DomainID))
+                WHERE ((e.entity_id = InternalEntityID AND InternalDomainID = 0)
+                    OR (e.entity_id = InternalDomainID))
                 AND e.version = Version;
 
             IF IVersion IS NULL THEN
@@ -61,12 +96,14 @@ retrieveOverridesBody: BEGIN
                 NULL AS collection_override,
                 name AS name_override,
                 NULL AS desc_override,
-                NULL AS type_override,
-                entity_id,
-                property_id
+                NULL AS type_name_override,
+                NULL AS type_id_override,
+                EntityID AS entity_id,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
             FROM archive_name_overrides
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
@@ -76,12 +113,14 @@ retrieveOverridesBody: BEGIN
                 NULL AS collection_override,
                 NULL AS name_override,
                 description AS desc_override,
-                NULL AS type_override,
-                entity_id,
-                property_id
+                NULL AS type_name_override,
+                NULL AS type_id_override,
+                EntityID AS entity_id,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
             FROM archive_desc_overrides
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
@@ -91,16 +130,18 @@ retrieveOverridesBody: BEGIN
                 NULL AS collection_override,
                 NULL AS name_override,
                 NULL AS desc_override,
-                IFNULL((SELECT value FROM name_data
+                (SELECT value FROM name_data
                     WHERE domain_id = 0
                     AND entity_id = datatype
                     AND property_id = 20
-                    LIMIT 1), datatype) AS type_override,
-                entity_id,
-                property_id
+                    LIMIT 1) AS type_name_override,
+                (SELECT id FROM entity_ids WHERE internal_id = datatype) AS type_id_override,
+                EntityID AS entity_id,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
             FROM archive_data_type
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
@@ -110,12 +151,14 @@ retrieveOverridesBody: BEGIN
                 collection AS collection_override,
                 NULL AS name_override,
                 NULL AS desc_override,
-                NULL AS type_override,
-                entity_id,
-                property_id
+                NULL AS type_name_override,
+                NULL AS type_id_override,
+                EntityID AS entity_id,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
             FROM archive_collection_type
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion;
 
             LEAVE retrieveOverridesBody;
@@ -126,12 +169,14 @@ retrieveOverridesBody: BEGIN
         NULL AS collection_override,
         name AS name_override,
         NULL AS desc_override,
-        NULL AS type_override,
-        entity_id,
-        property_id
+        NULL AS type_name_override,
+        NULL AS type_id_override,
+        EntityID AS entity_id,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
     FROM name_overrides
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
@@ -139,12 +184,14 @@ retrieveOverridesBody: BEGIN
         NULL AS collection_override,
         NULL AS name_override,
         description AS desc_override,
-        NULL AS type_override,
-        entity_id,
-        property_id
+        NULL AS type_name_override,
+        NULL AS type_id_override,
+        EntityID AS entity_id,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
     FROM desc_overrides
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
@@ -152,15 +199,17 @@ retrieveOverridesBody: BEGIN
         NULL AS collection_override,
         NULL AS name_override,
         NULL AS desc_override,
-        IFNULL((SELECT value FROM name_data
+        (SELECT value FROM name_data
             WHERE domain_id = 0
             AND entity_ID = datatype
-            AND property_id = 20 LIMIT 1), datatype) AS type_override,
-        entity_id,
-        property_id
+            AND property_id = 20 LIMIT 1) AS type_name_override,
+        (SELECT id FROM entity_ids WHERE internal_id = datatype) AS type_id_override,
+        EntityID AS entity_id,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
     FROM data_type
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
@@ -168,12 +217,14 @@ retrieveOverridesBody: BEGIN
         collection AS collection_override,
         NULL AS name_override,
         NULL AS desc_override,
-        NULL AS type_override,
-        entity_id,
-        property_id
+        NULL AS type_name_override,
+        NULL AS type_id_override,
+        EntityID AS entity_id,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
     FROM collection_type
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID;
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID;
 
 
 END;
diff --git a/procedures/retrieveEntityParents.sql b/procedures/retrieveEntityParents.sql
index 12b5c287881d2c10ee591986a654d974ac1feecc..6fa29054ff15869be035515a5556beb78ab9d66c 100644
--- a/procedures/retrieveEntityParents.sql
+++ b/procedures/retrieveEntityParents.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -28,37 +25,35 @@ DROP PROCEDURE IF EXISTS db_5_0.retrieveEntityParents;
 DELIMITER //
 
 /* Retrieve the parents of an Entity.
-
-Parameters
-==========
-
-EntityID : UNSIGNED
-Child entity for which all parental relations should be deleted.
-
-Returns
-=======
-ParentID : INT UNSIGNED
-  Each parent's ID
-
-ParentName :
-  The parent's name.
-
-ParentDescription :
-  The parent's description.
-
-ParentRole :
-  The parent's Role.
-
-ACL :
-  Access control list something
+ *
+ * Parameters
+ * ----------
+ * EntityID : VARCHAR(255)
+ *     Child entity for which all parental relations should be deleted.
+ *
+ * ResultSet
+ * ---------
+ * ParentID : VARCHAR(255)
+ *   Each parent's ID
+ * ParentName : VARCHAR(255)
+ *   The parent's name.
+ * ParentDescription : TEXT
+ *   The parent's description.
+ * ParentRole : VARCHAR(255)
+ *   The parent's Role.
+ * ACL : VARBINARY(65525)
+ *   Access control list.
 */
 CREATE PROCEDURE db_5_0.retrieveEntityParents(
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveEntityParentsBody: BEGIN
 
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         IF Version IS NOT NULL THEN
@@ -68,7 +63,7 @@ retrieveEntityParentsBody: BEGIN
         IF IsHead IS FALSE THEN
             SELECT e._iversion INTO IVersion
                 FROM entity_version as e
-                WHERE e.entity_id = EntityID
+                WHERE e.entity_id = InternalEntityID
                 AND e.version = Version;
 
             IF IVersion IS NULL THEN
@@ -77,10 +72,10 @@ retrieveEntityParentsBody: BEGIN
             END IF;
 
             SELECT
-                i.parent AS ParentID,
+                ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID,
                 ( SELECT value FROM name_data
                     WHERE domain_id = 0
-                    AND entity_id = ParentID
+                    AND entity_id = i.parent
                     AND property_id = 20
                 ) AS ParentName, -- This is not necessarily the name of the parent at the time of
                                  -- IVersion but it is a good guess. Future implementations of the
@@ -92,7 +87,7 @@ retrieveEntityParentsBody: BEGIN
                 (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL
                 FROM archive_isa AS i JOIN entities AS e
                     ON (i.parent = e.id)
-                WHERE i.child = EntityID
+                WHERE i.child = InternalEntityID
                 AND i.child_iversion = IVersion
                 AND i.direct IS TRUE
                 ;
@@ -102,18 +97,18 @@ retrieveEntityParentsBody: BEGIN
     END IF;
 
     SELECT
-        i.parent AS ParentID,
+        ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID,
         ( SELECT value FROM name_data
             WHERE domain_id = 0
-            AND entity_id = ParentID
+            AND entity_id = i.parent
             AND property_id = 20 ) AS ParentName,
         e.description AS ParentDescription,
         e.role AS ParentRole,
         (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL
         FROM isa_cache AS i JOIN entities AS e
             ON (i.parent = e.id)
-        WHERE i.child = EntityID
-        AND i.rpath = EntityID;
+        WHERE i.child = InternalEntityID
+        AND i.rpath = InternalEntityID;
 END
 //
 
diff --git a/procedures/retrieveEntityProperties.sql b/procedures/retrieveEntityProperties.sql
index b8bc565d73cd75cbbb3726fc93e5826725aa1c0f..b948af286e6c38a934c65131f2a6133b426d609c 100644
--- a/procedures/retrieveEntityProperties.sql
+++ b/procedures/retrieveEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -28,30 +25,70 @@ delimiter //
 
 drop procedure if exists db_5_0.retrieveEntityProperties //
 
+/*
+ * Retrieve the properties of an entity (level 1 and 2).
+ *
+ * Parameters
+ * ----------
+ *
+ * DomainID : VARCHAR(255)
+ *     The domain id (0 or the entity's id for level-2-data)
+ * EntityID : VARCHAR(255)
+ *     The entity id (or the property's id for level-2-data)
+ * Version : VARBINARY(255)
+ *     The version of the entity. Optional
+ *
+ * ResultSet
+ * ---------
+ * InternalPropertyID
+ *     Internal property id, to be used when PropertyID
+ *     is NULL because a replacement is used.
+ * PropertyID
+ *     The property id
+ * PropertyValue
+ *     The property value
+ * PropertyStatus
+ *     E.g. OBLIGATORY, FIX, ...
+ * PropertyIndex
+ *     The index of the property (for ordering).
+ * )
+ */
 create procedure db_5_0.retrieveEntityProperties(
-    in DomainID INT UNSIGNED,
-    in EntityID INT UNSIGNED,
+    in DomainID VARCHAR(255),
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveEntityPropertiesBody: BEGIN
 
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalDomainID INT UNSIGNED DEFAULT 0;
+
+    -- When DomainID != 0 the EntityID could possibly be a 'replacement id'
+    -- which are internal ids by definition (and do not have external
+    -- equivalents).
+    IF LOCATE("$", EntityID) = 1 THEN
+        SET InternalEntityID=SUBSTRING(EntityID, 2);
+    ELSE
+        SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+    END IF;
+    -- DomainID != 0 are always normal (i.e. external) Entity ids.
+    SELECT internal_id INTO InternalDomainID from entity_ids WHERE id = DomainID;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         IF Version IS NOT NULL THEN
-            IF DomainID = 0 THEN
+            IF InternalDomainID = 0 THEN
                 SELECT get_head_version(EntityID) = Version INTO IsHead;
             ELSE
                 SELECT get_head_version(DomainID) = Version INTO IsHead;
             END IF;
-
         END IF;
 
         IF IsHead IS FALSE THEN
             SELECT e._iversion INTO IVersion
                 FROM entity_version as e
-                WHERE ((e.entity_id = EntityID AND DomainID = 0)
-                    OR (e.entity_id = DomainID))
+                WHERE ((e.entity_id = InternalEntityID AND InternalDomainID = 0)
+                    OR (e.entity_id = InternalDomainID))
                 AND e.version = Version;
 
             IF IVersion IS NULL THEN
@@ -61,121 +98,135 @@ retrieveEntityPropertiesBody: BEGIN
 
             #-- double properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 value AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_double_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- integer properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 value AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_integer_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- date properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 CONCAT(value, '.NULL.NULL') AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_date_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- datetime properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 CONCAT(value, 'UTC', IF(value_ns IS NULL, '', value_ns))
                     AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_datetime_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- text properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 value AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_text_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- enum properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 value AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_enum_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- reference properties
             SELECT
-                property_id AS PropertyID,
-                IF(value_iversion IS NULL, value,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
+                IF(value_iversion IS NULL,
+                    IF(status = "REPLACEMENT",
+                        CONCAT("$", value),
+                        ( SELECT id FROM entity_ids WHERE internal_id = value )),
                     -- make it "value@version" if necessary
-                    CONCAT(value, "@", _get_version(value, value_iversion)))
+                    CONCAT(
+                        ( SELECT id FROM entity_ids WHERE internal_id = value ),
+                          "@", _get_version(value, value_iversion)))
                     AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_reference_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- null properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 NULL AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_null_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND _iversion = IVersion
 
             UNION ALL
 
             #-- name properties
             SELECT
-                property_id AS PropertyID,
+                CONCAT("$", property_id) AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
                 value AS PropertyValue,
                 status AS PropertyStatus,
                 pidx AS PropertyIndex
             FROM archive_name_data
-            WHERE domain_id = DomainID
-            AND entity_id = EntityID
+            WHERE domain_id = InternalDomainID
+            AND entity_id = InternalEntityID
             AND property_id != 20
             AND _iversion = IVersion;
 
@@ -185,115 +236,129 @@ retrieveEntityPropertiesBody: BEGIN
 
     #-- double properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         value AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM double_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- integer properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         value AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM integer_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- date properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         CONCAT(value, '.NULL.NULL') AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM date_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- datetime properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         CONCAT(value, 'UTC', IF(value_ns IS NULL, '', value_ns))
             AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM datetime_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- text properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         value AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM text_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- enum properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         value AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM enum_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- reference properties
     SELECT
-        property_id AS PropertyID,
-        IF(value_iversion IS NULL, value,
-            CONCAT(value, "@", _get_version(value, value_iversion)))
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
+        IF(value_iversion IS NULL,
+            IF(status = "REPLACEMENT",
+                CONCAT("$", value),
+                ( SELECT id FROM entity_ids WHERE internal_id = value )),
+            -- make it "value@version" if necessary
+            CONCAT(
+                ( SELECT id FROM entity_ids WHERE internal_id = value ),
+                  "@", _get_version(value, value_iversion)))
             AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM reference_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- null properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         NULL AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM null_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
 
     UNION ALL
 
     #-- name properties
     SELECT
-        property_id AS PropertyID,
+        CONCAT("$", property_id) AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
         value AS PropertyValue,
         status AS PropertyStatus,
         pidx AS PropertyIndex
     FROM name_data
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID
     AND property_id != 20;
 
-
 END;
 //
 
diff --git a/procedures/retrieveFSODescriptorByPath.sql b/procedures/retrieveFSODescriptorByPath.sql
index 382882b7cd6dbbcfaed870254669f8cc8b8039a7..73f9e0dbfb544ad9d9b5c43902dc52920b752e38 100644
--- a/procedures/retrieveFSODescriptorByPath.sql
+++ b/procedures/retrieveFSODescriptorByPath.sql
@@ -48,8 +48,8 @@ CREATE PROCEDURE db_5_0.retrieveFSODescriptorByPath(
 retrieveFSODescriptorByPathBody: BEGIN
 
     SELECT hash_algorithm AS FileHashAlgo,
-            byPath as ParamByPath,
-            file_id AS FileID,
+            byPath as Param,
+            (SELECT id FROM entity_ids WHERE internal_id = file_id) AS FileId,
             path AS FilePath,
             size AS FileSize,
             hex(hash) AS FileHash,
diff --git a/procedures/retrieveGroup.sql b/procedures/retrieveGroup.sql
deleted file mode 100644
index 7db1b89c6e0e407e63de29682d4ef033f56b5f92..0000000000000000000000000000000000000000
--- a/procedures/retrieveGroup.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-Drop Procedure if exists db_5_0.retrieveGroup;
diff --git a/procedures/retrieveSubentity.sql b/procedures/retrieveSubentity.sql
deleted file mode 100644
index eae01c6f6a05e2e97ff6caea2dff7b31d0b221ba..0000000000000000000000000000000000000000
--- a/procedures/retrieveSubentity.sql
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-DELIMITER //
-DROP PROCEDURE IF EXISTS db_5_0.retrieveSubEntity //
-/**
-
-**/
-DELIMITER ;
diff --git a/procedures/setFileProperties.sql b/procedures/setFileProperties.sql
new file mode 100644
index 0000000000000000000000000000000000000000..d9ebc10ab228a72c0ab47287bec2be1112b017ce
--- /dev/null
+++ b/procedures/setFileProperties.sql
@@ -0,0 +1,91 @@
+/*
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+DROP PROCEDURE IF EXISTS setFileProperties;
+DELIMITER //
+/**
+ * Insert/Update file properties.
+ *
+ * If ENTITY_VERSIONING is enabled the old file properties are moved to
+ * `archive_files`.
+ *
+ * Parameters
+ * ----------
+ * FileID
+ *   The entity's id.
+ * FileHash
+ *   The SHA512 Hash of the file (or NULL for directories).
+ * FileCheckedTimestamp
+ *   The timestamp when the hash was last checked.
+ * FileSize
+ *   The byte size (or NULL for directories).
+ * FilePath
+ *   The path of the object.
+ * FileMimeType
+ *   The mimetype (use "inode/directory" for directories, use NULL for unknown)
+ * FileStorageID
+ *   The ID of the back-end file storage where this object is located.
+ * FileKey
+ *   The file storage key of this object.
+ * FileParentID
+ *   The entity id of the parent directory (or NULL).
+ */
+CREATE PROCEDURE setFileProperties (
+    in FileID INT UNSIGNED,
+    in FilePath VARCHAR(5000),
+    in FileSize BIGINT UNSIGNED,
+    in FileHash VARCHAR(255),
+    in FileChecked BIGINT,
+    in FileMimeType VARBINARY(255),
+    in FileStorageId VARBINARY(255),
+    in FileKey VARBINARY(40000),
+    in FileParentID INT UNSIGNED,
+    in FileHashAlgo VARCHAR(255)
+)
+BEGIN
+    DECLARE IVersion INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = FileID;
+    IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
+        SELECT max(e._iversion) INTO IVersion
+            FROM entity_version AS e
+            WHERE e.entity_id = InternalEntityID;
+
+        INSERT INTO archive_files (file_id, path, size, hash,
+                checked_timestamp, mimetype, file_storage_id, file_key,
+                _iversion, hash_algorithm)
+            SELECT file_id, path, size, hash, checked_timestamp, mimetype,
+                file_storage_id, file_key, IVersion AS _iversion, hash_algorithm
+            FROM files
+            WHERE file_id = InternalEntityID;
+    END IF;
+
+    DELETE FROM files WHERE file_id = InternalEntityID;
+
+    IF FilePath IS NOT NULL THEN
+        INSERT INTO files (file_id, path, size, hash, checked_timestamp,
+                mimetype, file_storage_id, file_key, hash_algorithm)
+            VALUES (InternalEntityID, FilePath, FileSize, unhex(FileHash), FileChecked,
+                FileMimeType, FileStorageId, FileKey, FileHashAlgo);
+    END IF;
+
+END //
+DELIMITER ;
diff --git a/procedures/setPassword.sql b/procedures/setPassword.sql
deleted file mode 100644
index 33345d9625fadda9d1e182e7ea545e3b8fbf9e8a..0000000000000000000000000000000000000000
--- a/procedures/setPassword.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-DROP PROCEDURE IF EXISTS db_5_0.setPassword;
-delimiter //
-
-CREATE PROCEDURE db_5_0.setPassword(in EntityID INT UNSIGNED, in NewPassword VARCHAR(255))
-BEGIN
-
-
-	DELETE FROM passwords where entity_id=EntityID;
-	INSERT INTO passwords (entity_id, password) VALUES (EntityID, NewPassword);
-
-END;
-//
-delimiter ;
diff --git a/procedures/updateEntity.sql b/procedures/updateEntity.sql
index f98e4795b344bbf0c4b68ac90a0848daf5e14188..88538bbd38a2b3ead5caae9b379b9d202e5a3789 100644
--- a/procedures/updateEntity.sql
+++ b/procedures/updateEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.updateEntity;
@@ -34,11 +31,11 @@ delimiter //
  * Selects the new version identifier for the entity.
  */
 CREATE PROCEDURE db_5_0.updateEntity(
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in EntityName VARCHAR(255),
     in EntityDescription TEXT,
     in EntityRole VARCHAR(255),
-    in Datatype VARCHAR(255),
+    in DatatypeID VARCHAR(255),
     in Collection VARCHAR(255),
     in ACL VARBINARY(65525))
 BEGIN
@@ -48,20 +45,23 @@ BEGIN
     DECLARE ParentVersion VARBINARY(255) DEFAULT NULL;
     DECLARE Transaction VARBINARY(255) DEFAULT NULL;
     DECLARE OldIVersion INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
     call entityACL(ACLID, ACL);
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         SELECT max(_iversion) INTO OldIVersion
             FROM entity_version
-            WHERE entity_id = EntityID;
+            WHERE entity_id = InternalEntityID;
 
         -- move old data to archives
         INSERT INTO archive_entities (id, description, role,
                 acl, _iversion)
             SELECT e.id, e.description, e.role, e.acl, OldIVersion
             FROM entities AS e
-            WHERE e.id = EntityID;
+            WHERE e.id = InternalEntityID;
 
         INSERT INTO archive_data_type (domain_id, entity_id, property_id,
                 datatype, _iversion)
@@ -70,7 +70,7 @@ BEGIN
             FROM data_type AS e
             WHERE e.domain_id = 0
             AND e.entity_id = 0
-            AND e.property_id = EntityID;
+            AND e.property_id = InternalEntityID;
 
         INSERT INTO archive_collection_type (domain_id, entity_id, property_id,
                 collection, _iversion)
@@ -79,16 +79,16 @@ BEGIN
             FROM collection_type as e
             WHERE e.domain_id = 0
             AND e.entity_id = 0
-            AND e.property_id = EntityID;
+            AND e.property_id = InternalEntityID;
 
 
         SET Transaction = @SRID;
         SELECT e.version INTO ParentVersion
             FROM entity_version as e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             AND e._iversion = OldIVersion;
         CALL insert_single_child_version(
-            EntityID, Hash, Version,
+            InternalEntityID, Hash, Version,
             ParentVersion, Transaction);
     END IF;
 
@@ -96,34 +96,33 @@ BEGIN
         SET e.description = EntityDescription,
             e.role=EntityRole,
             e.acl = ACLID
-        WHERE e.id = EntityID;
+        WHERE e.id = InternalEntityID;
 
     -- clean up primary name, because updateEntity might be called without a
     -- prior call to deleteEntityProperties.
     DELETE FROM name_data
-        WHERE domain_id = 0 AND entity_id = EntityID AND property_id = 20;
+        WHERE domain_id = 0 AND entity_id = InternalEntityID AND property_id = 20;
     IF EntityName IS NOT NULL THEN
         INSERT INTO name_data
                 (domain_id, entity_id, property_id, value, status, pidx)
-            VALUES (0, EntityID, 20, EntityName, "FIX", 0);
+            VALUES (0, InternalEntityID, 20, EntityName, "FIX", 0);
     END IF;
 
     DELETE FROM data_type
-        WHERE domain_id=0 AND entity_id=0 AND property_id=EntityID;
+        WHERE domain_id=0 AND entity_id=0 AND property_id=InternalEntityID;
 
     DELETE FROM collection_type
-        WHERE domain_id=0 AND entity_id=0 AND property_id=EntityID;
+        WHERE domain_id=0 AND entity_id=0 AND property_id=InternalEntityID;
 
-    IF Datatype IS NOT NULL THEN
+    IF DatatypeID IS NOT NULL THEN
         INSERT INTO data_type (domain_id, entity_id, property_id, datatype)
-            SELECT 0, 0, EntityID,
-                ( SELECT entity_id FROM name_data WHERE domain_id = 0
-                    AND property_id = 20 AND value = Datatype LIMIT 1 );
+            SELECT 0, 0, InternalEntityID,
+                ( SELECT internal_id FROM entity_ids WHERE id = DatatypeID );
 
         IF Collection IS NOT NULL THEN
             INSERT INTO collection_type (domain_id, entity_id, property_id,
                     collection)
-                SELECT 0, 0, EntityID, Collection;
+                SELECT 0, 0, InternalEntityID, Collection;
         END IF;
     END IF;
 
diff --git a/tests/example.dump.sql b/tests/example.dump.sql
index cad5a03967a807005a217733c557a284408f304c..dc29bb5ea61dfc09e2374da080a03b21227440f4 100644
--- a/tests/example.dump.sql
+++ b/tests/example.dump.sql
@@ -563,31 +563,6 @@ INSERT INTO `passwd` VALUES ('guest','3fe82ca86837d4f9ff765d2d4265ded96843314936
 /*!40000 ALTER TABLE `passwd` ENABLE KEYS */;
 UNLOCK TABLES;
 
---
--- Table structure for table `passwords`
---
-
-DROP TABLE IF EXISTS `passwords`;
-/*!40101 SET @saved_cs_client     = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `passwords` (
-  `entity_id` int(10) unsigned NOT NULL COMMENT 'User ID.',
-  `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Password.',
-  PRIMARY KEY (`entity_id`),
-  CONSTRAINT `use_entity_id_entity` FOREIGN KEY (`entity_id`) REFERENCES `entities` (`id`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `passwords`
---
-
-LOCK TABLES `passwords` WRITE;
-/*!40000 ALTER TABLE `passwords` DISABLE KEYS */;
-INSERT INTO `passwords` VALUES (98,'37d7bd8a833261b4e4653644ee0a065f522b92b3738ca9ae2cb43a83844bf352c4a59c386a44965997a508c61988c9484c093775027425091d6d3d435c3c0e0c'),(99,'37d7bd8a833261b4e4653644ee0a065f522b92b3738ca9ae2cb43a83844bf352c4a59c386a44965997a508c61988c9484c093775027425091d6d3d435c3c0e0c');
-/*!40000 ALTER TABLE `passwords` ENABLE KEYS */;
-UNLOCK TABLES;
-
 --
 -- Table structure for table `permissions`
 --
@@ -668,7 +643,7 @@ CREATE TABLE `reference_data` (
 
 LOCK TABLES `reference_data` WRITE;
 /*!40000 ALTER TABLE `reference_data` DISABLE KEYS */;
-INSERT INTO `reference_data` VALUES (0,243,233,119,'REPLACEMENT',6),(0,243,119,240,'FIX',0),(0,243,232,120,'REPLACEMENT',7),(0,243,120,241,'FIX',0),(0,243,234,121,'REPLACEMENT',8),(0,243,121,242,'FIX',0),(0,265,255,230,'FIX',3),(0,265,256,243,'FIX',4),(0,265,257,119,'REPLACEMENT',6),(0,265,119,262,'FIX',0),(0,265,260,120,'REPLACEMENT',7),(0,265,120,263,'FIX',0),(0,265,259,121,'REPLACEMENT',8),(0,265,121,264,'FIX',0),(0,270,257,119,'REPLACEMENT',1),(0,270,260,120,'REPLACEMENT',2),(0,271,257,119,'REPLACEMENT',1),(0,271,119,268,'FIX',0),(0,271,260,120,'REPLACEMENT',2),(0,271,120,269,'FIX',0),(0,271,267,266,'FIX',3),(0,273,222,271,'FIX',1),(0,277,222,230,'FIX',1),(0,279,222,243,'FIX',1),(0,278,222,265,'FIX',1),(0,276,222,99,'FIX',1),(0,230,221,119,'REPLACEMENT',3),(0,230,119,226,'FIX',0),(0,230,220,120,'REPLACEMENT',4),(0,230,120,227,'FIX',0),(0,230,218,121,'REPLACEMENT',5),(0,230,121,228,'FIX',0),(0,230,219,122,'REPLACEMENT',6),(0,230,122,229,'FIX',0);
+INSERT INTO `reference_data` VALUES (0,243,233,119,'REPLACEMENT',6),(0,243,119,240,'FIX',0),(0,243,232,120,'REPLACEMENT',7),(0,243,120,241,'FIX',0),(0,243,234,121,'REPLACEMENT',8),(0,243,121,242,'FIX',0),(0,265,255,230,'FIX',3),(0,265,256,243,'FIX',4),(0,265,257,119,'REPLACEMENT',6),(0,265,119,262,'FIX',0),(0,265,260,120,'REPLACEMENT',7),(0,265,120,263,'FIX',0),(0,265,259,121,'REPLACEMENT',8),(0,265,121,264,'FIX',0),(0,270,257,119,'REPLACEMENT',1),(0,270,260,120,'REPLACEMENT',2),(0,271,257,119,'REPLACEMENT',1),(0,271,119,268,'FIX',0),(0,271,260,120,'REPLACEMENT',2),(0,271,120,269,'FIX',0),(0,271,267,266,'FIX',3),(0,273,222,271,'FIX',1),(0,277,222,230,'FIX',1),(0,279,222,243,'FIX',1),(0,278,222,265,'FIX',1),(0,230,221,119,'REPLACEMENT',3),(0,230,119,226,'FIX',0),(0,230,220,120,'REPLACEMENT',4),(0,230,120,227,'FIX',0),(0,230,218,121,'REPLACEMENT',5),(0,230,121,228,'FIX',0),(0,230,219,122,'REPLACEMENT',6),(0,230,122,229,'FIX',0);
 /*!40000 ALTER TABLE `reference_data` ENABLE KEYS */;
 UNLOCK TABLES;
 
@@ -2783,34 +2758,6 @@ BEGIN
 
     INSERT IGNORE INTO units_lin_con (signature_from, signature_to, a, b_dividend, b_divisor, c) VALUES (signature_from, signature_to, a, b_dividend, b_divisor, c);
 
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode              = @saved_sql_mode */ ;
-/*!50003 SET character_set_client  = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection  = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `insertUser` */;
-/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client  = utf8mb4 */ ;
-/*!50003 SET character_set_results = utf8mb4 */ ;
-/*!50003 SET collation_connection  = utf8mb4_general_ci */ ;
-/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
-/*!50003 SET sql_mode              = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`caosdb`@`%` PROCEDURE `insertUser`(in Name VARCHAR(255), in Password VARCHAR(255))
-BEGIN 
-
-
-INSERT INTO entities (name, role, acl) VALUES (Name, 'USER', 0);
-
-SET @LAST_UserID = LAST_INSERT_ID();
-
-INSERT INTO passwords VALUES (@LAST_UserID, Password);
-
-Select @LAST_UserID as UserID; 
-
 END ;;
 DELIMITER ;
 /*!50003 SET sql_mode              = @saved_sql_mode */ ;
@@ -3168,29 +3115,6 @@ BEGIN
 	SELECT collection as collection_override, NULL as name_override, NULL as desc_override, NULL as type_override, entity_id, property_id from collection_type where domain_id=DomainID and entity_id=EntityID;
 	
 
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode              = @saved_sql_mode */ ;
-/*!50003 SET character_set_client  = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection  = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `setPassword` */;
-/*!50003 SET @saved_cs_client      = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results     = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client  = utf8mb4 */ ;
-/*!50003 SET character_set_results = utf8mb4 */ ;
-/*!50003 SET collation_connection  = utf8mb4_general_ci */ ;
-/*!50003 SET @saved_sql_mode       = @@sql_mode */ ;
-/*!50003 SET sql_mode              = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`caosdb`@`%` PROCEDURE `setPassword`(in EntityID INT UNSIGNED, in NewPassword VARCHAR(255))
-BEGIN
-
-
-	DELETE FROM passwords where entity_id=EntityID;
-	INSERT INTO passwords (entity_id, password) VALUES (EntityID, NewPassword);
-
 END ;;
 DELIMITER ;
 /*!50003 SET sql_mode              = @saved_sql_mode */ ;
diff --git a/tests/test_autotap.sql b/tests/test_autotap.sql
index 22cc4e47b9625f71b746c7a876689a196f2c5eca..84bf0542f39d525de7dcdf70d129d617b81c42c4 100644
--- a/tests/test_autotap.sql
+++ b/tests/test_autotap.sql
@@ -724,7 +724,7 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description'
 -- COLUMN entities.role
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','entities','role','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'DOMAIN\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\',\'DIRECTORY\')','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'_REPLACEMENT\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\',\'DIRECTORY\',\'LINK\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','entities','role','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','entities','role',NULL,'');
 SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','role','utf8','');
@@ -909,7 +909,7 @@ SELECT tap.table_collation_is('_caosdb_schema_unit_tests','files','utf8_unicode_
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','files','InnoDB','');
 
 -- COLUMNS
-SELECT tap.columns_are('_caosdb_schema_unit_tests','files','`file_id`,`path`,`size`,`hash`,`checked_timestamp`,`parent_directory`,`mimetype`,`file_storage_id`,`file_key`','');
+SELECT tap.columns_are('_caosdb_schema_unit_tests','files','`file_id`,`path`,`size`,`hash`,`hash_algorithm`,`checked_timestamp`,`mimetype`,`file_storage_id`,`file_key`,`parent_directory`,`link_target`','');
 
 -- TODO COLUMN files.parent_directory
 SELECT tap.has_column('_caosdb_schema_unit_tests','files','parent_directory','');
@@ -919,6 +919,22 @@ SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','parent_directory'
 SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','parent_directory',NULL,'');
 SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','parent_directory',NULL,'');
 
+-- TODO COLUMN files.link_target
+SELECT tap.has_column('_caosdb_schema_unit_tests','files','link_target','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','link_target','int(10) unsigned','');
+SELECT tap.col_extra_is('_caosdb_schema_unit_tests','files','link_target','','');
+SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','link_target','NULL','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','link_target',NULL,'');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','link_target',NULL,'');
+
+-- TODO COLUMN files.hash_algorithm
+SELECT tap.has_column('_caosdb_schema_unit_tests','files','hash_algorithm','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','hash_algorithm','varbinary(255)','');
+SELECT tap.col_extra_is('_caosdb_schema_unit_tests','files','hash_algorithm','','');
+SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','hash_algorithm','\'SHA-512\'','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','hash_algorithm',NULL,'');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','hash_algorithm',NULL,'');
+
 -- TODO COLUMN files.mimetype
 SELECT tap.has_column('_caosdb_schema_unit_tests','files','mimetype','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','mimetype','varbinary(255)','');
@@ -937,7 +953,7 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','file_storage_id
 
 -- TODO COLUMN files.file_key
 SELECT tap.has_column('_caosdb_schema_unit_tests','files','file_key','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','file_key','varbinary(16175)','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','file_key','varbinary(16000)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','files','file_key','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','file_key',NULL,'');
 SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','file_key',NULL,'');
@@ -955,7 +971,7 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','file_id',NULL,'
 -- COLUMN files.path
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','files','path','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','path','varchar(16175)','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','path','varchar(16000)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','files','path','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','path',NULL,'');
 SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','path','utf8','');
@@ -998,6 +1014,12 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','files','fil_file_id_e
 SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','files','fil_file_id_entity','RESTRICT','');
 SELECT tap.fk_on_update('_caosdb_schema_unit_tests','files','fil_file_id_entity','RESTRICT','');
 
+-- CONSTRAINT files.files_ibfk_1
+
+SELECT tap.has_constraint('_caosdb_schema_unit_tests','files','files_ibfk_1','');
+SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','files','files_ibfk_1','FOREIGN KEY','');
+SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','files','files_ibfk_1','RESTRICT','');
+SELECT tap.fk_on_update('_caosdb_schema_unit_tests','files','files_ibfk_1','RESTRICT','');
 -- CONSTRAINT files.PRIMARY
 
 SELECT tap.has_constraint('_caosdb_schema_unit_tests','files','PRIMARY','');
@@ -1009,13 +1031,6 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','files','`file_id`','');
 SELECT tap.has_constraint('_caosdb_schema_unit_tests','files','path','');
 SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','files','path','UNIQUE','');
 
--- CONSTRAINT files.files_ibfk_1
-
-SELECT tap.has_constraint('_caosdb_schema_unit_tests','files','files_ibfk_1','');
-SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','files','files_ibfk_1','FOREIGN KEY','');
-SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','files','files_ibfk_1','RESTRICT','');
-SELECT tap.fk_on_update('_caosdb_schema_unit_tests','files','files_ibfk_1','RESTRICT','');
-
 
 -- ***************************************************************
 -- TABLE _caosdb_schema_unit_tests.integer_data
@@ -1959,11 +1974,11 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','trans
 -- COLUMN transaction_log.entity_id
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','transaction_log','entity_id','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','int(10) unsigned','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','transaction_log','entity_id','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4_bin','');
 
 -- COLUMN transaction_log.username
 
@@ -2134,11 +2149,11 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','ut
 -- COLUMN user_info.entity
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','user_info','entity','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','int(10) unsigned','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','user_info','entity','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','user_info','entity','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity',NULL,'');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity',NULL,'');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4_bin','');
 
 -- INDEXES
 SELECT tap.indexes_are('_caosdb_schema_unit_tests','user_info','`subject_entity`','');
@@ -2150,7 +2165,7 @@ SELECT tap.index_is_type('_caosdb_schema_unit_tests','user_info','subject_entity
 SELECT tap.is_indexed('_caosdb_schema_unit_tests','user_info','`entity`','');
 
 -- CONSTRAINTS
-SELECT tap.constraints_are('_caosdb_schema_unit_tests','user_info','`PRIMARY`,`subjects_ibfk_1`','');
+SELECT tap.constraints_are('_caosdb_schema_unit_tests','user_info','`PRIMARY`,`subjects_ibfk_2`','');
 
 -- CONSTRAINT user_info.PRIMARY
 
@@ -2160,10 +2175,10 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','user_info','`realm`,`name`',''
 
 -- CONSTRAINT user_info.subjects_ibfk_1
 
-SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','');
-SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','FOREIGN KEY','');
-SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT','');
-SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT','');
+SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','');
+SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','FOREIGN KEY','');
+SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT','');
+SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT','');
 
 -- ***************************************************************
 -- TABLE _caosdb_schema_unit_tests.user_roles
@@ -2547,27 +2562,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getChildren',
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','getChildren','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','getChildren','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.getFileIdByPath
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','getFileIdByPath','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getFileIdByPath','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','getFileIdByPath','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','getFileIdByPath','CONTAINS SQL','');
-
--- PROCEDURES _caosdb_schema_unit_tests.getRole
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','getRole','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getRole','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','getRole','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','getRole','CONTAINS SQL','');
-
--- PROCEDURES _caosdb_schema_unit_tests.initAutoIncrement
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','initAutoIncrement','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','initAutoIncrement','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','initAutoIncrement','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','initAutoIncrement','CONTAINS SQL','');
-
 -- PROCEDURES _caosdb_schema_unit_tests.initBackReference
 
 SELECT tap.has_procedure('_caosdb_schema_unit_tests','initBackReference','');
@@ -2631,13 +2625,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insertLinCon'
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insertLinCon','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insertLinCon','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.insertUser
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','insertUser','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insertUser','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insertUser','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insertUser','CONTAINS SQL','');
-
 -- PROCEDURES _caosdb_schema_unit_tests.intersectTable
 
 SELECT tap.has_procedure('_caosdb_schema_unit_tests','intersectTable','');
@@ -2694,12 +2681,12 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','raiseWarning'
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','raiseWarning','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','raiseWarning','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.registerSubdomain
+-- PROCEDURES _caosdb_schema_unit_tests.registerReplacementIds
 
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','registerSubdomain','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerSubdomain','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerSubdomain','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerSubdomain','CONTAINS SQL','');
+SELECT tap.has_procedure('_caosdb_schema_unit_tests','registerReplacementIds','');
+SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerReplacementIds','NO','');
+SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerReplacementIds','DEFINER','');
+SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerReplacementIds','CONTAINS SQL','');
 
 -- PROCEDURES _caosdb_schema_unit_tests.initSubProperty
 
@@ -2722,13 +2709,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerTempT
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerTempTableName','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerTempTableName','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.retrieveDatatype
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','retrieveDatatype','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','retrieveDatatype','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','retrieveDatatype','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','retrieveDatatype','CONTAINS SQL','');
-
 -- PROCEDURES _caosdb_schema_unit_tests.retrieveEntityParents
 
 SELECT tap.has_procedure('_caosdb_schema_unit_tests','retrieveEntityParents','');
@@ -2736,13 +2716,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','retrieveEntit
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','retrieveEntityParents','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','retrieveEntityParents','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.setPassword
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests','setPassword','');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','setPassword','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','setPassword','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','setPassword','CONTAINS SQL','');
-
 -- PROCEDURES _caosdb_schema_unit_tests.insertIsa
 
 SELECT tap.has_procedure('_caosdb_schema_unit_tests','insertIsa','');
@@ -2799,12 +2772,5 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insert_single
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insert_single_child_version','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insert_single_child_version','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.delete_all_entity_versions
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests', 'delete_all_entity_versions', '');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','delete_all_entity_versions','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','delete_all_entity_versions','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','delete_all_entity_versions','CONTAINS SQL','');
-
 CALL tap.finish();
 ROLLBACK;
diff --git a/tests/test_entity_versioning.sql b/tests/test_entity_versioning.sql
index 26efd8c029e9ad01f8966ddd687ed31f3c4a2b49..f7c52a210c8baef8e781142ff645122ce95ec4fe 100644
--- a/tests/test_entity_versioning.sql
+++ b/tests/test_entity_versioning.sql
@@ -1,9 +1,8 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
@@ -34,6 +31,13 @@ CALL tap.no_plan();
 
 -- SETUP
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+SET @EntityID3 = 10003;
+SET @EntityID4 = 10004;
+SET @EntityID5 = 10005;
+SET @EntityID6 = 10006;
+
 -- Disable versioning because we want to test `insert_single_child_version`
 -- separately from `insertEntity` but the former is called inside the latter
 -- when versioning is enabled.
@@ -46,22 +50,22 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES
 ("SRIDblieb", 3456, 4576, "you", "home");
 DELETE FROM entities WHERE id > 99;
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
+CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+SELECT entity_id INTO @InternalEntityID1 FROM name_data WHERE value="EntityName";
 
 
 -- TEST insert_single_child_version
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 0, "no versions there yet");
 
-CALL insert_single_child_version(@EntityID, "hashbla", "versionbla", NULL, "SRIDbla");
+CALL insert_single_child_version(@InternalEntityID1, "hashbla", "versionbla", NULL, "SRIDbla");
 SELECT _ipparent INTO @x from entity_version WHERE version="versionbla";
 SELECT tap.eq(@x, NULL, "no parent for the first version");
 
 -- add a second version
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 1, "one version there already");
-CALL insert_single_child_version(@EntityID, "hashblub", "versionblub", "versionbla", "SRIDblub");
+CALL insert_single_child_version(@InternalEntityID1, "hashblub", "versionblub", "versionbla", "SRIDblub");
 
 SELECT _ipparent INTO @x from entity_version WHERE version="versionblub";
 SELECT tap.eq(@x, 1, "the original entity is the parent");
@@ -72,7 +76,7 @@ SELECT tap.eq(@x, 2, "two versions there already");
 
 CALL tap._assert_throws(
      concat("CALL insert_single_child_version(",
-            @EntityID, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'),
+            @InternalEntityID1, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'),
      "non existing parent throws");
 
 SELECT count(*) INTO @x FROM entity_version;
@@ -80,21 +84,24 @@ SELECT tap.eq(@x, 2, "still two versions there");
 
 
 -- TEST get_primary_parent_version
-SELECT tap.eq(get_primary_parent_version(@EntityID, "versionblub"), "versionbla", "returns correct parent for versionblub");
-SELECT tap.eq(get_primary_parent_version(@EntityID, "versionbla"), NULL, "versionbla has no parent");
+SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionblub"), "versionbla", "returns correct parent for versionblub");
+SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionbla"), NULL, "versionbla has no parent");
 
 
+-- Reactivate when versioning's FORGET is being implemented
 -- TEST delete_all_entity_versions
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.ok(@x > 0, "several versions in the table");
 
-CALL delete_all_entity_versions(@EntityID);
+-- CALL delete_all_entity_versions(@EntityID1);
+DELETE FROM entity_version WHERE entity_id = @InternalEntityID1;
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 0, "no versions there any more");
 
 
 -- TEARDOWN clean up
 DELETE FROM name_data WHERE entity_id > 99;
+DELETE FROM entity_ids WHERE internal_id > 99;
 DELETE FROM entities WHERE id > 99;
 
 -- #####################################################################
@@ -108,20 +115,20 @@ SELECT tap.eq(@x, 0, "before insertEntity, no versions there");
 
 -- TEST insertEntity - should produce a version w/o parent
 SET @SRID = "SRIDbla";
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
-CALL insertEntity("ParentName", "ParentDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+SELECT entity_id INTO @InternalEntityID2 FROM name_data WHERE value="EntityName";
+CALL insertEntity(@EntityID3, "ParentName", "ParentDesc", "RECORDTYPE", "{acl1}");
 SELECT entity_id INTO @ParentID FROM name_data WHERE value="ParentName";
-CALL insertIsa(@EntityID, @ParentID);
-CALL insertEntityProperty(0, @EntityID, 17, "null_data", NULL, NULL,
+CALL insertIsa(@EntityID2, @EntityID3);
+CALL insertEntityProperty(0, @EntityID2, 17, "null_data", NULL, NULL,
     "RECOMMENDED", NULL, "DescOverride", NULL, NULL, 0);
 
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 1, "after insertEntity, a version is there.");
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent is NULL;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent is NULL;
 SELECT tap.eq(@x, 1, "after insertEntity, the _iversion number is 1.");
 
-SELECT _ipparent INTO @x from entity_version WHERE entity_id = @EntityID;
+SELECT _ipparent INTO @x from entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, NULL, "no parent for the freshly inserted entity");
 SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update")
     FROM archive_entities;
@@ -129,14 +136,14 @@ SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update")
 
 -- TEST updateEntity - should produce a version with a parent
 SET @SRID = "SRIDblub";
-CALL deleteEntityProperties(@EntityID);
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}");
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL deleteEntityProperties(@EntityID2);
+CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}");
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 2, "after updateEntity, a second version is there.");
 
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1;
 SELECT tap.eq(@x, 2, "after updateEntity, the _iversion number incremented.");
-SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1;
+SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1;
 SELECT tap.eq(@x, 1, "after updateEntity, the _pparent points to the first version");
 
 SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities")
@@ -144,60 +151,60 @@ SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities")
 
 
 -- TEST get_version_history
-CALL get_version_history(@EntityID);
+CALL get_version_history(@EntityID2);
 
 -- TEST retrieveEntity
 
 SELECT version INTO @x FROM entity_version
-    WHERE entity_id = @EntityID
+    WHERE entity_id = @InternalEntityID2
     AND _iversion = 2;
-CALL retrieveEntity(@EntityID, NULL);
-CALL retrieveEntity(@EntityID, "non-existing-version");
-CALL retrieveEntity(@EntityID, get_head_version(@EntityID));
-CALL retrieveEntity(@EntityID, @x);
+CALL retrieveEntity(@EntityID2, NULL);
+CALL retrieveEntity(@EntityID2, "non-existing-version");
+CALL retrieveEntity(@EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntity(@EntityID2, @x);
 
 -- TEST retrieveEntityParents
 
-CALL retrieveEntityParents(@EntityID, NULL);
-CALL retrieveEntityParents(@EntityID, "non-existing-version");
-CALL retrieveEntityParents(@EntityID, get_head_version(@EntityID));
-CALL retrieveEntityParents(@EntityID, @x);
+CALL retrieveEntityParents(@EntityID2, NULL);
+CALL retrieveEntityParents(@EntityID2, "non-existing-version");
+CALL retrieveEntityParents(@EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntityParents(@EntityID2, @x);
 
 -- TEST retrieveEntityProperties
 
-CALL retrieveEntityProperties(0, @EntityID, NULL);
-CALL retrieveEntityProperties(0, @EntityID, "non-existing-version");
-CALL retrieveEntityProperties(0, @EntityID, get_head_version(@EntityID));
-CALL retrieveEntityProperties(0, @EntityID, @x);
+CALL retrieveEntityProperties(0, @EntityID2, NULL);
+CALL retrieveEntityProperties(0, @EntityID2, "non-existing-version");
+CALL retrieveEntityProperties(0, @EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntityProperties(0, @EntityID2, @x);
 
 -- TEST retrieveOverrides
 
-CALL retrieveOverrides(0, @EntityID, NULL);
-CALL retrieveOverrides(0, @EntityID, "non-existing-version");
-CALL retrieveOverrides(0, @EntityID, get_head_version(@EntityID));
-CALL retrieveOverrides(0, @EntityID, @x);
+CALL retrieveOverrides(0, @EntityID2, NULL);
+CALL retrieveOverrides(0, @EntityID2, "non-existing-version");
+CALL retrieveOverrides(0, @EntityID2, get_head_version(@EntityID2));
+CALL retrieveOverrides(0, @EntityID2, @x);
 
 
 -- and 2nd updateEntity
 SET @SRID = "SRIDblieb";
-CALL updateEntity(@EntityID, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}");
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL updateEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}");
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 3, "after 2nd updateEntity, a 3rd version is there.");
 
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 2;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 2;
 SELECT tap.eq(@x, 3, "after 2nd updateEntity, the _iversion number incremented again.");
-SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _iversion = 3;
+SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _iversion = 3;
 SELECT tap.eq(@x, 2, "after 2nd updateEntity, the _pparent points to the 2nd version");
-SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @EntityID AND _ipparent = 2;
+SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @InternalEntityID2 AND _ipparent = 2;
 
 
 -- TEST deleteEntity - should remove all versions
-CALL deleteIsa(@EntityID);
-CALL deleteEntity(@EntityID);
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL deleteIsa(@EntityID3);
+CALL deleteEntity(@EntityID2);
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 0, "no versions there any more");
 
-CALL deleteEntity(@ParentID);
+CALL deleteEntity(@EntityID3);
 
 CALL tap.finish();
 ROLLBACK;
@@ -217,21 +224,21 @@ DELETE FROM transactions;
 -- insert entity without versioning
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID4, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
 SELECT count(*) INTO @NumOfEntities FROM entities;
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
+SELECT entity_id INTO @InternalEntityID4 FROM name_data WHERE value="EntityName";
 
 SET @TheUser = "TheUser"; -- used to identify the matching entry in transaction_log
 -- fill transaction_log: one entity with two updates (and one insert) and another entity with insert and delete.
 INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds, nanos)
     -- the first entry is the one which is be found by _fix_unversioned
     VALUES
-        ("Update", @EntityID, @TheUser,     "CaosDB",  23458, 254),
+        ("Update", @InternalEntityID4, @TheUser,     "CaosDB",  23458, 254),
         -- the rest is dummy data
-        ("Update", @EntityID, "OtherUser",  "CaosDB",   2345, 633), -- not the latest transaction
-        ("Insert", @EntityID, "OtherUser",  "CaosDB",    245, 633), -- not the latest transaction
-        ("Insert", @EntityID + 1, @TheUser, "CaosDB",   2325, 653), -- not the right entity, inserted before our target
-        ("Delete", @EntityID + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target
+        ("Update", @InternalEntityID4, "OtherUser",  "CaosDB",   2345, 633), -- not the latest transaction
+        ("Insert", @InternalEntityID4, "OtherUser",  "CaosDB",    245, 633), -- not the latest transaction
+        ("Insert", @InternalEntityID4 + 1, @TheUser, "CaosDB",   2325, 653), -- not the right entity, inserted before our target
+        ("Delete", @InternalEntityID4 + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target
 
 
 SELECT tap.eq(COUNT(*), 5, "five entries in transaction_log") FROM transaction_log;
@@ -251,11 +258,11 @@ SELECT tap.eq(COUNT(*), 2,
     "after _fix_unversioned, one entry for our test entity in transactions, one for the standard entities.")
     FROM transactions;
 
-SELECT tap.eq(entity_id, @EntityID, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99;
+SELECT tap.eq(entity_id, @InternalEntityID4, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99;
 SELECT tap.ok(srid IS NOT NULL, "srid was generated and user/time matches entries from transaction_log")
     FROM transactions AS t JOIN transaction_log AS l
     ON (l.seconds = t.seconds AND l.nanos = t.nanos AND l.username = t.username AND l.realm = t.realm)
-    WHERE l.entity_id = @EntityID AND l.username = @TheUser;
+    WHERE l.entity_id = @InternalEntityID4444 AND l.username = @TheUser;
 
 CALL tap.finish();
 ROLLBACK;
@@ -275,18 +282,18 @@ DELETE FROM transactions;
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}");
-CALL insertEntity("EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID5, "EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID6, "EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}");
 SELECT count(*) INTO @NumOfEntities FROM entities;
-SELECT entity_id INTO @EntityID1 FROM name_data WHERE value="EntityName1";
-SELECT entity_id INTO @EntityID2 FROM name_data WHERE value="EntityName2";
+SELECT entity_id INTO @InternalEntityID5 FROM name_data WHERE value="EntityName1";
+SELECT entity_id INTO @InternalEntityID6 FROM name_data WHERE value="EntityName2";
 
 INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds,
         nanos)
     -- the first entry is the one which will be found by _fix_unversioned
-    VALUES ("INSERT", @EntityID1, "User", "CaosDB", 10000, 250),
-        ("INSERT", @EntityID2, "User", "CaosDB", 10000, 250),
-        ("UPDATE", @EntityID2, "User", "CaosDB", 20000, 250);
+    VALUES ("INSERT", @InternalEntityID5, "User", "CaosDB", 10000, 250),
+        ("INSERT", @InternalEntityID6, "User", "CaosDB", 10000, 250),
+        ("UPDATE", @InternalEntityID6, "User", "CaosDB", 20000, 250);
 
 
 SELECT tap.eq(COUNT(*), 3, "three entries in transaction_log") FROM transaction_log;
@@ -309,10 +316,10 @@ SELECT tap.eq(COUNT(*), 3,
 
 SELECT tap.eq(seconds, 10000, "version seconds of entity 1 is correct")
     FROM entity_version AS v JOIN transactions AS t
-    ON (v.srid = t.srid) WHERE v.entity_id = @EntityID1;
+    ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID1;
 SELECT tap.eq(seconds, 20000, "version seconds of entity 2 is correct")
     FROM entity_version AS v JOIN transactions AS t
-    ON (v.srid = t.srid) WHERE v.entity_id = @EntityID2;
+    ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID2;
 
 CALL tap.finish();
 ROLLBACK;
diff --git a/tests/test_insert_update_delete.sql b/tests/test_insert_update_delete.sql
index a11b05e3d9a72d6038800adebf5b73c699c2a2b8..ff1e4ec3acc6fe0121ff168279fe7659e05a914c 100644
--- a/tests/test_insert_update_delete.sql
+++ b/tests/test_insert_update_delete.sql
@@ -1,9 +1,31 @@
+/**
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 USE _caosdb_schema_unit_tests;
 BEGIN;
 CALL tap.no_plan();
 
 -- SETUP
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+
 -- Disable versioning and only test the non-versioning behavior
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 
@@ -16,31 +38,31 @@ SELECT entity_id into @TextDatatypeID FROM name_data WHERE value ="TEXT";
 -- TEST insertEntity
 SELECT tap.eq(COUNT(id), 0, "No entities")
     FROM entities WHERE id>=100;
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
 
 SELECT tap.eq(COUNT(entity_id), 1, "Entity has been inserted")
     FROM name_data WHERE value="EntityName";
 
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
-SELECT tap.ok(@EntityID >= 100, "EntityID greater 99");
+SELECT entity_id INTO @InternalEntityID FROM name_data WHERE value="EntityName";
+SELECT tap.ok(@InternalEntityID >= 100, "EntityID greater 99");
 
 SELECT tap.eq(acl, @ACLID1, "correct acl id had been assigned")
-    FROM entities WHERE id=@EntityID;
+    FROM entities WHERE id=@InternalEntityID;
 
 
 -- TEST insertEntityProperty
-CALL insertEntity("AProperty", "APropDesc", "PROPERTY", "{acl1}");
-SELECT entity_id INTO @PropID FROM name_data WHERE value="AProperty";
-INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @PropID, @TextDatatypeID);
+CALL insertEntity(@EntityID2, "AProperty", "APropDesc", "PROPERTY", "{acl1}");
+SELECT entity_id INTO @InternalPropertyID FROM name_data WHERE value="AProperty";
+INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @InternalPropertyID, @TextDatatypeID);
 
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 0, "No data in null_data table");
-CALL insertEntityProperty(0, @EntityID, @PropID, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0);
+CALL insertEntityProperty(0, @EntityID1, @EntityID2, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0);
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 1, "One row in null_data table");
 
 -- TEST updateEntity
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID1, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
 
 SELECT tap.eq(COUNT(entity_id), 0, "Old Entity name not present")
     FROM name_data WHERE value="EntityName";
@@ -48,21 +70,21 @@ SELECT tap.eq(COUNT(entity_id), 1, "Entity name has been updated")
     FROM name_data WHERE value="NewEntityName";
 
 SELECT tap.eq(acl, @ACLID2, "acl has been updated")
-    FROM entities WHERE id=@EntityID;
+    FROM entities WHERE id=@InternalEntityID;
 
 -- CALL updateEntity again an update the Name
-CALL updateEntity(@EntityID, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}");
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID2, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
 
 
 -- TEST deleteEntityProperties
-CALL deleteEntityProperties(@EntityID);
+CALL deleteEntityProperties(@EntityID1);
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 0, "data removed from null_data table");
 
 -- TEST deleteEntity
-CALL deleteEntity(@EntityID);
-CALL deleteEntity(@PropID);
+CALL deleteEntity(@EntityID1);
+CALL deleteEntity(@EntityID2);
 SELECT COUNT(id) INTO @x FROM entities WHERE id>100;
 SELECT tap.eq(@x, 0, "entity deleted");
 
diff --git a/tests/test_issues.sql b/tests/test_issues.sql
index ab64de844e01c2ad3e273d6ea1e0c24709781a09..ef5abd400387410e18057a5a2281f1d9c391a38d 100644
--- a/tests/test_issues.sql
+++ b/tests/test_issues.sql
@@ -1,9 +1,9 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
  * Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,14 +17,16 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
 BEGIN;
 CALL tap.no_plan();
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+SET @EntityID3 = 10003;
+SET @EntityID4 = 10004;
 
 -- ########################################################################
 -- TEST Issues from https://gitlab.com/caosdb/caosdb-mysqlbackend/-/issues
@@ -42,23 +44,18 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES
 CALL entityACL(@ACLID1, "{acl1}");
 
 -- Insert entities and obtain IDs
-CALL insertEntity("A", "Desc A", "RECORDTYPE", "{acl1}");
-CALL insertEntity("B", "Desc B", "RECORDTYPE", "{acl1}");
-CALL insertEntity("C", "Desc C", "RECORDTYPE", "{acl1}");
-CALL insertEntity("rec", "Desc rec", "RECORD", "{acl1}");
-
-SELECT entity_id INTO @ID_A FROM name_data WHERE value="A";
-SELECT entity_id INTO @ID_B FROM name_data WHERE value="B";
-SELECT entity_id INTO @ID_C FROM name_data WHERE value="C";
-SELECT entity_id INTO @ID_rec FROM name_data WHERE value="rec";
+CALL insertEntity(@EntityID1, "A", "Desc A", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID2, "B", "Desc B", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID3, "C", "Desc C", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID4, "rec", "Desc rec", "RECORD", "{acl1}");
 
 -- Insert is-a relationships
-CALL insertIsA(@ID_A, @ID_B);
-CALL insertIsA(@ID_B, @ID_C);
-CALL insertIsA(@ID_rec, @ID_A);
+CALL insertIsA(@EntityID1, @EntityID2);
+CALL insertIsA(@EntityID2, @EntityID3);
+CALL insertIsA(@EntityID4, @EntityID1);
 
 -- Try to delete last child
 -- leads to failure in issue #21
-CALL deleteIsa(@ID_rec);
+CALL deleteIsa(@EntityID4);
 
 ROLLBACK;
diff --git a/tests/test_reference_values.sql b/tests/test_reference_values.sql
index c22a42da1fa4a3ffebfc2fa0ad10d3d4d0910d2a..2b9dcefc8f6244f1753185fe86e351c847baa3a2 100644
--- a/tests/test_reference_values.sql
+++ b/tests/test_reference_values.sql
@@ -1,9 +1,8 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
@@ -31,36 +28,39 @@ CALL tap.no_plan();
 -- #####################################################################
 
 -- SETUP
--- switch off versioning
-DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
-
 DELETE FROM entity_version;
 DELETE FROM transactions;
 INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES
 ("SRIDbla", 1234, 2345, "me", "home"),
 ("SRIDblub", 2345, 3465, "me", "home"),
 ("SRIDblieb", 3456, 4576, "you", "home");
-SET @SRID = "SRIDbla";
-CALL insertEntity("EntityName", "EntityDescription", "RECORDTYPE", "{}");
-SET @EntityID=99;
+SET @EntityID="99";
 SET @PropertyID=11;
-SELECT id INTO @Value FROM entities WHERE description = "EntityDescription";
+SET @Value=50;
+SET @SRID="SRIDbla";
+call insertEntity(@EntityID, "TheName", "TheDesc", "RecordType", "{}");
+call insertEntity(@Value, "RefValue", "ValueDesc", "Record", "{}");
+SELECT internal_id INTO @InternalEntityID FROM entity_ids WHERE id = @EntityID;
+SELECT internal_id INTO @InternalValueID FROM entity_ids WHERE id = @Value;
+
+-- switch off versioning
+DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 
 -- TEST insertEntityProperty without Versioning
 CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
     NULL, "FIX", NULL, NULL, NULL, NULL, 0);
 
 -- TODO switch expected/actual
-SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data;
-SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data;
-SELECT tap.eq(11, property_id, "property ok") FROM reference_data;
-SELECT tap.eq(@VALUE, value, "value ok") FROM reference_data;
+SELECT tap.eq("0", domain_id, "domain ok") FROM reference_data;
+SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data;
+SELECT tap.eq("11", property_id, "property ok") FROM reference_data;
+SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data;
 SELECT tap.eq("FIX", status, "status ok") FROM reference_data;
 SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data;
-SELECT tap.eq(NULL, value_iversion, "value_iversion ok") FROM reference_data;
+SELECT tap.eq(NULL, value_iversion, "value_iversion ok 1") FROM reference_data;
 
 -- clean up
-DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99;
+DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalValueID;
 
 -- #####################################################################
 -- TODO TEST insertEntityProperty with Versioning
@@ -71,68 +71,68 @@ INSERT INTO feature_config (_key, _value) VALUES ("ENTITY_VERSIONING", "ENABLED"
 
 
 -- TEST insertEntityProperty with Versioning - REFERENCE HEAD
-SELECT id INTO @Value FROM entities WHERE description = "EntityDescription";
 CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
     NULL, "FIX", NULL, NULL, NULL, NULL, 0);
 
 -- TODO switch expected/actual
 SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data;
-SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data;
+SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data;
 SELECT tap.eq(11, property_id, "property ok") FROM reference_data;
-SELECT tap.eq(@Value, value, "value ok") FROM reference_data;
+SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data;
 SELECT tap.eq("FIX", status, "status ok") FROM reference_data;
 SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data;
-SELECT tap.eq(value_iversion, NULL, "value_iversion ok") FROM reference_data;
+SELECT tap.eq(value_iversion, NULL, "value_iversion ok 2") FROM reference_data;
 
-DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99;
+DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalEntityID;
 
 
 -- TEST insertEntityProperty with Versioning - Reference version
-SELECT id INTO @Value FROM entities WHERE description = "EntityDescription";
-CALL insert_single_child_version(@Value, "hashbla", "versionbla", NULL, "SRIDbla");
-CALL insert_single_child_version(@Value, "hashblub", "versionblub", "versionbla", "SRIDblub");
-
-
-SET @VersionedValue=CONCAT(@Value, "@versionbla");
-CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data",
-    @VersionedValue, NULL, "FIX", NULL, NULL, NULL, NULL, 0);
+SELECT * FROM entity_ids;
+SELECT * FROM entity_version;
+SELECT e.version INTO @ParentVersion
+    FROM entity_version as e
+    WHERE e.entity_id = @InternalValueID
+    AND e._iversion = 1;
+CALL insert_single_child_version(@InternalValueID, "hashblub", "versionblub", @ParentVersion, "SRIDblub");
+
+SET @VALUE=CONCAT("50@", @ParentVersion);
+CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
+    NULL, "FIX", NULL, NULL, NULL, NULL, 0);
 
 SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data;
-SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data;
+SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data;
 SELECT tap.eq(11, property_id, "property ok") FROM reference_data;
-SELECT tap.eq(@Value, value, "value ok") FROM reference_data;
+SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data;
 SELECT tap.eq("FIX", status, "status ok") FROM reference_data;
 SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data;
-SELECT tap.eq(value_iversion, "1", "value_iversion ok") FROM reference_data;
+SELECT tap.eq(value_iversion, "1", "value_iversion ok 3") FROM reference_data;
 
-DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99;
+DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalEntityID;
 
-SET @VersionedValue=CONCAT(@Value, "@versionblub");
-CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data",
-    @VersionedValue, NULL, "FIX", NULL, NULL, NULL, NULL, 0);
+SET @VALUE="50@versionblub";
+CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
+    NULL, "FIX", NULL, NULL, NULL, NULL, 0);
 
 -- TODO switch expected/actual
 SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data;
-SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data;
+SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data;
 SELECT tap.eq(11, property_id, "property ok") FROM reference_data;
-SELECT tap.eq(@Value, value, "value ok") FROM reference_data;
+SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data;
 SELECT tap.eq("FIX", status, "status ok") FROM reference_data;
 SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data;
-SELECT tap.eq(value_iversion, "2", "value_iversion ok") FROM reference_data;
+SELECT tap.eq(value_iversion, "2", "value_iversion ok 4") FROM reference_data;
 
 
 -- invalid values throw errors
-SET @VersionedValue=CONCAT(@Value, "@");
+SET @VALUE="50@";
 CALL tap._assert_throws('
-    CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data",
-        @VersionedValue, NULL, "FIX", NULL, NULL, NULL, NULL, 0)', "@ but no
-    version id");
+    CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
+        NULL, "FIX", NULL, NULL, NULL, NULL, 0)', "@ but no version id");
 
-SET @VersionedValue=CONCAT(@Value, "@non-existing-version");
+SET @VALUE="50@non-existing-version";
 CALL tap._assert_throws('
-    CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data",
-        @VersionedValue, NULL, "FIX", NULL, NULL, NULL, NULL, 0)',
-    "non-existing-version id");
+    CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
+        NULL, "FIX", NULL, NULL, NULL, NULL, 0)', "non-existing-version id");
 
 
 -- #####################################################################
diff --git a/utils/backup.sh b/utils/backup.sh
index bdc345cfe1e956024fbd8492c6a1a2d65acc2cdd..4d53da3edafd52be32d9f33507664d6971581360 100755
--- a/utils/backup.sh
+++ b/utils/backup.sh
@@ -56,7 +56,7 @@ function backup() {
     fi
 
     echo "Dumping database $database to $backupfile ..."
-    $MYSQLDUMP_CMD $(get_mysql_args_nodb) --opt --default-character-set=utf8 \
+    $MYSQLDUMP_CMD $(get_db_args_nodb) --opt --default-character-set=utf8 \
           --routines "$database" > "$backupfile"
 
     success
diff --git a/utils/helpers.sh b/utils/helpers.sh
index 6adb318503e26061369a1144568dea4f60ef3d46..86f7d5981c7497fe478bccb3f391932585934545 100644
--- a/utils/helpers.sh
+++ b/utils/helpers.sh
@@ -52,47 +52,25 @@ function mysql_execute_file {
 	fi
 }
 
-
-function get_mysql_args {
-	echo "$(get_mysql_args_nodb) --database=$DATABASE_NAME"
-}
-
 function get_db_args {
 	echo "$(get_db_args_nodb) --database=$DATABASE_NAME"
 }
 
 function get_db_args_nodb {
-	if [ "$DATABASE_USER" ]; then
-		mysql_con_arguments="--user=$DATABASE_USER"
+	if [ -n "$MYSQL_USER" ]; then
+		mysql_con_arguments="--user=$MYSQL_USER"
 	fi
-	if [ "$DATABASE_USER_PW" ]; then
-		mysql_con_arguments="$mysql_con_arguments --password=$DATABASE_USER_PW"
+	if [ -n "$MYSQL_USER_PASSWORD" ]; then
+		mysql_con_arguments="$mysql_con_arguments --password=$MYSQL_USER_PASSWORD"
 	fi
-	if [[ "$MYSQL_HOST" && ( "$MYSQL_HOST" != "localhost" ) ]]; then
+	if [ -n "$MYSQL_HOST" ] && [ "$MYSQL_HOST" != "localhost" ]; then
 		mysql_con_arguments="$mysql_con_arguments --host=$MYSQL_HOST"
-		if [ "$MYSQL_PORT" ]; then
-			mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT"
-		fi
 	fi
-	echo $mysql_con_arguments
-}
-
-function get_mysql_args_nodb {
-	if [ "$LOGIN_PATH" ]; then
-		mysql_con_arguments="--login-path=$LOGIN_PATH"
-	else
-		if [ "$MYSQL_USER" ]; then
-			mysql_con_arguments="--user=$MYSQL_USER"
-		fi
-		if [ "$MYSQL_USER_PASSWORD" ]; then
-			mysql_con_arguments="$mysql_con_arguments --password=$MYSQL_USER_PASSWORD"
-		fi
-		if [[ "$MYSQL_HOST" && ( "$MYSQL_HOST" != "localhost" ) ]]; then
-			mysql_con_arguments="$mysql_con_arguments --host=$MYSQL_HOST"
-			if [ "$MYSQL_PORT" ]; then
-				mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT"
-			fi
-		fi
+	if [ -n "$MYSQL_PORT" ] && [ "$MYSQL_PORT" != "3306" ]; then
+		mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT"
+	fi
+	if [ -n "$MYSQL_OPTS" ] ; then
+		mysql_con_arguments="$mysql_con_arguments $MYSQL_OPTS"
 	fi
 	echo $mysql_con_arguments
 }
diff --git a/utils/load_settings.sh b/utils/load_settings.sh
index 9d5fc61c261c1154b0d0a6d191de9eee767611f1..34d30774aabe0ccb1ed1c3443ba5cf0c11d3936b 100644
--- a/utils/load_settings.sh
+++ b/utils/load_settings.sh
@@ -65,6 +65,7 @@ export MYSQL_CONFIG_EDITOR_CMD
 export MYSQL_HOST
 export MYSQL_PORT
 export MYSQL_USER
+export MYSQL_OPTS
 export DATABASE_NAME
 export DATABASE_USER
 export DATABASE_USER_PW
diff --git a/utils/make_db b/utils/make_db
index 9afcb95bbf53f99e109b270ee55126290653b16b..955ec4661a501dcae874aba27b9dfbd8cfbbd0be 100755
--- a/utils/make_db
+++ b/utils/make_db
@@ -88,7 +88,7 @@ function _install_unit_test_database () {
     if _db_exists "$DATABASE_NAME"; then
         echo "using $DATABASE_NAME"
     else
-        sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_mysql_args_nodb)
+        sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_db_args_nodb)
 
         # create test user
         grant
@@ -114,7 +114,7 @@ function _setup_mytap() {
     pushd libs > /dev/null
     unzip -u mytap*.zip > /dev/null
     pushd mytap*/ > /dev/null
-    $MYSQL_CMD $(get_mysql_args_nodb) < mytap.sql > /dev/null || exit 1
+    $MYSQL_CMD $(get_db_args_nodb) < mytap.sql > /dev/null || exit 1
     popd > /dev/null
     rm -r mytap*/
     popd > /dev/null
@@ -130,13 +130,28 @@ name in your .config file "
         exit 0
     fi
 
-    sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_mysql_args_nodb)
+    sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_db_args_nodb)
+}
+
+function sanity_check() {
+    trap "$(shopt -po errexit)" RETURN
+    set +e
+    echo -n "running sanity checks ..."
+    msg="$($MYSQL_CMD $(get_db_args) < "utils/sanity_check.sql" 2>/dev/null)"
+    code="$?"
+    if [ "$code" -eq "0" ] ; then
+        echo " [OK]"
+    else
+        echo " [FAILED]"
+        echo "$msg"
+        exit 1
+    fi
 }
 
 # Inserts the dump (arg 1) into the database
 function restore_db() {
     SQL_FILE="$1"
-    $MYSQL_CMD $(get_mysql_args) < "$SQL_FILE"
+    $MYSQL_CMD $(get_db_args) < "$SQL_FILE"
     cat <<EOF
 If this is not the same SQL server where the SQL dump was originally created
 from, make sure that a user with sufficient permissions exists.  Note that you
@@ -145,7 +160,7 @@ EOF
 }
 
 function test-connection() {
-    $MYSQL_CMD $(get_mysql_args_nodb) -e "select 0;"
+    $MYSQL_CMD $(get_db_args_nodb) -e "select 0;"
 }
 
 # Creates a user and grants it sufficient rights.
@@ -169,7 +184,7 @@ function grant() {
     if [[ $1 = "--strict" ]] ; then
         for host in ${DATABASE_USER_HOST_LIST//,/ } ; do
             CMD="SELECT COUNT(*) FROM mysql.user WHERE user='${DATABASE_USER}' AND host='${host}';"
-            [[ $($MYSQL_CMD $(get_mysql_args_nodb) -s -N -e "$CMD") = 0 ]] || {
+            [[ $($MYSQL_CMD $(get_db_args_nodb) -s -N -e "$CMD") = 0 ]] || {
                 echo "The user '${DATABASE_USER}@${host}' is already in the database."
                 echo "Please use another user or delete it, e.g. with"
                 echo "'mysql -u ${MYSQL_USER} -p -e \"DROP USER ${DATABASE_USER}@${host};\"'"
@@ -183,7 +198,7 @@ function grant() {
         # FIXME Are all these permissions necessary? See
         # https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/28 "Default
         # installation target does not work for existing databases"
-        $MYSQL_CMD $(get_mysql_args_nodb) <<EOF
+        $MYSQL_CMD $(get_db_args_nodb) <<EOF
 CREATE USER IF NOT EXISTS
     '$DATABASE_USER'@'$host' identified by '$DATABASE_USER_PW';
 GRANT USAGE ON *.* TO '$DATABASE_USER'@'$host';
@@ -198,16 +213,16 @@ EOF
 function drop() {
     DROPDB="$1"
     for host in ${DATABASE_USER_HOST_LIST//,/ } ; do
-        $MYSQL_CMD $(get_mysql_args_nodb) -e "DROP USER '${DATABASE_USER}'@'${host}';" || true
+        $MYSQL_CMD $(get_db_args_nodb) -e "DROP USER '${DATABASE_USER}'@'${host}';" || true
     done
-    "$MYSQLADMIN_CMD" $(get_mysql_args_nodb) -f drop "$DROPDB"
+    "$MYSQLADMIN_CMD" $(get_db_args_nodb) -f drop "$DROPDB"
 }
 
 
 # Returns 0 or non-zero, depending on whether the database exists already.
 # Optional parameter: [DATABASE_NAME], else $DATABASE_NAME is used.
 function _db_exists() {
-    $MYSQL_CMD $(get_mysql_args_nodb) -D "${1-${DATABASE_NAME}}" -e "show tables;" > /dev/null 2>&1 \
+    $MYSQL_CMD $(get_db_args_nodb) -D "${1-${DATABASE_NAME}}" -e "show tables;" > /dev/null 2>&1 \
         && return 0 || return 1
 }
 
@@ -236,7 +251,7 @@ function grant-permission() {
     fi
 
     cmd="SELECT COUNT(1) from roles where name='${role}';"
-    count=$($MYSQL_CMD $(get_mysql_args) -AN -e "$cmd")
+    count=$($MYSQL_CMD $(get_db_args) -AN -e "$cmd")
     if [[ $count == "0" ]]; then
         echo "Role not found!"
         exit 1
@@ -245,7 +260,7 @@ function grant-permission() {
     cmd="INSERT INTO permissions (role, permissions) VALUE ('${role}', '${permissions}')"
     cmd+="ON DUPLICATE KEY UPDATE role='${role}', permissions='${permissions}'"
     cmd+=";"
-    $MYSQL_CMD $(get_mysql_args) -e "$cmd"
+    $MYSQL_CMD $(get_db_args) -e "$cmd"
 }
 
 
@@ -257,5 +272,6 @@ case $1 in
     "test-connection") test-connection ;;
     "install_db") install_db ;;
     "restore_db") restore_db $2 ;;
+    "sanity_check") sanity_check ;;
     *) echo "Unknown action: $1"; exit 32
 esac
diff --git a/utils/sanity_check.sql b/utils/sanity_check.sql
new file mode 100644
index 0000000000000000000000000000000000000000..c29e7c8a82f238f5836e519159fa48d63933a609
--- /dev/null
+++ b/utils/sanity_check.sql
@@ -0,0 +1,85 @@
+
+
+DROP PROCEDURE IF EXISTS sanity_check;
+delimiter //
+CREATE PROCEDURE sanity_check()
+sanityCheckBody: BEGIN
+    CREATE TEMPORARY TABLE expected_tables (table_name VARCHAR(255));
+    INSERT INTO expected_tables (table_name) VALUES
+("archive_collection_type"),
+("archive_data_type"),
+("archive_date_data"),
+("archive_datetime_data"),
+("archive_desc_overrides"),
+("archive_double_data"),
+("archive_entities"),
+("archive_enum_data"),
+("archive_files"),
+("archive_integer_data"),
+("archive_isa"),
+("archive_name_data"),
+("archive_name_overrides"),
+("archive_null_data"),
+("archive_query_template_def"),
+("archive_reference_data"),
+("archive_text_data"),
+("collection_type"),
+("data_type"),
+("date_data"),
+("datetime_data"),
+("desc_overrides"),
+("double_data"),
+("entities"),
+("entity_ids"),
+("entity_acl"),
+("entity_version"),
+("enum_data"),
+("feature_config"),
+("files"),
+("integer_data"),
+("isa_cache"),
+("name_data"),
+("name_overrides"),
+("null_data"),
+("passwd"),
+("permissions"),
+("query_template_def"),
+("reference_data"),
+("roles"),
+("stats"),
+("text_data"),
+("transaction_log"),
+("transactions"),
+("units_lin_con"),
+("user_info"),
+("user_roles")
+;
+
+SELECT COUNT(WRONG) INTO @count_wrong FROM ( SELECT l.table_name AS MATCHED, r.table_name AS WRONG FROM expected_tables AS l RIGHT OUTER JOIN information_schema.tables AS r ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) WHERE r.table_schema = database()) AS temp WHERE temp.MATCHED IS NULL;
+
+SELECT COUNT(MISSING) INTO @count_missing FROM ( SELECT l.table_name AS MISSING, r.table_name AS MATCHED FROM expected_tables AS l LEFT OUTER JOIN information_schema.tables AS r ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) WHERE r.table_schema = database() OR r.table_schema IS NULL) AS temp WHERE temp.MATCHED IS NULL;
+
+IF @count_missing = 0 AND @count_wrong = 0 THEN
+    LEAVE sanityCheckBody;
+END IF;
+
+SELECT "--------------";
+SELECT @count_missing AS "Number of missing tables";
+
+SELECT MISSING AS "Missing tables" FROM ( SELECT l.table_name AS MISSING, r.table_name AS MATCHED FROM expected_tables AS l LEFT OUTER JOIN information_schema.tables AS r ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) WHERE r.table_schema = database() OR r.table_schema IS NULL) AS temp WHERE temp.MATCHED IS NULL;
+
+SELECT "--------------";
+SELECT @count_wrong AS "Number of tables which should not exist";
+
+SELECT WRONG AS "Tables which should not exist" FROM ( SELECT l.table_name AS MATCHED, r.table_name AS WRONG FROM expected_tables AS l RIGHT OUTER JOIN information_schema.tables AS r ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) WHERE r.table_schema = database()) AS temp WHERE temp.MATCHED IS NULL;
+
+SELECT "--------------";
+SELECT "ERROR" from sanity_check_failed;
+
+END;
+//
+delimiter ;
+
+CALL sanity_check();
+
+DROP PROCEDURE sanity_check;