diff --git a/.docker/Dockerfile b/.docker/Dockerfile
index 5c49eb7e9c88346b8423a611dc14aca2e85cf346..f9a4145fdf1a70e7be1ede3649261757a12d2c65 100644
--- a/.docker/Dockerfile
+++ b/.docker/Dockerfile
@@ -1,4 +1,4 @@
-FROM debian:buster
+FROM debian:bookworm
 RUN apt-get update \
     && \
     apt-get install -y \
@@ -11,4 +11,8 @@ RUN apt-get update \
 		python3-sqlparse \
 		python3-sphinx \
 		doxygen
-RUN pip3 install breathe sphinx-rtd-theme recommonmark
+RUN pip3 install --break-system-packages \
+  breathe \
+  sphinx-rtd-theme \
+  pytest \
+  recommonmark
diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml
new file mode 100644
index 0000000000000000000000000000000000000000..8c6555eb457a992f69625c55bfced34d9b1c51fd
--- /dev/null
+++ b/.docker/docker-compose.yml
@@ -0,0 +1,23 @@
+version: '3.6'
+services:
+  sqldb:
+    image: mariadb:11.4
+    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/.gitignore b/.gitignore
index 26060c8b9c3986ed5a0803bcf1e1e2a88acee1a3..6f952db9ec3600b624a0151d97db6d299cbd53ca 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,5 @@ libs/*
 # Generated files
 _doxygen/
 _generated/
-/build/
\ No newline at end of file
+/build/
+*~
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1e54f4c213acfb9f2b67e01b2ad38b64171c31c0..3137b6ad8ddc686c563e78e6e2c5ee3f0a6ca3fe 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -3,7 +3,9 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+# Copyright (C) 2024 Indiscale GmbH <info@indiscale.com>
 # Copyright (C) 2019 Henrik tom Wörden
+# Copyright (C) 2024 Daniel Hornung <d.hornung@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
@@ -59,43 +61,35 @@ unittests-mariadb:
   tags: [ docker ]
   stage: test
   services:
-    - mariadb:10.4
-
+    - mariadb:10.11
   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:
+# Run the dump update tests
+test-dump-update:
   tags: [ docker ]
   stage: test
-  # Should not stop the pipeline from continuing.
-  allow_failure: true
-  services:
-    - name: mysql:5.7
-      command: ["--default-authentication-plugin=mysql_native_password"]
-
   script:
-    # remove some lines from autotap because the checks of column default
-    # values don't work with mysql-5
-    - sed -i "/col_default_is.*NULL/d" tests/test_autotap.sql
-    - sed -i "/col_default_is.*INACTIVE/d" tests/test_autotap.sql
-    - sed -i "/col_default_is.*SHA/d" tests/test_autotap.sql
-    - make pipeline-test SQL_HOST=mysql
+    - make test-dump-update
+
+# # Run the unit tests with MySQL 5
+# unittests-mysql-5:
+#   tags: [ docker ]
+#   stage: test
+#   # Should not stop the pipeline from continuing.
+#   allow_failure: true
+#   services:
+#     - name: mysql:5.7.36
+#       command: ["--default-authentication-plugin=mysql_native_password"]
+#
+#   script:
+#     # remove some lines from autotap because the checks of column default
+#     # values don't work with mysql-5
+#     - sed -i "/col_default_is.*NULL/d" tests/test_autotap.sql
+#     - sed -i "/col_default_is.*INACTIVE/d" tests/test_autotap.sql
+#     - sed -i "/col_default_is.*SHA/d" tests/test_autotap.sql
+#     - sed -i "s/utf8mb3/utf8/" tests/test_autotap.sql
+#     - make pipeline-test SQL_HOST=mysql
 
 ######## Deploy ########
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22588269882a81dd299b2e56120576d2382d9426..3bd316eb5605e52ad4c4ee60e84a6d40db5512c9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,31 +5,166 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
-## [Unreleased] ##
+## [Unreleased]
+
+### Added
+
+- New version requirement: MariaDB 11.2 or later.
+
+### Changed
+
+* Changed names from CaosDB to LinkAhead.
+
+### Deprecated
+
+### Removed
+
+- MySQL support.  See the deprecation in the 7.0.0 release.
+
+### Fixed
+
+- [SQL dump migration can now be applied
+  twice](https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/60):
+  Fixed an error in the regex.
+- [linkahead-server#264](https://gitlab.com/linkahead/linkahead-server/-/issues/264)
+  Queries ignore accents and umlauts: Changed to more appropriate
+  collation and character sets. This requires MariaDB 11.2 or later,
+  see above.
+
+### Security
+
+## [8.0.0] - 2024-10-24 ##
+
+### Added ###
+
+- Script to update outdated database dumps.
+
+### Changed ###
+
+- `OFFSET` is a reserved keyword in MariaDB 10.6, so the former
+  `OFFSET` parameter name in the `get_head_relative` function was
+  changed to HeadOffset. See
+  [`update_dumps/README.md`](update_dumps/README.md) for information
+  on how to update old SQL dumps to be compatible with this renaming
+  and MariaDB >= 10.6.
+
+## [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 ###
 
+* Sanity checks during `make install` and `make upgrade`.
+
+## [7.0.0] - 2023-10-25 ##
+(Timm Fitschen)
+
 ### Changed ###
 
-* Changed names from CaosDB to LinkAhead.
+* 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 ###
 
-### Removed ###
+* MySQL Support. Last version which is known to work well with LinkAhead is MySQL 5.7.36
 
 ### Fixed ###
 
-### Security ###
+* 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).
 
-## [5.0.0] - 2021-10-28 ##
+## [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 ###
 
-* #33 CI pipeline for MySQL (was only MariaDB before).
+* Table `entity_ids`
+* Procedure `getIdByName`
+* Procedure `insertEntityDataType` and `insertEntityCollection`
+* Procedure `setFileProperties`.
 
 ### Changed ###
 
-### Deprecated ###
+* 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 ###
 
@@ -43,8 +178,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 ###
@@ -65,31 +198,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
 * `get_version_history` returns two additional columns, `child_username` and
   `child_realm`.
 * Added a `versioned` flag to the following procedures:
-    * `applyBackReference`
-    * `applyIDFilter`
-    * `applyPOV`
-    * `applyRefPOV`
-    * `makeStmt`
-    * `calcComplementUnion`
-    * `calcDifference`
-    * `calcIntersection`
-    * `finishSubProperty`
-    * `getChildren`
-    * `initEmptyTargetSet`
-    * `initDisjunctionFilter`
-    * `initEntity`
-    * `initQuery`
-    * `createTmpTable`
+	* `applyBackReference`
+	* `applyIDFilter`
+	* `applyPOV`
+	* `applyRefPOV`
+	* `makeStmt`
+	* `calcComplementUnion`
+	* `calcDifference`
+	* `calcIntersection`
+	* `finishSubProperty`
+	* `getChildren`
+	* `initEmptyTargetSet`
+	* `initDisjunctionFilter`
+	* `initEntity`
+	* `initQuery`
+	* `createTmpTable`
 * Added a `direct` column to `archive_isa` table
 
-### Deprecated ###
-
 ### Removed ###
 
 * unused procedures:
-    * `initNegationFilter`
-    * `initConjunctionFilter`
-    * `finishNegationFilter`
+	* `initNegationFilter`
+	* `initConjunctionFilter`
+	* `finishNegationFilter`
 
 ### Fixed ###
 
@@ -109,8 +240,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   version resultet in an error. See corresponding test in `linkahead-pyinttest`
   `tests/test_versioning.py::test_datatype_without_name`
 
-### Security ###
-
 ## [3.0.0] - 2020-09-01 ##
 
 ### Added ###
@@ -128,20 +257,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   with a lot of additions to the API. E.g.
   * New `entity_version`.
   * All `*_data` tables have a new twin, the `archive_*_data` table, where all
-    old versions of entities are stored. The `*_data` tables only contain the
-    data of the latest version.
+	old versions of entities are stored. The `*_data` tables only contain the
+	data of the latest version.
   * Additional `archive_isa` for the history entities' parents.
   * Additional `_iversion` column for the `reference_data` table for storing
-    references to particular versions of an entity.
+	references to particular versions of an entity.
   * New `setFileProperties` and `retrieveQueryTemplateDef` procedures which reduce server code and let the
-    backend decide which tables to use. Also, this is necessary for the
-    versioning, because these procedures behave differently depending on the
-    ENTITY_VERSIONING feature being enabled or disabled.
+	backend decide which tables to use. Also, this is necessary for the
+	versioning, because these procedures behave differently depending on the
+	ENTITY_VERSIONING feature being enabled or disabled.
   * Several functions and procedures for the interaction with the
-    `entity_version` table and the `transactions` table. E.g.
-    `insert_single_child_version`, `delete_all_entity_versions`,
-    `get_iversion`, `get_primary_parent_version`, `get_version_timestamp`,
-    `get_head_version`, `get_head_relative`, `get_version_history`.
+	`entity_version` table and the `transactions` table. E.g.
+	`insert_single_child_version`, `delete_all_entity_versions`,
+	`get_iversion`, `get_primary_parent_version`, `get_version_timestamp`,
+	`get_head_version`, `get_head_relative`, `get_version_history`.
   The versions are tracked internally by the `_iversion` field which is an
   integer and which should not be used outside of the backend.
 * New makefile targets for testing with MariaDB instance from Docker image: call
@@ -164,5 +293,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/CITATION.cff b/CITATION.cff
new file mode 100644
index 0000000000000000000000000000000000000000..3d997f969ded2b5b3b8f9975835e51be7e86b30a
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,28 @@
+cff-version: 1.2.0
+message: "If you use this software, please cite it as below."
+authors:
+  - family-names: Fitschen
+    given-names: Timm
+    orcid: https://orcid.org/0000-0002-4022-432X
+  - family-names: Schlemmer
+    given-names: Alexander
+    orcid: https://orcid.org/0000-0003-4124-9649
+  - family-names: Hornung
+    given-names: Daniel
+    orcid: https://orcid.org/0000-0002-7846-6375
+  - family-names: tom Wörden
+    given-names: Henrik
+    orcid: https://orcid.org/0000-0002-5549-578X
+  - family-names: Spreckelsen
+    given-names: Florian
+    orcid: https://orcid.org/0000-0002-6856-2910
+  - family-names: Parlitz
+    given-names: Ulrich
+    orcid: https://orcid.org/0000-0003-3058-1435
+  - family-names: Luther
+    given-names: Stefan
+    orcid: https://orcid.org/0000-0001-7214-8125
+title: "LinkAhead - MariaDB Backend"
+version: 8.0.0
+doi: 10.3390/data4020083
+date-released: 2024-10-10
diff --git a/Makefile b/Makefile
index e776ee0babe292158c9e886730b4a41448375ac2..c2cbce0edc270234c9af76167eeaa0b6fe777abc 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
+# This file is a part of the Linkahead Project.
 #
-# ** header v3.0
-# This file is a part of the LinkAhead Project.
-#
+# Copyright (C) 2025 Daniel Hornung <d.hornung@indiscale.com>
+# Copyright (C) 2025 IndiScale GmbH <info@indiscale.com>
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
 #
@@ -18,8 +18,7 @@
 # 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
-#
+
 SHELL=/bin/bash
 
 INSTALL_SQL_FILE=db_5_0.sql
@@ -34,6 +33,7 @@ test-connection:
 .PHONY: upgrade
 upgrade:
 	@cd patches; ./applyPatches.sh --env=../.config
+	@./utils/make_db sanity_check
 
 .PHONY: install
 install: _install _grant upgrade
@@ -55,23 +55,26 @@ drop-%:
 test:
 	./utils/make_db test --fresh
 
-# Run tests with a database which is started in a Docker container
+.PHONY: test-dump-update
+test-dump-update:
+	pytest dump_updates
+
+# Run tests with a database which is started in a MariaDB Docker container
 .PHONY: test-docker
 test-docker:
 	@docker kill linkahead-mysqlserver-test || true
-	@docker container rm linkahead-mysqlserver-test || true
+	@docker container rm -v linkahead-mysqlserver-test || true
 	@docker run --name linkahead-mysqlserver-test -p "3306:3306" \
-		-e MYSQL_ROOT_PASSWORD="pass-for-test" -d mariadb
+		-e MYSQL_ROOT_PASSWORD="pass-for-test" -d mariadb:11.4
 	@sleep 10
 	MAINPATH=$(realpath tests/docker_env) utils/make_db test --fresh
-	@docker kill linkahead-mysqlserver-test
-	@docker container rm linkahead-mysqlserver-test
+	make test-docker-stop
 
 # if automatic stopping failed
 .PHONY: test-docker-stop
 test-docker-stop:
 	docker kill linkahead-mysqlserver-test
-	docker container rm linkahead-mysqlserver-test
+	docker container rm -v linkahead-mysqlserver-test
 
 # Compile the standalone documentation
 .PHONY: doc
@@ -85,7 +88,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 9e9d7c929cf872f8f8662e8912a3bec310cf293c..3c714592bc1ce7f71a7492c7c6ab53cbea48d5fc 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 
 ## Welcome
 
-This is the **LinkAhead MySQL Backend** repository and a part of the
+This is the **LinkAhead MariaDB Backend** repository and a part of the
 LinkAhead project.
 
 ## Setup
@@ -18,30 +18,32 @@ Please refer to the [official documentation](https://docs.linkahead.org/linkahea
 
 ## Contributing
 
-Thank you very much to all contributers—[past, present](https://gitlab.com/linkahead/linkahead/-/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/linkahead/linkahead/-/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/linkahead/linkahead-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/linkahead-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) linkahead.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
 
 * Copyright (C) 2018 Research Group Biomedical Physics, Max Planck Institute
   for Dynamics and Self-Organization Göttingen.
-* Copyright (C) 2020-2023 Indiscale GmbH <info@indiscale.com>
+* Copyright (C) 2020-2025 Indiscale GmbH <info@indiscale.com>
 
 All files in this repository are licensed under a [GNU Affero General Public
 License](LICENCE.md) (version 3 or later).
diff --git a/README_SETUP.md b/README_SETUP.md
index 88fbe41de13229faac502a89a4b767c15ae013e3..689852903dc4e0530fc464fe9e1cb95e2f3e5455 100644
--- a/README_SETUP.md
+++ b/README_SETUP.md
@@ -1,9 +1,9 @@
-# Setup of the LinkAhead SQL back end
+# Setup of the LinkAhead MariaDB backend
 
 ## 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 11.2` or later.
+* make
 
 ## Create the configuration
 * Create an empty `.config` file. For the default values and the meaning of
@@ -12,7 +12,7 @@
   parameter that you want to change, add a corresponding line in your `.config`
   file. You probably want to change the passwords.  As the passwords are stored
   unencrypted in the `.config` file, make sure nobody else can read it.
-    * If there is no `mysql-config-editor` (`MySQL 5.5`. and `MariaDB`) then the
+    * If there is no `mysql-config-editor` program, then the
       `MYSQL_USER_PASSWORD` must be provided, that is the password of the
       `MYSQL_USER`.
     * If you are using MariaDB and the `root` database user uses pam
@@ -22,7 +22,7 @@
 
 ## Setup the SQL database for LinkAhead
 
-* Run `make install`. If a there is a database with the name you have choosen
+* Run `make install`. If a there is a database with the name you have chosen
   during the configuration, you need to reconfigure or delete the database
   first.
   * *Required database privileges:*
@@ -88,19 +88,46 @@ 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`.
+
+### Developing tests ###
+
+To use the mytap framework:
+
+```console
+$ cd libs; unzip mytap-1.0.zip; cd mytap-1.0
+# Use the necessary mariadb options for connecting to the server in the following commands
+$ mariadb ... < mytap.sql  # Set up the "tap" database and functions.
+$ mariadb ... < scripts/autotap.sql  # Insert the "autotap" function.
+# Create autotap file (for comparison with current state)
+$ mariadb ... --raw -B --skip-column-names -e "call tap.autotap('_caosdb_schema_unit_tests')" > test_autotap.current.sql 
+# Run the autotap tests (may fail unfortunately with current MariaDB):
+$ mariadb ... < test_autotap.current.sql
+```
+
 ### Troubleshooting
 
-#### MySQL has failing tests
+#### Failure to restore a database dump created with an older MariaDB version ####
 
-Our test suite is developed with MariaDB. That is why some tests, those which
-check constraints based on auto-generated names, fail because MySQL generates
-other names.
+Have a look into the `dump_updates/README.md`. In cases of version
+incompatibilities, the necessary steps to migrate the dump are
+probably described there and scripts for the migrations are provided
+in the same directory.
 
-Also some test fail with the message "Expected: NULL / Was: NULL" which is
-obviously what was expected.
+#### MySQL has failing tests
 
-Please look carefully through the tests. If something more serious than that
-comes up, please report a bug.
+*Note: Since we switched from MySQL to MariaDB, the two DBMS projects have diverged quite far.  As a
+result, we no longer support MySQL.
 
 ## Documentation #
 
diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md
index 9b06342c9d4a91f1add4bd61559ecd1d8e94546a..41c47136c1ab7160578950a384ce9c6ab2182b5b 100644
--- a/RELEASE_GUIDELINES.md
+++ b/RELEASE_GUIDELINES.md
@@ -1,12 +1,13 @@
-# Release Guidelines for the LinkAhead MySQL Backend
+# Release Guidelines for the LinkAhead MariaDB backend
 
 This document specifies release guidelines in addition to the general release
-guidelines of the LinkAhead Project
-([RELEASE_GUIDELINES.md](https://gitlab.com/linkahead/linkahead/blob/dev/RELEASE_GUIDELINES.md))
+guidelines of the CaosDB Project
+([RELEASE_GUIDELINES.md](https://gitlab.com/caosdb/caosdb-meta/-/blob/dev/RELEASE_GUIDELINES.md))
 
 ## General Prerequisites
 
-* All tests are passing.
+* All tests are passing. (Note that pipelines may fail if the major
+  version increased. Rely on manual tests in that case.)
 * (FEATURES.md is up-to-date and a public API is being declared in that document.)
 * CHANGELOG.md is up-to-date.
 * (DEPENDENCIES.md is up-to-date.)
@@ -19,10 +20,23 @@ guidelines of the LinkAhead 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` and in `CITATION.cff`.
 
-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)
+
+11. If necessary, i.e., if the patch or major versions were increased
+	with the release, do a LinkAhead server release.
diff --git a/config.defaults b/config.defaults
index 79ebcba154f01dd86ad3b4399bca2eb84656632b..aba6e0c25d6d275c653f6e6b063d8d25bd281678 100644
--- a/config.defaults
+++ b/config.defaults
@@ -1,7 +1,7 @@
-#
-# ** header v2.0
 # This file is a part of the LinkAhead Project.
 #
+# Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com>
+# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com>
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
 #
@@ -15,11 +15,9 @@
 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 # GNU General Public License for more details.
 #
-# You should have received a copy of the GNU General Public License
+# 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
-#
 
 # # Commands
 # The MySQL client program.
@@ -40,6 +38,12 @@ MYSQL_PORT=3306
 # which will then be used by the LinkAhead 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/Maintenance.rst b/doc/Maintenance.rst
index fbdef943a3b579c2457b746d09cfcd6d530c128a..ec8d8f3f6a677527a5a581096dc9bbd9c7068d97 100644
--- a/doc/Maintenance.rst
+++ b/doc/Maintenance.rst
@@ -1,12 +1,9 @@
-
 Maintenance
 ===========
 
-
 Creating a Backup
 -----------------
 
-
 You can use the Python script ``utils/backup.py`` to create a backup (SQL dump) 
 of the SQL-Backend::
 
diff --git a/doc/conf.py b/doc/conf.py
index 20f21f40728038c43e98725f6929bd1905d66dc6..1c33c3faa66aae1a78f2c9cd333b442ed227f7f3 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -22,13 +22,13 @@ import sphinx_rtd_theme
 # -- Project information -----------------------------------------------------
 
 project = 'linkahead-mysqlbackend'
-copyright = '2023, IndiScale GmbH'
+copyright = '2021 - 2024, IndiScale GmbH'
 author = 'Daniel Hornung'
 
 # The short X.Y version
-version = '6.0'
+version = '8.0.1'
 # The full version, including alpha/beta/rc tags
-release = '6.0.0-SNAPSHOT'
+release = '8.0.1-SNAPSHOT'
 
 
 # -- General configuration ---------------------------------------------------
diff --git a/doc/index.rst b/doc/index.rst
index 652b8556ca4cbbf29a6d29063e0d6d12d9b8b83e..fc6fd46750fa5cd4459f440e7ca7ac5afc041cb3 100644
--- a/doc/index.rst
+++ b/doc/index.rst
@@ -10,7 +10,9 @@ Welcome to documentation of LinkAhead's MySQL Backend!
    Getting started <README_SETUP>
    Concepts <concepts>
    Maintenance 
-   API documentation<functions>
+   API documentation <functions>
+   Related Projects <related_projects/index>
+   Back to Overview <https://docs.indiscale.com/>
 
 This documentation helps you to :doc:`get started<README_SETUP>`, explains the most important
 :doc:`concepts<concepts>` .
diff --git a/doc/related_projects/index.rst b/doc/related_projects/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..78abfd939a097245042a8487eee8ae0d6b4d9e44
--- /dev/null
+++ b/doc/related_projects/index.rst
@@ -0,0 +1,25 @@
+Related Projects
+++++++++++++++++
+
+.. toctree::
+   :maxdepth: 2
+   :caption: Contents:
+   :hidden:
+
+.. container:: projects
+
+   For in-depth documentation for users, administrators  and developers, you may want to visit the subproject-specific documentation pages for:
+
+   :`Server <https://docs.indiscale.com/caosdb-server>`_: The Java part of the LinkAhead server.
+
+   :`WebUI <https://docs.indiscale.com/caosdb-webui>`_: The default web frontend for the LinkAhead server.
+
+   :`PyLinkAhead <https://docs.indiscale.com/caosdb-pylib>`_: The LinkAhead Python library.
+
+   :`Advanced user tools <https://docs.indiscale.com/caosdb-advanced-user-tools>`_: The advanced Python tools for LinkAhead.
+
+   :`LinkAhead Crawler <https://docs.indiscale.com/caosdb-crawler/>`_: The crawler is the main tool for automatic data integration in LinkAhead.
+
+   :`LinkAhead <https://docs.indiscale.com/caosdb-deploy>`_: Your all inclusive LinkAhead software package.
+
+   :`Back to Overview <https://docs.indiscale.com/>`_: LinkAhead Documentation.
diff --git a/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh b/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8b9e4843c349a9281526953d6e0c40712a2b1c1a
--- /dev/null
+++ b/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh
@@ -0,0 +1,44 @@
+#!/usr/bin/env bash
+
+# This file is a part of the LinkAhead Project.
+#
+# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2024 Daniel Hornung <d.hornung@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/>.
+
+# About this script
+# =================
+#
+# Fix the use of "offset" as a procedure parameter name.  "OFFSET" became a reserved keyword in
+# MariaDB 10.6.
+#
+# This script takes an SQL dump from stdin and prints the fixed SQL to stdout.
+#
+# Usage
+# -----
+#
+# 2024-10-02.dump_fix_mariadb_10_6.sh < yourdump.sql > yourdump.fixed.sql
+
+set -euo pipefail
+IFS=$'\n\t'
+
+script='
+/^[[:blank:]]+Offset INT UNSIGNED/s/Offset INT UNSIGNED\) RETURNS varbinary\(255\)/HeadOffset INT UNSIGNED\) RETURNS varbinary(255)/
+s/LIMIT 1 OFFSET Offset/LIMIT 1 OFFSET HeadOffset/
+'
+
+sed -E -e "$script"
+
+unset script
diff --git a/dump_updates/README.md b/dump_updates/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..704ea80321a9a873185d0c6959e2000ad26fa10d
--- /dev/null
+++ b/dump_updates/README.md
@@ -0,0 +1,21 @@
+# SQL dump updates #
+
+## Dump ##
+
+This directory contains scripts to update database dumps to newer versions of the MariaDB server.
+
+## Background ##
+
+In some cases, restoring the database content from existing SQL dumps may not be possible in a
+straightforward manner.  For those cases, this directory contains scripts to help with known issues.
+
+Examples for problems include:
+
+- New reserved keywords in MariaDB, that were previously used as identifiers in code.
+
+# Known issues and their fix #
+
+- SQL syntax error near `Offset INT UNSIGNED`: If a dump was made before MariaDB 10.6 (LinkAhead <
+  0.15) and with the SQL backend before 7.0.3, there was a pramater named `Offset`.  With MariaDB
+  10.6 however, `OFFSET` became a reserved keyword.  This can be fixed by running  
+  `2024-10-02.dump_fix_mariadb_10_6.sh < yourdump.sql > yourdump.fixed.sql`
diff --git a/dump_updates/test/test_all.py b/dump_updates/test/test_all.py
new file mode 100644
index 0000000000000000000000000000000000000000..acdeeeceb341c396c91b764e60bd8b30a7bcd19d
--- /dev/null
+++ b/dump_updates/test/test_all.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+
+# This file is a part of the LinkAhead Project.
+#
+# Copyright (C) 2024 IndiScale GmbH <www.indiscale.com>
+# Copyright (C) 2024 Daniel Hornung <d.hornung@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/>.
+
+"""Testing the dump update scripts
+
+As a general rule, dump updaters should be idempotent, so tests should run the update again after
+the first checks are successlful.
+
+TODO: Reduce the boilerplate for the tests.
+"""
+
+import filecmp
+from pathlib import Path
+from subprocess import run
+from tempfile import NamedTemporaryFile
+
+
+def get_basedir() -> str:
+    """Return the assumped base dir for the dump updates.
+    """
+    path = Path(__file__).parents[1]
+    return str(path)
+
+
+def get_test_data(basename: str) -> list[tuple[str, str]]:
+    """Return a list of [input, expectedoutput] tuples.
+
+    The output may be an empty string if no corresponding file can be found.
+    """
+    basedir = get_basedir()
+    datadir = Path(basedir) / "test" / "test_data"
+    results = []
+    for input_path in datadir.glob(f"{basename}.example*[0-9].sql"):
+        expected_path = datadir / f"{input_path.name[:-4]}.expected.sql"
+        if expected_path.exists():
+            expected = str(expected_path)
+        else:
+            expected = ""
+        results.append((str(input_path), expected))
+    return results
+
+
+def test_2024_10_02(tmpdir):
+    """``Offset`` became a reserved keyword in MariaDB 10.6.
+    """
+    script = "2024-10-02.dump_fix_mariadb_10_6.sh"
+    script_fullname = str(Path(get_basedir()) / script)
+    test_data = get_test_data(script[:-3])
+    for infile, expectedfile in test_data:
+        with (NamedTemporaryFile(dir=tmpdir, suffix=".sql", delete=True) as output,
+              open(infile, mode="rb") as infile_stream
+              ):
+            run([script_fullname],
+                stdin=infile_stream,
+                stdout=output,
+                check=True
+                )
+            assert filecmp.cmp(output.name, expectedfile), "Output does not match expected output."
+            with (NamedTemporaryFile(dir=tmpdir, suffix=".sql", delete=True) as output2,
+                  open(output.name, mode="rb") as infile_stream
+                  ):
+                run([script_fullname],
+                    stdin=infile_stream,
+                    stdout=output2,
+                    check=True
+                    )
+                assert filecmp.cmp(output2.name, expectedfile), (
+                    "Run 2: Output does not match expected output.")
diff --git a/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql
new file mode 100644
index 0000000000000000000000000000000000000000..1a58223ba65827231ce658f1a655a68706bf8088
--- /dev/null
+++ b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql
@@ -0,0 +1,36 @@
+/* Just a short snippt with the problem */
+
+
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = utf8 */ ;
+/*!50003 SET character_set_results = utf8 */ ;
+/*!50003 SET collation_connection  = utf8_general_ci */ ;
+DELIMITER ;;
+CREATE DEFINER=`root`@`%` FUNCTION `get_head_relative`(EntityID VARCHAR(255),
+    HeadOffset 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;
+
+    
+    
+    
+    
+    RETURN (
+        SELECT e.version
+            FROM entity_version AS e
+            WHERE e.entity_id = InternalEntityID
+            ORDER BY e._iversion DESC
+            LIMIT 1 OFFSET HeadOffset
+        );
+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 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' */ ;
+/*!50003 D */
diff --git a/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql
new file mode 100644
index 0000000000000000000000000000000000000000..a5476af3268360476f2c1ef741cb25007e29ce5d
--- /dev/null
+++ b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql
@@ -0,0 +1,36 @@
+/* Just a short snippt with the problem */
+
+
+/*!50003 SET @saved_col_connection = @@collation_connection */ ;
+/*!50003 SET character_set_client  = utf8 */ ;
+/*!50003 SET character_set_results = utf8 */ ;
+/*!50003 SET collation_connection  = utf8_general_ci */ ;
+DELIMITER ;;
+CREATE DEFINER=`root`@`%` FUNCTION `get_head_relative`(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;
+
+    
+    
+    
+    
+    RETURN (
+        SELECT e.version
+            FROM entity_version AS e
+            WHERE e.entity_id = InternalEntityID
+            ORDER BY e._iversion DESC
+            LIMIT 1 OFFSET Offset
+        );
+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 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' */ ;
+/*!50003 D */
diff --git a/libs/mytap-1.0.zip b/libs/mytap-1.0.zip
index 9e04965cd40320bde2e598c585119ffa7f6b1eab..75341f8c8f8725fca94e2a34bc3dd58e8fa8e641 100644
Binary files a/libs/mytap-1.0.zip and b/libs/mytap-1.0.zip differ
diff --git a/patches/applyPatches.sh b/patches/applyPatches.sh
index ffaa06a782c3dfeababff092158bc5990f11220e..306e6d976aae09410c8c24db791448842a740162 100755
--- a/patches/applyPatches.sh
+++ b/patches/applyPatches.sh
@@ -47,4 +47,5 @@ do
 done
 
 cd ../
+
 $UTILSPATH/update_sql_procedures.sh
diff --git a/patches/patch20170316-2.0.27/patch.sh b/patches/patch20170316-2.0.27/patch.sh
index 504b5dcca20004806cf49ec16b574f3128af8d5b..fb46b77407e819d7f0984752bfa4047858960ece 100755
--- a/patches/patch20170316-2.0.27/patch.sh
+++ b/patches/patch20170316-2.0.27/patch.sh
@@ -35,7 +35,12 @@ fi
 
 check_version $OLD_VERSION
 
-mysql_execute 'DELETE FROM `entities` WHERE id=6; ALTER TABLE `entities` MODIFY COLUMN `role` ENUM("RECORDTYPE","RECORD","FILE","DOMAIN","PROPERTY","DATATYPE","ROLE","QUERYTEMPLATE") NOT NULL; INSERT INTO entities (id, name, description, role, acl) VALUES (8,"QUERYTEMPLATE","The QueryTemplate role.","ROLE",0); UPDATE `entities` SET role="ROLE" WHERE id<100 and name=role; CREATE TABLE `query_template_def` (id INT UNSIGNED PRIMARY KEY, definition MEDIUMTEXT NOT NULL, CONSTRAINT `query_template_def_ibfk_1` FOREIGN KEY (`id`) REFERENCES `entities` (`id`));'
+mysql_execute '
+DELETE FROM `entities` WHERE id=6;
+ALTER TABLE `entities` MODIFY COLUMN `role` ENUM("RECORDTYPE","RECORD","FILE","DOMAIN","PROPERTY","DATATYPE","ROLE","QUERYTEMPLATE") NOT NULL;
+INSERT INTO entities (id, name, description, role, acl) VALUES (8,"QUERYTEMPLATE","The QueryTemplate role.","ROLE",0);
+UPDATE `entities` SET role="ROLE" WHERE id<100 and name=role;
+CREATE TABLE `query_template_def` (id INT UNSIGNED PRIMARY KEY, definition MEDIUMTEXT NOT NULL, CONSTRAINT `query_template_def_ibfk_1` FOREIGN KEY (`id`) REFERENCES `entities` (`id`));'
 
 update_version $NEW_VERSION
 
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/patch20241024-8.0.0/patch.sh b/patches/patch20241024-8.0.0/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..2573c95864518363088af121a705d87f786b07ca
--- /dev/null
+++ b/patches/patch20241024-8.0.0/patch.sh
@@ -0,0 +1,41 @@
+#!/bin/bash
+#
+# This file is a part of the LinkAhead Project.
+#
+# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2024 Timm Fitschen <t.fitschen@indiscale.com>
+# Copyright (C) 2024 Florian Spreckelsen <f.spreckelsen@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 v8.0.0
+#
+# The patch is empty because the change has to be applied manually
+# from ../../dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh if necessary.
+
+NEW_VERSION="v8.0.0"
+OLD_VERSION="v7.0.2"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+update_version $NEW_VERSION
+
+success
diff --git a/patches/patch20250130-8.1.0/patch.sh b/patches/patch20250130-8.1.0/patch.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5a092150f217c44d100a15735523ef74ea613a8b
--- /dev/null
+++ b/patches/patch20250130-8.1.0/patch.sh
@@ -0,0 +1,99 @@
+#!/bin/bash
+#
+# This file is a part of the Linkahead Project.
+#
+# Copyright (C) 2025 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2025 Daniel Hornung <d.hornung@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 v8.1.0
+#
+# Set the collation so that accents on characters become relevant.
+
+OLD_VERSION="v8.0.0"
+NEW_VERSION="v8.1.0"
+
+if [ -z "$UTILSPATH" ]; then
+  UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+# Update charsets and collations.
+
+# Change database default.
+mysql_execute "ALTER DATABASE \`$DATABASE_NAME\` COLLATE = 'uca1400_as_ci';"
+
+# Some columns should be changed manually to prevent text length changes.
+mysql_execute "ALTER TABLE desc_overrides MODIFY description TEXT CHARACTER SET utf8mb4;"
+mysql_execute "ALTER TABLE entities MODIFY description TEXT CHARACTER SET utf8mb4;"
+mysql_execute "ALTER TABLE permissions MODIFY permissions MEDIUMTEXT CHARACTER SET utf8mb4 NOT NULL;"
+mysql_execute "ALTER TABLE query_template_def MODIFY definition MEDIUMTEXT CHARACTER SET utf8mb4 NOT NULL;"
+mysql_execute "ALTER TABLE roles MODIFY description MEDIUMTEXT CHARACTER SET utf8mb4;"
+mysql_execute "ALTER TABLE text_data MODIFY value TEXT CHARACTER SET utf8mb4 NOT NULL;"
+
+# Remove some constraints first.
+mysql_execute 'ALTER TABLE user_info DROP FOREIGN KEY `subjects_ibfk_2`;'
+
+# Get all tables, drop first line, take first column
+tables=$(mysql_execute "SHOW TABLE status where Collation='utf8mb3_unicode_ci';" -B | tail +2 | awk '{print $1}')
+for table in $tables; do
+    mysql_execute "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE uca1400_as_ci;"
+done
+
+# Add constraints again.
+mysql_execute 'ALTER TABLE user_info MODIFY COLUMN `entity` VARCHAR(255) COLLATE utf8mb4_bin DEFAULT NULL;'
+mysql_execute 'ALTER TABLE user_info ADD CONSTRAINT `subjects_ibfk_2` FOREIGN KEY (`entity`) REFERENCES `entity_ids` (`id`);'
+
+# Set custom collations for columns
+mysql_execute "ALTER TABLE transaction_log MODIFY entity_id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;"
+
+
+### Finished ###
+
+update_version $NEW_VERSION
+
+success
+
+
+##### Useful commands #####
+
+# cd git/caosdb-mysqlbackend/
+# UTILSPATH=utils
+# . utils/patch_header.sh
+
+
+# show table status where Collation='utf8mb3_unicode_ci';
+
+# name_data
+# text_data
+
+# show table status like 'name_data';
+# select * from name_data where value like 'Yield%';
+# update name_data SET value='Yield-stréss' where entity_id=354;
+# update name_data SET value='Yield-strés😋s' where entity_id=354;
+# select * from name_data where value='Yield-stress';
+
+# # Unicode 14.0.0
+# ALTER TABLE name_data CONVERT TO CHARACTER SET utf8mb4 COLLATE uca1400_as_ci;
+
+# FULL_COLLATION_NAME: utf8mb4_uca1400_as_ci;
+# COLLATION_NAME: uca1400_as_ci;
+
+# mariadb -h sqldb -u caosdb -prandom1234 --default-character-set=utf8mb4 caosdb
+
diff --git a/procedures/deleteEntity.sql b/procedures/deleteEntity.sql
index 7a195399b6c71ae68b26e2f74c53ab871ae05b0e..986a7908cb5ceb06c986c46cb7deac1b880e8f69 100644
--- a/procedures/deleteEntity.sql
+++ b/procedures/deleteEntity.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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,37 +29,43 @@ 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 file_id=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 916ddcba2751b9251ff2ddc387201e0ad9eebc3b..9216d9436c3b139ea68199940a5259512aa16133 100644
--- a/procedures/deleteEntityProperties.sql
+++ b/procedures/deleteEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 cc9acd08059b2656ee934ba4a47f1c48dcdf5601..517912b73527ab7725d433c0cd91d7702b447e1c 100644
--- a/procedures/deleteIsaCache.sql
+++ b/procedures/deleteIsaCache.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 241474cb8dbf20f9caa9050aed9cbb600a8cef6d..a71c0c729f9fae5e710b8cfd8e37618e7615ff20 100644
--- a/procedures/entityVersioning.sql
+++ b/procedures/entityVersioning.sql
@@ -1,9 +1,9 @@
 /*
  * This file is a part of the LinkAhead Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
- *
+ * Copyright (C) 2020-2024 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2024 Daniel Hornung <d.hornung@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
@@ -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;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
 
-    DELETE FROM entity_version WHERE entity_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
+ * HeadOffset : 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,
-    Offset INT UNSIGNED)
+    EntityID VARCHAR(255),
+    HeadOffset 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,9 +309,9 @@ 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
+            LIMIT 1 OFFSET HeadOffset
         );
 END;
 //
@@ -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,56 +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
- * ----------
- * EntityID
- *   The file's id.
- * FilePath
- *   Path of the file in the internal file system.  If NULL, an existing file
- *   entity is simply deleted.
- * FileSize
- *   Size of the file in bytes.
- * FileHash
- *   A Sha512 Hash of the file.
- */
-CREATE PROCEDURE setFileProperties (
-    in EntityID INT UNSIGNED,
-    in FilePath TEXT,
-    in FileSize BIGINT UNSIGNED,
-    in FileHash 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 = EntityID;
-
-        INSERT INTO archive_files (file_id, path, size, hash,
-                _iversion)
-            SELECT file_id, path, size, hash, IVersion AS _iversion
-            FROM files
-            WHERE file_id = EntityID;
-    END IF;
-
-    DELETE FROM files WHERE file_id = EntityID;
-
-    IF FilePath IS NOT NULL THEN
-        INSERT INTO files (file_id, path, size, hash)
-            VALUES (EntityID, FilePath, FileSize, unhex(FileHash));
-    END IF;
-
-END //
-
-
 DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef //
 
 /**
@@ -469,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
@@ -480,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?
@@ -494,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.
@@ -507,7 +479,7 @@ retrieveQueryTemplateDefBody: BEGIN
 
             SELECT definition
             FROM archive_query_template_def
-            WHERE id = EntityID
+            WHERE id = InternalEntityID
             AND _iversion = IVersion;
 
             LEAVE retrieveQueryTemplateDefBody;
@@ -516,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 b99d6a6c1e80831c392a11a3b4212538afad5887..1eae0729db3af3b8c06cf4ea27bebf77a17679a7 100644
--- a/procedures/getDependentEntities.sql
+++ b/procedures/getDependentEntities.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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
@@ -18,56 +19,76 @@
  * 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 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 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 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/getFileIdByPath.sql b/procedures/getFileIdByPath.sql
index 81326400f8ca54b8474f4b0ae20283a5f3a82ceb..d73a20698d67c7c94b5057cba305a4922ff64495 100644
--- a/procedures/getFileIdByPath.sql
+++ b/procedures/getFileIdByPath.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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,16 +18,27 @@
  *
  * 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.getFileIdByPath;
 Delimiter //
-Create Procedure db_5_0.getFileIdByPath (in FilePath VARCHAR(255))
-BEGIN 
 
-Select file_id as FileID from files where path=FilePath LIMIT 1;
+/*
+ * Return a file's id for a given path or nothing if the path is unknown.
+ *
+ * Parameters
+ * ----------
+ * FilePath : TEXT
+ *    The file's path.
+ *
+ * Returns
+ * -------
+ * EntityID : VARCHAR(255)
+ */
+Create Procedure db_5_0.getFileIdByPath (in FilePath TEXT)
+BEGIN
+
+    SELECT e.id AS FileID FROM files AS f LEFT JOIN entity_ids ON e.internal_in = f.file_id WHERE f.path=FilePath LIMIT 1;
 
 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 649127105aca34c56ae8fb7eac1433c3f0898714..0000000000000000000000000000000000000000
--- a/procedures/getInfo.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 ab1955d9416400d8d4ceeafc030bba29cd4ba2db..0000000000000000000000000000000000000000
--- a/procedures/getRole.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 d1350175acd198cfd645c1a54ec478f5409d1832..0000000000000000000000000000000000000000
--- a/procedures/initAutoIncrement.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 e05fdb4e008213b619ac47e4125fc3cc9844a47a..6b47b505f296d3dc662852bb609552643efc0dc1 100644
--- a/procedures/insertEntity.sql
+++ b/procedures/insertEntity.sql
@@ -1,11 +1,10 @@
 /*
  * ** header v3.0
- * This file is a part of the LinkAhead 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,17 +43,17 @@ ACL : VARBINARY(65525)
 Select
 ======
 
-A tuple (EntityID, Version)
+(Version)
 */
-CREATE PROCEDURE db_5_0.insertEntity(in EntityName VARCHAR(255), in EntityDesc TEXT, in EntityRole VARCHAR(255), in ACL VARBINARY(65525))
+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);
 
@@ -63,13 +62,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
@@ -77,10 +78,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;
 
 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 b2e926a1659f76e50242e40e2d318062564dea17..872ee1d47dea7fca09b60586efbd4189a5a6149a 100644
--- a/procedures/insertEntityProperty.sql
+++ b/procedures/insertEntityProperty.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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/insertIsaCache.sql b/procedures/insertIsaCache.sql
index eaa83f104a273997f80f7276da548af3a812db50..d0273e39b88ce4c37ca2a9a2dcd32852403d199a 100644
--- a/procedures/insertIsaCache.sql
+++ b/procedures/insertIsaCache.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 392b6668c7e1fe8bb743afa37cb51f35e52b624c..0000000000000000000000000000000000000000
--- a/procedures/insertUser.sql
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 489a63e47a1185d6e221fedbe5a3aec65f0470f3..98d9387077d89f3173fa939f6d7517bfbe95ebff 100644
--- a/procedures/isSubtype.sql
+++ b/procedures/isSubtype.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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/overrideName.sql b/procedures/overrideName.sql
index 8ee39d25739220705d20688fe217a06fc0a18694..f8921330fcfa44c5f056dd2072fb8d781b7e2993 100644
--- a/procedures/overrideName.sql
+++ b/procedures/overrideName.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 642e7806b47dae6848e77126f6a5c413ac9615db..062de92d9f1dc477a72dfda3285af9133b24ae98 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 LinkAhead 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 9fb9101260e61b33439cb7d5ea6e2e3a9ff5ca2d..a038e4c7961c9c3a01f725c210dec4cfb9029eeb 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 LinkAhead 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 63267a4505040c186721a367d141ac566cb30bc4..0d2490b43b17ecc4157156db0d2d2be84bd58d3b 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 LinkAhead 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 777ddcc90f87b1a9cfe2d3ae70b64ce2c5ce25f7..6b3be3cdd2f97737ec8cb92a77040076027f1927 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 LinkAhead 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 cb7822b8426d95dad2c159a23deaa1882c46cd78..cd1d35b1a4301b978ecc6bbd70653d222f949c96 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,11 +78,12 @@ 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=?;');
+        SET @query_param = eid;
         PREPARE initEntityStmt FROM @initEntityStmtStr;
-        EXECUTE initEntityStmt;
+        EXECUTE initEntityStmt USING @query_param;
         DEALLOCATE PREPARE initEntityStmt;
     END IF;
 
diff --git a/procedures/query/initPOV.sql b/procedures/query/initPOV.sql
index f5c1d1d95d63bde8d18de8f6065ded150213594c..4f132219c3c0dc9fdea76a76f943199551d6f079 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 LinkAhead 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 27fa2b0669bb8d4d776fce8baf0583bf5b8039b8..a6c4955954908699710849f1cc12e4f45b101c30 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 LinkAhead 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 03b0111dbcffea357ddadd8f1c4a1e842e7ad1a4..18d7082319866603a9abda158d357781112be37c 100644
--- a/procedures/registerSubdomain.sql
+++ b/procedures/registerReplacementIds.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 1a32d7f92a23b88dce5b71efc6e10d4dc733f1a8..0000000000000000000000000000000000000000
--- a/procedures/retrieveDatatype.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 8ecfea0c787f165970fe0cbf22e344dd0c7398c3..3e0aeb580cdb3ff26da6bee6167b9ba5ad63a94d 100644
--- a/procedures/retrieveEntity.sql
+++ b/procedures/retrieveEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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,30 +33,40 @@ 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 (Datatype, Collection, EntityID, EntityName, EntityDesc,
- *           EntityRole, FileSize, FilePath, FileHash, ACL, Version)
+ * Tuple of (DatatypeID, DatatypeName, Collection, EntityID, EntityName,
+ *           EntityDesc, EntityRole, FileSize, FilePath, FileHash, ACL,
+ *           Version)
  */
 create procedure db_5_0.retrieveEntity(
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveEntityBody: BEGIN
     DECLARE FilePath VARCHAR(255) DEFAULT NULL;
     DECLARE FileSize VARCHAR(255) DEFAULT NULL;
     DECLARE FileHash VARCHAR(255) 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
@@ -73,7 +80,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.
@@ -84,16 +91,16 @@ retrieveEntityBody: BEGIN
             SELECT path, size, HEX(hash)
                 INTO FilePath, FileSize, FileHash
                 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;
 
@@ -102,7 +109,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;
 
@@ -111,18 +118,17 @@ 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
-                    -- LIMIT 1 -- TODO Remove this line if all tests pass.
                     ) AS EntityName,
                 e.description AS EntityDesc,
                 e.role AS EntityRole,
@@ -132,7 +138,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;
 
@@ -145,33 +151,34 @@ retrieveEntityBody: BEGIN
     SELECT path, size, hex(hash)
         INTO FilePath, FileSize, FileHash
         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,
@@ -180,7 +187,7 @@ retrieveEntityBody: BEGIN
         FileHash AS FileHash,
         (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/retrieveEntityOverrides.sql b/procedures/retrieveEntityOverrides.sql
index ab3d1c11f34977fcea63f6d0b572c235366c19a7..d66e60a6bd8dbe509ff989522cc4e84b38b6f8cc 100644
--- a/procedures/retrieveEntityOverrides.sql
+++ b/procedures/retrieveEntityOverrides.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 c1378197b12b833b54f8fb22d41cb2d8ee2aa21e..5895a233a63bf51ac597b2e3c80a722e821a2f6c 100644
--- a/procedures/retrieveEntityParents.sql
+++ b/procedures/retrieveEntityParents.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 5eee63c6c8eb1353135bf269fe86bc10a7baa89c..7918f0eb3669b11ddcb1c1fd0e651fe3fd69b276 100644
--- a/procedures/retrieveEntityProperties.sql
+++ b/procedures/retrieveEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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/retrieveGroup.sql b/procedures/retrieveGroup.sql
deleted file mode 100644
index 38504b093f40da27b01d82e51d2d4e1c308745c8..0000000000000000000000000000000000000000
--- a/procedures/retrieveGroup.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 a7f2fb6b3bea081786cd65eec9ae253cbaa4b901..0000000000000000000000000000000000000000
--- a/procedures/retrieveSubentity.sql
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 //
-/**
-CREATE PROCEDURE db_5_0.retrieveSubEntity(in EntityID INT UNSIGNED, in DomainID INT UNSIGNED)
-BEGIN
-	DECLARE FilePath VARCHAR(255) DEFAULT NULL;
-	DECLARE FileSize VARCHAR(255) DEFAULT NULL;
-	DECLARE FileHash VARCHAR(255) DEFAULT NULL;
-	
-	Select path, size, hex(hash) into FilePath, FileSize, FileHash from files where file_id = EntityID LIMIT 1;
-		Select DomainID as DomainID,
-			EntityID as EntityID, 
-			e.name as EntityName, 
-			e.description as EntityDesc, 
-			e.role as EntityRole, 
-			FileSize as FileSize, 
-			FilePath as FilePath, 
-			FileHash as FileHash 
-		from entities e where id = EntityID LIMIT 1;
-
-END;
-//
-
-**/
-DELIMITER ;
diff --git a/procedures/setFileProperties.sql b/procedures/setFileProperties.sql
new file mode 100644
index 0000000000000000000000000000000000000000..e1efa3f4c200f37a4d1c1769ca6db1d31d27f62a
--- /dev/null
+++ b/procedures/setFileProperties.sql
@@ -0,0 +1,73 @@
+/*
+ * 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 //
+/**
+ * Update file properties.
+ *
+ * If ENTITY_VERSIONING is enabled the old file properties are moved to
+ * `archive_files`.
+ *
+ * Parameters
+ * ----------
+ * EntityID : VARCHAR(255)
+ *   The file's id.
+ * FilePath : TEXT
+ *   Path of the file in the internal file system.  If NULL, an existing file
+ *   entity is simply deleted.
+ * FileSize : BIGINT UNSIGNED
+ *   Size of the file in bytes.
+ * FileHash : VARCHAR(255)
+ *   A Sha512 Hash of the file.
+ */
+CREATE PROCEDURE setFileProperties (
+    in EntityID VARCHAR(255),
+    in FilePath TEXT,
+    in FileSize BIGINT UNSIGNED,
+    in FileHash VARCHAR(255)
+)
+BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+    DECLARE IVersion INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
+    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,
+                _iversion)
+            SELECT file_id, path, size, hash, IVersion AS _iversion
+            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)
+            VALUES (InternalEntityID, FilePath, FileSize, unhex(FileHash));
+    END IF;
+
+END //
+DELIMITER ;
diff --git a/procedures/setPassword.sql b/procedures/setPassword.sql
deleted file mode 100644
index 0302dd69c6eae34fe38a0dfcc8ed56a8046ec809..0000000000000000000000000000000000000000
--- a/procedures/setPassword.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the LinkAhead 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 96a140b2354a3ba17e8c7c6a5783729c4dbee21a..bdfe05b92cccb7c424e1a5b70759a15c7d9612dc 100644
--- a/procedures/updateEntity.sql
+++ b/procedures/updateEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the LinkAhead 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 014e480e7a5423093b2a9f74b14cec4a7e54ad70..1fdb96dbf1e3fc35aba9b7d9ac7ad5e2fb45ad40 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 ebec7304fd753261775a40a8ccfd8e765136ec0e..6d62a0ced953fddc7afe1ccc06d45ef339e8f47e 100644
--- a/tests/test_autotap.sql
+++ b/tests/test_autotap.sql
@@ -38,7 +38,11 @@ SELECT tap.has_schema('_caosdb_schema_unit_tests','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','archive_isa','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','archive_isa','utf8_unicode_ci','');
+-- *******
+-- Collation testing of tables fails for uca1400 collations, see upstream issue:
+-- https://github.com/hepabolu/mytap/issues/58
+-- *******
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','archive_isa','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','archive_isa','InnoDB','');
 
 -- COLUMNS
@@ -116,7 +120,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','archive_isa','archive_isa_i
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','collection_type','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','collection_type','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','collection_type','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','collection_type','InnoDB','');
 
 -- COLUMNS
@@ -155,8 +159,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','collection_type','collection'
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','collection_type','collection','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','collection_type','collection','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','collection_type','collection',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','collection_type','collection','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','collection_type','collection','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','collection_type','collection','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','collection_type','collection','utf8mb4_uca1400_as_ci','');
 
 -- INDEXES
 SELECT tap.indexes_are('_caosdb_schema_unit_tests','collection_type','`domain_id`,`entity_id`,`property_id`','');
@@ -208,7 +212,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','collection_type','collectio
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','data_type','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','data_type','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','data_type','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','data_type','InnoDB','');
 
 -- COLUMNS
@@ -300,7 +304,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','data_type','datatype_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','date_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','date_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','date_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','date_data','InnoDB','');
 
 -- COLUMNS
@@ -348,8 +352,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','date_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','date_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','date_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','date_data','status','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','date_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','date_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','date_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','date_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN date_data.pidx
 
@@ -398,7 +402,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','date_data','date_ov_forkey_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','datetime_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','datetime_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','datetime_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','datetime_data','InnoDB','');
 
 -- COLUMNS
@@ -437,8 +441,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','datetime_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','datetime_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','datetime_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','datetime_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','datetime_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','datetime_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','datetime_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','datetime_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN datetime_data.pidx
 
@@ -505,7 +509,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','datetime_data','dat_propert
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','desc_overrides','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','desc_overrides','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','desc_overrides','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','desc_overrides','InnoDB','');
 
 -- COLUMNS
@@ -544,8 +548,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','desc_overrides','description'
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','desc_overrides','description','text','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','desc_overrides','description','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','desc_overrides','description','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8mb4_uca1400_as_ci','');
 
 -- INDEXES
 SELECT tap.indexes_are('_caosdb_schema_unit_tests','desc_overrides','`desc_ov_dom_ent_idx`','');
@@ -590,7 +594,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','desc_overrides','desc
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','double_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','double_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','double_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','double_data','InnoDB','');
 
 -- COLUMNS
@@ -638,8 +642,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','double_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','double_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','double_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','double_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','double_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','double_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','double_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','double_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN double_data.pidx
 
@@ -697,7 +701,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','double_data','dou_property_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','entities','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entities','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entities','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entities','InnoDB','');
 
 -- COLUMNS
@@ -718,17 +722,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','entities','description','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','description','text','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','entities','description','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','entities','description','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','description','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','description','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description','utf8mb4_uca1400_as_ci','');
 
 -- 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\')','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'_REPLACEMENT\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\')','');
 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','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','role','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','role','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','role','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN entities.acl
 
@@ -760,7 +764,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','entities','`id`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','entity_acl','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_acl','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_acl','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entity_acl','InnoDB','');
 
 -- COLUMNS
@@ -807,7 +811,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','entity_acl','`id`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','enum_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','enum_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','enum_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','enum_data','InnoDB','');
 
 -- COLUMNS
@@ -855,8 +859,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','enum_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','enum_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','enum_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','enum_data','status','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','enum_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','enum_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','enum_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','enum_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN enum_data.pidx
 
@@ -905,7 +909,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','enum_data','enum_ov_forkey_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','files','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','files','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','files','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','files','InnoDB','');
 
 -- COLUMNS
@@ -926,8 +930,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','files','path','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','path','varchar(255)','');
 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','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','path','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','path','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','path','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN files.size
 
@@ -977,7 +981,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','files','`file_id`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','integer_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','integer_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','integer_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','integer_data','InnoDB','');
 
 -- COLUMNS
@@ -1025,8 +1029,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','integer_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','integer_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','integer_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','integer_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','integer_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','integer_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','integer_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','integer_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN integer_data.pidx
 
@@ -1084,7 +1088,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','integer_data','int_property
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','isa_cache','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','isa_cache','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','isa_cache','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','isa_cache','InnoDB','');
 
 -- COLUMNS
@@ -1114,8 +1118,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','isa_cache','rpath','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','isa_cache','rpath','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','isa_cache','rpath','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','isa_cache','rpath',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8mb4_uca1400_as_ci','');
 
 -- CONSTRAINTS
 SELECT tap.constraints_are('_caosdb_schema_unit_tests','isa_cache','`PRIMARY`,`isa_cache_child_entity`,`isa_cache_parent_entity`','');
@@ -1145,7 +1149,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','isa_cache','`child`,`parent`,`
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','name_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','name_data','InnoDB','');
 
 -- COLUMNS
@@ -1184,8 +1188,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_data','value','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_data','value','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_data','value','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_data','value',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','value','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','value','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','value','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','value','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN name_data.status
 
@@ -1193,8 +1197,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN name_data.pidx
 
@@ -1266,7 +1270,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','name_data','name_data_prope
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','name_overrides','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_overrides','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_overrides','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','name_overrides','InnoDB','');
 
 -- COLUMNS
@@ -1305,8 +1309,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_overrides','name','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_overrides','name','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_overrides','name','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_overrides','name','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_overrides','name','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_overrides','name','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_overrides','name','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_overrides','name','utf8mb4_uca1400_as_ci','');
 
 -- INDEXES
 SELECT tap.indexes_are('_caosdb_schema_unit_tests','name_overrides','`name_ov_dom_ent_idx`','');
@@ -1351,7 +1355,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','name_overrides','name
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','null_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','null_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','null_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','null_data','InnoDB','');
 
 -- COLUMNS
@@ -1390,8 +1394,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','null_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','null_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','null_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','null_data','status','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','null_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','null_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','null_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','null_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN null_data.pidx
 
@@ -1440,7 +1444,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','null_data','null_forkey_pro
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','passwd','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','passwd','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','passwd','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','passwd','InnoDB','');
 
 -- COLUMNS
@@ -1470,8 +1474,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','passwd','alg','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','passwd','alg','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','passwd','alg','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','passwd','alg','\'SHA-512\'','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','passwd','alg','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','passwd','alg','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','passwd','alg','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','passwd','alg','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN passwd.it
 
@@ -1505,7 +1509,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','passwd','`principal`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','permissions','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','permissions','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','permissions','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','permissions','InnoDB','');
 
 -- COLUMNS
@@ -1526,8 +1530,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','permissions','permissions',''
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','permissions','permissions','mediumtext','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','permissions','permissions','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','permissions','permissions',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','permissions','permissions','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','permissions','permissions','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','permissions','permissions','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','permissions','permissions','utf8mb4_uca1400_as_ci','');
 
 -- CONSTRAINTS
 SELECT tap.constraints_are('_caosdb_schema_unit_tests','permissions','`PRIMARY`,`perm_name_roles`','');
@@ -1550,7 +1554,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','permissions','`role`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','query_template_def','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','query_template_def','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','query_template_def','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','query_template_def','InnoDB','');
 
 -- COLUMNS
@@ -1571,8 +1575,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','query_template_def','definiti
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','query_template_def','definition','mediumtext','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','query_template_def','definition','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','query_template_def','definition',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8mb4_uca1400_as_ci','');
 
 -- CONSTRAINTS
 SELECT tap.constraints_are('_caosdb_schema_unit_tests','query_template_def','`PRIMARY`,`query_template_def_ibfk_1`','');
@@ -1595,7 +1599,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','query_template_def','query_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','reference_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','reference_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','reference_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','reference_data','InnoDB','');
 
 -- COLUMNS
@@ -1643,8 +1647,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','reference_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','reference_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','reference_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','reference_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','reference_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','reference_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','reference_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','reference_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN reference_data.pidx
 
@@ -1722,7 +1726,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','reference_data','reference_
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','roles','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','roles','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','roles','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','roles','InnoDB','');
 
 -- COLUMNS
@@ -1743,8 +1747,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','roles','description','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','roles','description','mediumtext','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','roles','description','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','roles','description','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','roles','description','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','roles','description','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','roles','description','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','roles','description','utf8mb4_uca1400_as_ci','');
 
 -- CONSTRAINTS
 SELECT tap.constraints_are('_caosdb_schema_unit_tests','roles','`PRIMARY`','');
@@ -1760,7 +1764,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','roles','`name`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','stats','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','stats','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','stats','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','stats','InnoDB','');
 
 -- COLUMNS
@@ -1772,8 +1776,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','stats','name','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','stats','name','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','stats','name','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','stats','name',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','stats','name','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','stats','name','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','stats','name','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','stats','name','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN stats.value
 
@@ -1798,7 +1802,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','stats','`name`','');
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','text_data','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','text_data','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','text_data','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','text_data','InnoDB','');
 
 -- COLUMNS
@@ -1837,8 +1841,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','text_data','value','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','text_data','value','text','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','text_data','value','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','text_data','value',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','value','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','value','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','value','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','value','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN text_data.status
 
@@ -1846,8 +1850,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','text_data','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','text_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','text_data','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','text_data','status',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','status','utf8mb4_uca1400_as_ci','');
 
 -- COLUMN text_data.pidx
 
@@ -1896,7 +1900,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','text_data','str_property_id
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','transaction_log','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','transaction_log','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','transaction_log','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','transaction_log','InnoDB','');
 
 -- COLUMNS
@@ -1908,17 +1912,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','transaction_log','transaction
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','transaction','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','transaction_log','transaction','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','transaction_log','transaction',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8mb4_uca1400_as_ci','');
 
 -- 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
 
@@ -1970,7 +1974,7 @@ SELECT tap.is_indexed('_caosdb_schema_unit_tests','transaction_log','`entity_id`
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','units_lin_con','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','units_lin_con','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','units_lin_con','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','units_lin_con','InnoDB','');
 
 -- COLUMNS
@@ -2044,7 +2048,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','units_lin_con','`signature_fro
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','user_info','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_info','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_info','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','user_info','InnoDB','');
 
 -- COLUMNS
@@ -2083,17 +2087,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','user_info','status','');
 SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','status','enum(\'ACTIVE\',\'INACTIVE\')','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','user_info','status','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','user_info','status','\'INACTIVE\'','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','status','utf8','');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','utf8_unicode_ci','');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','status','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','utf8mb4_uca1400_as_ci','');
 
 -- 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`','');
@@ -2105,7 +2109,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
 
@@ -2115,17 +2119,17 @@ 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
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','user_roles','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_roles','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_roles','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','user_roles','InnoDB','');
 
 -- COLUMNS
@@ -2179,7 +2183,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_roles','user_roles_ibf
 -- ***************************************************************
 
 SELECT tap.has_table('_caosdb_schema_unit_tests','entity_version','');
-SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_version','utf8_unicode_ci','');
+-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_version','utf8mb4_uca1400_as_ci','');
 SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entity_version','InnoDB','');
 
 -- COLUMNS
@@ -2509,20 +2513,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getFileIdByPa
 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','');
@@ -2586,13 +2576,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','');
@@ -2649,12 +2632,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
 
@@ -2677,13 +2660,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','');
@@ -2691,13 +2667,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','');
@@ -2754,12 +2723,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 f54e7d0526e47654fd1f06643b71b0b6d1aadc81..eb01deb2ec2a25b9117c3855c129d814f77f552b 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 LinkAhead 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 ea82fbdd3369c7c8cb1bdda6eee0242cd3231075..768d090245fc6a6a280377959e2c326a7f60ec59 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 LinkAhead 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/linkahead/linkahead-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 1226229786d511824cd975053151ed78b7b91a61..1b77f7cb984742e40b50ad287789073042ad6daf 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 LinkAhead 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;
@@ -37,9 +34,14 @@ 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 @EntityID=99;
+SET @EntityID="99";
 SET @PropertyID=11;
 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";
@@ -49,16 +51,16 @@ 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(50, 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
@@ -69,39 +71,43 @@ INSERT INTO feature_config (_key, _value) VALUES ("ENTITY_VERSIONING", "ENABLED"
 
 
 -- TEST insertEntityProperty with Versioning - REFERENCE HEAD
-SET @VALUE="50";
 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(50, 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
-CALL insert_single_child_version(50, "hashbla", "versionbla", NULL, "SRIDbla");
-CALL insert_single_child_version(50, "hashblub", "versionblub", "versionbla", "SRIDblub");
-
-SET @VALUE="50@versionbla";
+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(50, 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 @VALUE="50@versionblub";
 CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
@@ -109,12 +115,12 @@ CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value,
 
 -- 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(50, 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
diff --git a/utils/backup.sh b/utils/backup.sh
index 6f2872ef49b5f33698b723d0b3d8b2e05f14e588..7b0da2284578be303f852e664702ca033c754356 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 1bb13f5bd4f4d8c57b152428acc07869fa4e0274..ff4b189bffeabf467e0725de9a4b62fe72cd6bf3 100644
--- a/utils/helpers.sh
+++ b/utils/helpers.sh
@@ -2,9 +2,9 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-# Copyright (C) 2019, 2020 Daniel Hornung (d.hornung@indiscale.com)
+# Copyright (C) 2019, 2020, 2024 Daniel Hornung (d.hornung@indiscale.com)
 # Copyright (C) 2020 Henrik tom Wörden
-# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2020, 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
@@ -34,7 +34,7 @@
 function mysql_execute {
 	  #TODO is it meaningful that here always the database user is used???
 	  set -e
-	  $MYSQL_CMD $(get_db_args) -e "$1"
+	  $MYSQL_CMD $(get_db_args) -e "$@"
 	  ret=${PIPESTATUS[0]}
 	  if [ "$ret" -ne 0 ]; then
 		    failure "MYSQL ERROR"
@@ -52,47 +52,31 @@ function mysql_execute_file {
 	fi
 }
 
-
-function get_mysql_args {
-	echo "$(get_mysql_args_nodb) --database=$DATABASE_NAME"
-}
-
+# Return the arguments from `get_db_args_nodb` and additionally the database name as
+# `--database=mydatabasename`.
 function get_db_args {
 	echo "$(get_db_args_nodb) --database=$DATABASE_NAME"
 }
 
+# Return arguments for user, password, host, port and additional options in MYSQL_OPTS.
+#
+# For example, the output may be:
+# --user=myuser --password=mypassword --host=example.com --port=1234 --other --option
 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 44d8f2d630270727a3a7cbd08f4b3ee037e6a7d7..8531113afa5f670400988f92692a59a031c91a11 100644
--- a/utils/load_settings.sh
+++ b/utils/load_settings.sh
@@ -2,9 +2,9 @@
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 #   Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-# Copyright (C) 2019, 2020 Daniel Hornung (d.hornung@indiscale.com)
+# Copyright (C) 2019, 2020, 2024 Daniel Hornung <d.hornung@indiscale.com>
 # Copyright (C) 2020 Henrik tom Wörden
-# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+# Copyright (C) 2020, 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
@@ -62,9 +62,12 @@ export MYSQL_CMD
 export MYSQLDUMP_CMD
 export MYSQLADMIN_CMD
 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 ea301acc6228344feb7f8b4f7e97a55cd1919048..c7f94fd2d57944758cb48f0aedb2ac2672ec16d3 100755
--- a/utils/make_db
+++ b/utils/make_db
@@ -1,10 +1,9 @@
 #!/bin/bash
 
-# ** header v3.0
 # This file is a part of the LinkAhead Project.
 #
-# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com>
-# Copyright (C) 2019, 2020, 2021 Daniel Hornung <d.hornung@indiscale.com>
+# Copyright (C) 2021, 2024 Indiscale GmbH <info@indiscale.com>
+# Copyright (C) 2019, 2020, 2021, 2024 Daniel Hornung <d.hornung@indiscale.com>
 # Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
 # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com>
 # Copyright (C) 2020 IndiScale <info@indiscale.com>
@@ -22,7 +21,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
 
 # Although some sanity checks are performed, this script still allows lots of SQL injection
 # possibilities.
@@ -87,7 +85,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
@@ -113,7 +111,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
@@ -129,13 +127,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
@@ -144,7 +157,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.
@@ -168,7 +181,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};\"'"
@@ -182,7 +195,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';
@@ -197,16 +210,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
 }
 
@@ -235,7 +248,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
@@ -244,7 +257,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"
 }
 
 
@@ -256,5 +269,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/patch_header.sh b/utils/patch_header.sh
index 76896b067960f67a101bfa3954bbdecb4f41b31d..c7d25ae3f21ccbba30658182572177847d5610a7 100644
--- a/utils/patch_header.sh
+++ b/utils/patch_header.sh
@@ -1,12 +1,10 @@
-#
-# ** header v3.0
 # This file is a part of the LinkAhead Project.
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 # Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-# Copyright (C) 2019, 2020 Daniel Hornung <d.hornung@indiscale.com>
+# Copyright (C) 2019, 2020, 2025 Daniel Hornung <d.hornung@indiscale.com>
 # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com>
-# Copyright (C) 2020 IndiScale <info@indiscale.com>
+# Copyright (C) 2020, 2025 IndiScale <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
@@ -21,12 +19,20 @@
 # 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
-#
 
 ###############################################################################
 #                          header for patch scripts                           #
 ###############################################################################
+#
+# This file defines the following functions (see below for more detailed descriptions):
+#
+# - check_version_or_exit: Check if the stored version is as expected.
+# - update_version: Set the stored version.
+# - dump_table: Store table content into a file.
+# - redo_table: Apply the table content stored by dump_table.
+#
+# This file also sets the `errexit` option (`set -e`).
+#
 
 set -e
 
@@ -63,7 +69,7 @@ configuration make file.  Notable examples are:
 - DATABASE_USER_PW
 
 EOF
-              )
+           )
 
 function _print_help() {
   echo -e "$USAGE"
@@ -115,21 +121,51 @@ done
 if [ -n "$PATCH" ]; then
     echo -ne "applying patch $PATCH to $DATABASE_NAME ... "
 fi
-# @param $1: db version string, e.g. v2.0.0
-# @return: 0 on success, 1 on failure
-function check_version {
+
+# usage: check_version_or_exit version
+#
+# Check if the version string is as expected.  Otherwise, `exit 0`.
+#
+# Arguments
+# ---------
+#
+# version: str
+#   The expected database version string, e.g. 'v2.0.0'
+#
+# Returns
+# -------
+#
+# 0 on success
+function check_version_or_exit {
     local version=$($MYSQL_CMD $(get_db_args) -B -e "Select CaosDBVersion();")
-	  if [[ "$(echo $version | sed 's/^CaosDBVersion()\s//')" = "$1" ]]; then
+    local version="$(echo $version | sed 's/^CaosDBVersion()\s//')"
+	  if [[ "$version" = "$1" ]]; then
         return 0
 	  fi
     uptodate
 }
 
-# @param $1: new version string
+# Deprecated name, call "check_version_or_exit" directly instead.
+function check_version {
+    check_version_or_exit "$1"
+}
+
+# usage: update_version version
+#
+# Set the version string.
+#
+# Arguments
+# ---------
+#
+# version: str
+#   The new database version string, e.g. 'v2.0.0'
 function update_version {
     mysql_execute "DROP FUNCTION IF EXISTS CaosDBVersion; CREATE FUNCTION CaosDBVersion() RETURNS VARCHAR(255) DETERMINISTIC RETURN '$1';"
 }
 
+# usage: dump_table table
+#
+# Dump the table given in the argument into file "caosdb.<table>.<OLD_VERSION>.dump.sql"
 function dump_table {
     if [[ -z $MYSQLDUMP_CMD ]]; then
         echo "Cannot find mysqldump program!" >&2
@@ -139,6 +175,9 @@ function dump_table {
                     > ${DATABASE_NAME}.${1}.${OLD_VERSION}.dump.sql
 }
 
+# usage: redo_table table
+#
+# Apply the dump from `dump_table` to the database.  Takes the same argument.
 function redo_table {
          $MYSQL_CMD $(get_db_args) < ${DATABASE_NAME}.${1}.${OLD_VERSION}.dump.sql
 }
diff --git a/utils/sanity_check.sql b/utils/sanity_check.sql
new file mode 100644
index 0000000000000000000000000000000000000000..5e3d580cc386feb44b5e97269ac384c050d6cf84
--- /dev/null
+++ b/utils/sanity_check.sql
@@ -0,0 +1,121 @@
+
+
+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() AND r.table_type != 'TEMPORARY'
+  )
+  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 expec.table_name AS MATCHED, info.table_name AS WRONG FROM
+      expected_tables AS expec
+    RIGHT OUTER JOIN
+      information_schema.tables AS info
+    ON (info.table_name COLLATE utf8_unicode_ci = expec.table_name)
+    WHERE info.table_schema = database() and info.table_type != 'TEMPORARY'
+  )
+  AS temp WHERE temp.MATCHED IS NULL;
+
+SELECT "--------------";
+SELECT "ERROR" from sanity_check_failed;
+
+END;
+//
+delimiter ;
+
+CALL sanity_check();
+
+DROP PROCEDURE sanity_check;
diff --git a/utils/update_sql_procedures.sh b/utils/update_sql_procedures.sh
index bbbbc15b299cf24bcfa4c72da6a4e49534655e67..2fe1febfc7d5bbe45a8bc68c630e13d1cef6707f 100755
--- a/utils/update_sql_procedures.sh
+++ b/utils/update_sql_procedures.sh
@@ -1,13 +1,12 @@
 #!/bin/bash
 #
-# ** header v3.0
 # This file is a part of the LinkAhead Project.
 #
 # Copyright (C) 2018 Research Group Biomedical Physics,
 #   Max-Planck-Institute for Dynamics and Self-Organization Göttingen
-# Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com>
+# Copyright (C) 2020, 2024 Daniel Hornung <d.hornung@indiscale.com>
 # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com>
-# Copyright (C) 2020 IndiScale <info@indiscale.com>
+# Copyright (C) 2020, 2024 IndiScale <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
@@ -22,8 +21,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
-#
 
 # Updates all SQL procedures
 
@@ -37,7 +34,7 @@ fi
 source $UTILSPATH/load_settings.sh
 source $UTILSPATH/helpers.sh
 
-echo -n "updating procedures ... "
+echo "Updating procedures ... "
 temp_proc_sql=$(mktemp --suffix=.sql)
 sed -e "s/db_5_0/$DATABASE_NAME/g" procedures/*.sql procedures/query/*.sql \
     > "$temp_proc_sql"