diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e8bc3c8d2427efd08bae8c4ec0176b6addf642cd..4709a64daf23b5628ae69bfd8f4877cb37abbe74 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -69,7 +69,7 @@ unittests-mysql-8:
   # Should not stop the pipeline from continuing.
   allow_failure: true
   services:
-    - name: mysql:8.0
+    - name: mysql:8.0.32
       command: ["--default-authentication-plugin=mysql_native_password"]
 
   script:
@@ -84,7 +84,7 @@ unittests-mysql-5:
   # Should not stop the pipeline from continuing.
   allow_failure: true
   services:
-    - name: mysql:5.7
+    - name: mysql:5.7.36
       command: ["--default-authentication-plugin=mysql_native_password"]
 
   script:
@@ -99,17 +99,23 @@ unittests-mysql-5:
 
 # Trigger building of server image and integration tests
 trigger_build:
-  tags: [ docker ]
   stage: deploy
-  script:
-    - /usr/bin/curl -X POST
-      -F token=$CI_JOB_TOKEN
-      -F "variables[F_BRANCH]=$CI_COMMIT_REF_NAME"
-      -F "variables[MYSQLBACKEND]=$CI_COMMIT_REF_NAME"
-      -F "variables[TriggerdBy]=MYSQLBACKEND"
-      -F "variables[TriggerdByHash]=$CI_COMMIT_SHORT_SHA"
-      -F ref=$DEPLOY_REF https://gitlab.indiscale.com/api/v4/projects/14/trigger/pipeline
-
+  inherit:
+    variables:
+      # List the variables that shall be inherited, which also means they will override any equally
+      # named varibles in child pipelines.
+      - DEPLOY_REF
+  variables:
+    F_BRANCH: $CI_COMMIT_REF_NAME
+    MYSQLBACKEND: $CI_COMMIT_REF_NAME
+    TRIGGERED_BY_REPO: MYSQLBACKEND
+    TRIGGERED_BY_REF: $CI_COMMIT_REF_NAME
+    TRIGGERED_BY_HASH: $CI_COMMIT_SHORT_SHA
+
+  trigger:
+    project: caosdb/src/caosdb-deploy
+    branch: $DEPLOY_REF
+    strategy: depend
 
 # Build the sphinx documentation and make it ready for deployment by Gitlab Pages
 # Special job for serving a static website. See https://docs.gitlab.com/ee/ci/yaml/README.html#pages
diff --git a/.gitlab/issue_templates/Default.md b/.gitlab/issue_templates/Default.md
new file mode 100644
index 0000000000000000000000000000000000000000..aa1a65aca363b87aff50280e1a86824009d2098b
--- /dev/null
+++ b/.gitlab/issue_templates/Default.md
@@ -0,0 +1,28 @@
+## Summary
+
+*Please give a short summary of what the issue is.*
+
+## Expected Behavior
+
+*What did you expect how the software should behave?*
+
+## Actual Behavior
+
+*What did the software actually do?*
+
+## Steps to Reproduce the Problem
+
+*Please describe, step by step, how others can reproduce the problem.  Please try these steps for yourself on a clean system.*
+
+1.
+2.
+3.
+
+## Specifications
+
+- Version: *Which version of this software?*
+- Platform: *Which operating system, which other relevant software versions?*
+
+## Possible fixes
+
+*Do you have ideas how the issue can be resolved?*
diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md
index 2f4128ff4ada4354eb5eedf46632c2127c81cf1b..3629e0ca3695000863d8c254516f64bf59a7bf60 100644
--- a/.gitlab/merge_request_templates/Default.md
+++ b/.gitlab/merge_request_templates/Default.md
@@ -1,42 +1,51 @@
 # Summary
 
-    Insert a meaningful description for this merge request here.  What is the
-    new/changed behavior? Which bug has been fixed? Are there related Issues?
+*Insert a meaningful description for this merge request here:  What is the new/changed behavior?
+Which bug has been fixed? Are there related issues?*
+
 
 # Focus
 
-    Point the reviewer to the core of the code change. Where should they start
-    reading? What should they focus on (e.g. security, performance,
-    maintainability, user-friendliness, compliance with the specs, finding more
-    corner cases, concrete questions)?
+*Point the reviewer to the core of the code change. Where should they start reading? What should
+they focus on (e.g. security, performance, maintainability, user-friendliness, compliance with the
+specs, finding more corner cases, concrete questions)?*
+
 
 # Test Environment
 
-    How to set up a test environment for manual testing?
+*How to set up a test environment for manual testing?*
+
 
 # Check List for the Author
 
-Please, prepare your MR for a review. Be sure to write a summary and a
-focus and create gitlab comments for the reviewer. They should guide the
-reviewer through the changes, explain your changes and also point out open
-questions. For further good practices have a look at [our review
+Please, prepare your MR for a review. Be sure to write a summary and a focus and create gitlab
+comments for the reviewer. They should guide the reviewer through the changes, explain your changes
+and also point out open questions. For further good practices have a look at [our review
 guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md)
 
 - [ ] All automated tests pass
-- [ ] Reference related Issues
-- [ ] Up-to-date CHANGELOG.md
+- [ ] Reference related issues
+- [ ] Up-to-date CHANGELOG.md (or not necessary)
+- [ ] Up-to-date JSON schema (or not necessary)
+- [ ] Appropriate user and developer documentation (or not necessary)
+  - Update / write published documentation (`make doc`).
+  - How do I use the software?  Assume "stupid" users.
+  - How do I develop or debug the software?  Assume novice developers.
 - [ ] Annotations in code (Gitlab comments)
   - Intent of new code
   - Problems with old code
   - Why this implementation?
 
+
 # Check List for the Reviewer
 
 - [ ] I understand the intent of this MR
 - [ ] All automated tests pass
-- [ ] Up-to-date CHANGELOG.md
-- [ ] The test environment setup works and the intended behavior is
-  reproducible in the test environment
+- [ ] Up-to-date CHANGELOG.md (or not necessary)
+- [ ] Appropriate user and developer documentation (or not necessary), also in published
+      documentation.
+- [ ] The test environment setup works and the intended behavior is reproducible in the test
+  environment
 - [ ] In-code documentation and comments are up-to-date.
 - [ ] Check: Are there specifications? Are they satisfied?
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3bdb31195744cdf38b453e5764f7e6bee37479f2..989048b0bb0d95eed7bab913a4a6927e79ecb297 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,69 @@ 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).
 
+## [6.0.0 2023-10-17] ##
+
+This is a major update. Switching from integer ids for internal and external use to string ids for the external use while keeping the old integer ids for internal use.
+
+### Added ###
+
+* Table `entity_ids`
+* Procedure `getIdByName`
+* Procedure `insertEntityDataType` and `insertEntityCollection`
+* Procedure `setFileProperties`.
+
+### Changed ###
+
+* Rename PROCEDURE `registerSubdomain` to `registerReplacementIds`.
+* Change column `entities.role` datatype: replace 'DOMAIN' enum value with `_REPLACEMENT`.
+* Change column `transactions_log.entity_id` to VARCHAR(255)
+* Change column `user_info.entity` to VARCHAR(255)
+* Change signature of procedure `applyIDFilter` - `EntityID VARCHAR(255)`
+* Change signature of procedure `initBackreference` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)`
+* Change signature of procedure `initPOVPropertiesTable` - `PropertyID VARCHAR(255)`
+* Change signature of procedure `initPOVRefidsTable` - `PropertyID VARCHAR(255)`
+* Change signature of procedure `initSubEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `deleteEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `deleteEntityProperties` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_primary_parent_version` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_version_timestamp` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_head_version` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_head_relative` - `EntityID VARCHAR(255)`
+* Change signature of procedure `get_version_history` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveQueryTemplateDef` - `EntityID VARCHAR(255)`
+* Change signature of procedure `getDependentEntities` - `EntityID VARCHAR(255)`
+* Change signature of procedure `insertEntity` - Add parameter `EntityID VARCHAR(255)`
+* Change signature of procedure `insertEntityProperty` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)`, `DomainID VARCHAR(255)`, `DatatypeOverride VARCHAR(255)`
+* Change signature of procedure `insertIsa` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`.
+* Change signature of procedure `isSubtype` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`.
+* Change signature of procedure `retrieveEntity` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveOverrides` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)`
+* Change signature of procedure `retrieveEntityParents` - `EntityID VARCHAR(255)`
+* Change signature of procedure `retrieveEntityProperties` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)`
+* Change signature of procedure `updateEntity` - `EntityID VARCHAR(255)`
+
+### Deprecated ###
+
+### 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`.
+
+### Security ###
+
 ## [5.0.0] - 2021-10-28 ##
 
 ### Added ###
diff --git a/README.md b/README.md
index c0543b4f1a4d3fe58100e7d19de2f82f911e1ae6..7094464dae407a9eff280f2312a7b582f5f29a2b 100644
--- a/README.md
+++ b/README.md
@@ -36,14 +36,10 @@ Conduct](https://gitlab.com/linkahead/linkahead/-/blob/main/CODE_OF_CONDUCT.md).
       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.
-    * **Code style:** This project adhers to the PEP8 recommendations, you can test your code style
-      using the `autopep8` tool (`autopep8 -i -r ./`).  Please write your doc strings following the
-      [NumpyDoc](https://numpydoc.readthedocs.io/en/latest/format.html) conventions.
 * You can also  join the LinkAhead community on
   [#linkahead:matrix.org](https://matrix.to/#/!unwwlTfOznjEnMMXxf:matrix.org).
 
 ## License
-## License
 
 * Copyright (C) 2018 Research Group Biomedical Physics, Max Planck Institute
   for Dynamics and Self-Organization Göttingen.
diff --git a/README_SETUP.md b/README_SETUP.md
index 11588e7db750b2f535144c52a03dda4167dbfc22..1b88d56636ccbbbfa3ed616ff323d8e9fdf4835c 100644
--- a/README_SETUP.md
+++ b/README_SETUP.md
@@ -24,6 +24,11 @@
 * Run `make install`. If a there is a database with the name you have choosen
   during the configuration, you need to reconfigure or delete the database
   first.
+  * *Required database privileges:*
+    * If the user does not exist yet, you need the [appropriate global privileges](https://mariadb.com/kb/en/grant/#global-privileges), for example
+      `CREATE USER` and the privileges to grant that user all global privileges.  The required
+      privileges may be reduced in the future.
+    * For normal usage, [database privileges](https://mariadb.com/kb/en/grant/#database-privileges) are required.
 
 ## Upgrade the SQL database
 
diff --git a/doc/conf.py b/doc/conf.py
index ded9c5b073eab87449686d2ceb27de211bac7a31..02d6ce6b0b593134782f48314152fab8733edbd7 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -26,9 +26,9 @@ copyright = '2021, IndiScale GmbH'
 author = 'Daniel Hornung'
 
 # The short X.Y version
-version = '5.0'
+version = '6.0'
 # The full version, including alpha/beta/rc tags
-release = '5.0.0'
+release = '6.0.0'
 
 
 # -- General configuration ---------------------------------------------------
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/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..54208ab713ae9cc7bc6db8ae7501f1266e2bec86
--- /dev/null
+++ b/patches/patch20221122-6.0-SNAPSHOT/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 v5.0.0
+# Drop the 'rules' table.
+
+NEW_VERSION="v6.0.0-SNAPSHOT-EXTIDS"
+OLD_VERSION="v5.0.0"
+
+if [ -z "$UTILSPATH" ]; then
+ UTILSPATH="../utils"
+fi
+
+. $UTILSPATH/patch_header.sh $*
+
+check_version $OLD_VERSION
+
+mysql_execute_file $PATCH_DIR/create_entity_ids_table.sql
+
+update_version $NEW_VERSION
+
+success
+
diff --git a/procedures/deleteEntity.sql b/procedures/deleteEntity.sql
index 5574f3e3499a0802cd9ba176904b13016e966643..f8b026d02eb48f677d2348e5f0c059b88a821d04 100644
--- a/procedures/deleteEntity.sql
+++ b/procedures/deleteEntity.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 /* Delete a (sparse) Entity from the database.
@@ -31,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 147959df5f24dc8e67f1fbce97c609da1e31e09a..71b5651c58f5162752a4728c935a4a1a4ce66736 100644
--- a/procedures/deleteEntityProperties.sql
+++ b/procedures/deleteEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,23 +18,34 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.deleteEntityProperties;
 delimiter //
 
-CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID INT UNSIGNED)
+/*
+ * Delete all properties of an entity (i.e. remove them from the *_data tables
+ * and the isa_cache table).
+ *
+ * Parameters
+ * ==========
+ *
+ * EntityID : VARCHAR(255)
+ *    The entity's id.
+ */
+CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID VARCHAR(255))
 BEGIN
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
-    CALL deleteIsa(EntityID);
+    CALL deleteIsa(InternalEntityID);
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         SELECT max(e._iversion) INTO IVersion -- What's the latest version?
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID;
+            WHERE e.entity_id = InternalEntityID;
 
         -- Copy the rows from *_data to archive_*_data ---------------------
         INSERT INTO archive_reference_data (domain_id, entity_id,
@@ -43,142 +53,142 @@ BEGIN
             SELECT domain_id, entity_id, property_id, value, value_iversion,
                 status, pidx, IVersion AS _iversion
             FROM reference_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_null_data (domain_id, entity_id,
                 property_id, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, status,
                 pidx, IVersion AS _iversion
             FROM null_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_text_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM text_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_name_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM name_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_enum_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM enum_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_integer_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion, unit_sig)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion, unit_sig
             FROM integer_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_double_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion, unit_sig)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion, unit_sig
             FROM double_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_datetime_data (domain_id, entity_id,
                 property_id, value, value_ns, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, value_ns,
                 status, pidx, IVersion AS _iversion
             FROM datetime_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_date_data (domain_id, entity_id,
                 property_id, value, status, pidx, _iversion)
             SELECT domain_id, entity_id, property_id, value, status,
                 pidx, IVersion AS _iversion
             FROM date_data
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_name_overrides (domain_id, entity_id,
                 property_id, name, _iversion)
             SELECT domain_id, entity_id, property_id, name,
                 IVersion AS _iversion
             FROM name_overrides
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_desc_overrides (domain_id, entity_id,
                 property_id, description, _iversion)
             SELECT domain_id, entity_id, property_id, description,
                 IVersion AS _iversion
             FROM desc_overrides
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_data_type (domain_id, entity_id,
                 property_id, datatype, _iversion)
             SELECT domain_id, entity_id, property_id, datatype,
                 IVersion AS _iversion
             FROM data_type
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_collection_type (domain_id, entity_id,
                 property_id, collection, _iversion)
             SELECT domain_id, entity_id, property_id, collection,
                 IVersion AS _iversion
             FROM collection_type
-            WHERE (domain_id = 0 AND entity_id = EntityID)
-            OR domain_id = EntityID;
+            WHERE (domain_id = 0 AND entity_id = InternalEntityID)
+            OR domain_id = InternalEntityID;
 
         INSERT INTO archive_query_template_def (id, definition, _iversion)
             SELECT id, definition, IVersion AS _iversion
             FROM query_template_def
-            WHERE id = EntityID;
+            WHERE id = InternalEntityID;
 
     END IF;
 
     DELETE FROM reference_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM null_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM text_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM name_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM enum_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM integer_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM double_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM datetime_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM date_data
-    where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
     DELETE FROM name_overrides
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM desc_overrides
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
     DELETE FROM data_type
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
     DELETE FROM collection_type
-    WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID;
+    WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID;
 
-    DELETE FROM query_template_def WHERE id=EntityID;
+    DELETE FROM query_template_def WHERE id=InternalEntityID;
 
 END;
 //
diff --git a/procedures/deleteIsaCache.sql b/procedures/deleteIsaCache.sql
index fd78d3fd8a23a93b91cacedbcc28f91966c59d90..dcfb68cf694458b56401720da8c939baae770247 100644
--- a/procedures/deleteIsaCache.sql
+++ b/procedures/deleteIsaCache.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 SET GLOBAL log_bin_trust_function_creators = 1;
 
@@ -38,30 +35,30 @@ parameter entity is a child or inside the rpath.
 Parameters
 ==========
 
-EntityID : UNSIGNED
-Child entity for which all parental relations should be deleted.
+InternalEntityID : UNSIGNED
+    Child entity for which all parental relations should be deleted.
 */
-CREATE PROCEDURE db_5_0.deleteIsa(IN EntityID INT UNSIGNED)
+CREATE PROCEDURE db_5_0.deleteIsa(IN InternalEntityID INT UNSIGNED)
 BEGIN
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         SELECT max(_iversion) INTO IVersion
             FROM entity_version
-            WHERE entity_id = EntityID;
+            WHERE entity_id = InternalEntityID;
 
         -- move to archive_isa before deleting
         INSERT IGNORE INTO archive_isa (child, child_iversion, parent, direct)
-            SELECT e.child, IVersion AS child_iversion, e.parent, rpath = EntityID
+            SELECT e.child, IVersion AS child_iversion, e.parent, rpath = InternalEntityID
             FROM isa_cache AS e
-            WHERE e.child = EntityID;
+            WHERE e.child = InternalEntityID;
     END IF;
 
     DELETE FROM isa_cache
-        WHERE child = EntityID
-        OR rpath = EntityID
-        OR rpath LIKE concat('%>', EntityID)
-        OR rpath LIKE concat('%>', EntityID, '>%');
+        WHERE child = InternalEntityID
+        OR rpath = InternalEntityID
+        OR rpath LIKE concat('%>', InternalEntityID)
+        OR rpath LIKE concat('%>', InternalEntityID, '>%');
 
 END;
 //
diff --git a/procedures/entityVersioning.sql b/procedures/entityVersioning.sql
index 888fc60ac4b9a821a6b8e3446f13456abad91815..b474d0121130a1695d69616e1de4cc54468b5e64 100644
--- a/procedures/entityVersioning.sql
+++ b/procedures/entityVersioning.sql
@@ -1,8 +1,8 @@
 /*
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -27,23 +27,23 @@ DROP PROCEDURE IF EXISTS db_5_0.insert_single_child_version //
  *
  * Parameters
  * ----------
- * EntityID
- *   The ID of the versioned entity.
- * Hash
+ * InternalEntityID : INT UNSIGNED
+ *   The internal ID of the versioned entity.
+ * Hash : VARBINARY(255)
  *   A hash of the entity. This is currently not implemented properly and only
  *   there for future use.
- * Version
+ * Version : VARBINARY(255)
  *   The new version ID of the entity, must be produced by the caller.  Must be unique for each
  *   EntityID.
- * Parent
+ * Parent : VARBINARY(255)
  *   The version ID of the primary parent (i.e. predecessor).  May be NULL; but if given, it must
  *   exist.
- * Transaction
+ * Transaction : VARBINARY(255)
  *   The transaction ID which created this entity version (by inserting
  *   or updating an entity).
  */
 CREATE PROCEDURE db_5_0.insert_single_child_version(
-    in EntityID INT UNSIGNED,
+    in InternalEntityID INT UNSIGNED,
     in Hash VARBINARY(255),
     in Version VARBINARY(255),
     in Parent VARBINARY(255),
@@ -57,12 +57,12 @@ BEGIN
     IF Parent IS NOT NULL THEN
         SELECT e._iversion INTO newipparent
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             AND e.version = Parent;
         IF newipparent IS NULL THEN
             -- throw error;
             SELECT concat("This parent does not exists: ", Parent)
-            FROM nonexisting;
+            FROM parent_version_does_not_exist;
         END IF;
     END IF;
 
@@ -70,7 +70,7 @@ BEGIN
     -- generate _iversion
     SELECT max(e._iversion)+1 INTO newiversion
         FROM entity_version AS e
-        WHERE e.entity_id=EntityID;
+        WHERE e.entity_id=InternalEntityID;
     IF newiversion IS NULL THEN
         SET newiversion = 1;
     END IF;
@@ -78,7 +78,7 @@ BEGIN
     INSERT INTO entity_version
         (entity_id, hash, version, _iversion, _ipparent, srid)
         VALUES
-        (EntityID, Hash, Version, newiversion, newipparent, Transaction);
+        (InternalEntityID, Hash, Version, newiversion, newipparent, Transaction);
 
 
 
@@ -87,22 +87,28 @@ END;
 
 DROP PROCEDURE IF EXISTS db_5_0.delete_all_entity_versions //
 
+/* THIS PROCEDURE HAS NEVER BEEN USED (outside of the tests). Reactivate when
+ * versioning's FORGET is being implemented. */
 /**
  * Remove all records in the entity_version table for the given entity.
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The id of the versioned entity.
  */
-CREATE PROCEDURE db_5_0.delete_all_entity_versions(
-    in EntityID INT UNSIGNED)
+/* CREATE PROCEDURE db_5_0.delete_all_entity_versions(
+    in EntityID VARCHAR(255))
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
 
-    DELETE FROM entity_version WHERE entity_id = EntityID;
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
+    DELETE FROM entity_version WHERE entity_id = InternalEntityID;
 
 END;
 //
+*/
 
 DROP FUNCTION IF EXISTS db_5_0.get_iversion //
 
@@ -111,9 +117,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity's id.
- * Version
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
+ * Version : VARBINARY(255)
  *   The (official, externally used) version id.
  *
  * Returns
@@ -121,7 +127,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion //
  * The internal version id.
  */
 CREATE FUNCTION db_5_0.get_iversion(
-    EntityID INT UNSIGNED,
+    InternalEntityID INT UNSIGNED,
     Version VARBINARY(255))
 RETURNS INT UNSIGNED
 READS SQL DATA
@@ -129,7 +135,7 @@ BEGIN
     RETURN (
         SELECT e._iversion
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
                 AND e.version = Version
         );
 END;
@@ -143,9 +149,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Version
+ * Version : VARBINARY(255)
  *   The version id.
  *
  * Returns
@@ -153,17 +159,21 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version //
  * The id of the given version's primary parent version.
  */
 CREATE FUNCTION db_5_0.get_primary_parent_version(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Version VARBINARY(255))
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     RETURN (
         SELECT p.version
             FROM entity_version AS e INNER JOIN entity_version AS p
                 ON (e._ipparent = p._iversion
                     AND e.entity_id = p.entity_id)
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
                 AND e.version = Version
         );
 END;
@@ -177,9 +187,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Version
+ * Version : VARBINARY(255)
  *   The version id.
  *
  * Returns
@@ -188,16 +198,20 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp //
  * Note that the dot `.` here is not necessarily a decimal separator.
  */
 CREATE FUNCTION db_5_0.get_version_timestamp(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Version VARBINARY(255))
 RETURNS VARCHAR(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     RETURN (
         SELECT concat(t.seconds, '.', t.nanos)
             FROM entity_version AS e INNER JOIN transactions AS t
                 ON ( e.srid = t.srid )
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             AND e.version = Version
     );
 END;
@@ -210,7 +224,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
  *
  * Returns
@@ -218,7 +232,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version //
  * The version id of the HEAD.
  */
 CREATE FUNCTION db_5_0.get_head_version(
-    EntityID INT UNSIGNED)
+    EntityID VARCHAR(255))
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
@@ -233,15 +247,15 @@ DROP FUNCTION IF EXISTS db_5_0._get_head_iversion //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity id.
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
  *
  * Returns
  * -------
  * The _iversion of the HEAD.
  */
 CREATE FUNCTION db_5_0._get_head_iversion(
-    EntityID INT UNSIGNED)
+    InternalEntityID INT UNSIGNED)
 RETURNS INT UNSIGNED
 READS SQL DATA
 BEGIN
@@ -252,7 +266,7 @@ BEGIN
     RETURN (
         SELECT e._iversion
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             ORDER BY e._iversion DESC
             LIMIT 1
         );
@@ -267,9 +281,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
- * Offset
+ * Offset : INT UNSIGNED
  *   Distance in the sequence of primary parents of the entity. E.g. `0` is the
  *   HEAD itself. `1` is the primary parent of the HEAD. `2` is the primary
  *   parent of the primary parent of the HEAD, and so on.
@@ -279,11 +293,15 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative //
  * The version id of the HEAD.
  */
 CREATE FUNCTION db_5_0.get_head_relative(
-    EntityID INT UNSIGNED,
+    EntityID VARCHAR(255),
     Offset INT UNSIGNED)
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     -- This implementation assumes that the distance from the head equals the
     -- difference between the _iversion numbers. This will not be correct anymore
     -- as soon as branches may split and merge. Then, a walk over the primary
@@ -291,7 +309,7 @@ BEGIN
     RETURN (
         SELECT e.version
             FROM entity_version AS e
-            WHERE e.entity_id = EntityID
+            WHERE e.entity_id = InternalEntityID
             ORDER BY e._iversion DESC
             LIMIT 1 OFFSET Offset
         );
@@ -304,24 +322,24 @@ DROP FUNCTION IF EXISTS db_5_0._get_version //
  *
  * Parameters
  * ----------
- * EntityID
- *   The entity id.
+ * InternalEntityID : INT UNSIGNED
+ *   The entity's internal id.
  * IVersion
  *   Internal version id (integer).
  *
  * Returns
  * -------
- * The version id.
+ * The (external) version id.
  */
 CREATE FUNCTION db_5_0._get_version(
-    EntityID INT UNSIGNED,
+    InternalEntityID INT UNSIGNED,
     IVersion INT UNSIGNED)
 RETURNS VARBINARY(255)
 READS SQL DATA
 BEGIN
     RETURN (
         SELECT version FROM entity_version
-            WHERE entity_id = EntityID
+            WHERE entity_id = InternalEntityID
             AND _iversion = IVersion
         );
 END;
@@ -335,7 +353,7 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history //
  *
  * Parameters
  * ----------
- * EntityID
+ * EntityID : VARCHAR(255)
  *   The entity id.
  *
  * Selects
@@ -344,8 +362,12 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history //
  *   child_realm). `child` and `parent` are version IDs.
  */
 CREATE PROCEDURE db_5_0.get_version_history(
-    in EntityID INT UNSIGNED)
+    in EntityID VARCHAR(255))
 BEGIN
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID;
+
     -- retrieve root(s) (initial versions)
     SELECT c.version AS child,
             NULL as parent,
@@ -355,7 +377,7 @@ BEGIN
             t.realm AS child_realm
         FROM entity_version AS c INNER JOIN transactions as t
         ON ( c.srid = t.srid )
-        WHERE c.entity_id = EntityID
+        WHERE c.entity_id = InternalEntityID
         AND c._ipparent is Null
 
     -- TODO This first SELECT statement is necessary because the second one
@@ -375,7 +397,7 @@ BEGIN
             ON (c._ipparent = p._iversion
                 AND c.entity_id = p.entity_id
                 AND t.srid = c.srid)
-        WHERE p.entity_id = EntityID;
+        WHERE p.entity_id = InternalEntityID;
 END;
 //
 
@@ -412,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 708503d90954c8ecea1fafa67113b7130a7b6684..0940e440661c0d73f2eea03e3e10d10082c9eb9e 100644
--- a/procedures/getDependentEntities.sql
+++ b/procedures/getDependentEntities.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <www.indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -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 e565eced5b7fac23199d2ce9169fe45822dfffbc..07e7b8bcb57c61f4ff8f155537bf0d5bb8307820 100644
--- a/procedures/getFileIdByPath.sql
+++ b/procedures/getFileIdByPath.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,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 03c75b4e1df37400596c85d20e5421abc43c6f10..0000000000000000000000000000000000000000
--- a/procedures/getInfo.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-#-- old procedure.
-Drop Procedure if exists db_5_0.getInfo;
diff --git a/procedures/getRole.sql b/procedures/getRole.sql
deleted file mode 100644
index bea96fcfbf14d7ad8ec62b88c272ab22c5d94258..0000000000000000000000000000000000000000
--- a/procedures/getRole.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-
-
-
-
-
-DROP PROCEDURE IF EXISTS db_5_0.getRole;
-delimiter //
-CREATE PROCEDURE db_5_0.getRole(in RoleName VARCHAR(255))
-BEGIN
-
-Select e.id INTO @RoleID from entities e where e.name=RoleName AND e.role=RoleName LIMIT 1;
-
-call retrieveEntity(@RoleID);
-
-
-
-
-END;
-//
-delimiter ;
diff --git a/procedures/initAutoIncrement.sql b/procedures/initAutoIncrement.sql
deleted file mode 100644
index 54cb54525ee7d8b864c1e979dfda6ab9471fcfb5..0000000000000000000000000000000000000000
--- a/procedures/initAutoIncrement.sql
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-DROP PROCEDURE IF EXISTS db_5_0.initAutoIncrement;
-delimiter //
-
-CREATE PROCEDURE db_5_0.initAutoIncrement()
-BEGIN
-
-    SELECT @max := MAX(entity_id)+ 1 FROM transaction_log; 
-    IF @max IS NOT NULL THEN
-        SET @stmtStr = CONCAT('ALTER TABLE entities AUTO_INCREMENT=',@max);
-        PREPARE stmt FROM @stmtStr;
-        EXECUTE stmt;
-        DEALLOCATE PREPARE stmt;
-    END IF;
-
-END;
-//
-delimiter ;
diff --git a/procedures/insertEntity.sql b/procedures/insertEntity.sql
index e73a3bd8acc9ac7ad27f9b261c780a10939d8e8c..816fe8bae65c8a92569d4229993815d6ac0634af 100644
--- a/procedures/insertEntity.sql
+++ b/procedures/insertEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -31,12 +28,14 @@ delimiter //
 Parameters
 ==========
 
+EntityID : VARCHAR(255)
+    The entity id.
 EntityName : VARCHAR(255)
 
 EntityDesc : TEXT
 
 EntityRole : VARCHAR(255)
-Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'DOMAIN', 'PROPERTY',
+Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'PROPERTY',
 'DATATYPE', 'ROLE', 'QUERYTEMPLATE'
 
 ACL : VARBINARY(65525)
@@ -44,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..78df168f72972a2ccc8dd95792e9849d0715aaf9
--- /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.
+ * DataType : VARCHAR(255)
+ *   The data type, e.g. "DOUBLE", "Person"
+ */
+CREATE PROCEDURE db_5_0.insertEntityDataType(in PropertyID VARCHAR(255), in DataType 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 entity_id FROM name_data WHERE domain_id = 0 AND property_id = 20 AND value = DataType LIMIT 1);
+
+
+END;
+//
+DELIMITER ;
+
+
+DROP PROCEDURE IF EXISTS db_5_0.insertEntityCollection;
+DELIMITER //
+
+/*
+ * Insert the (default) collection type of a property.
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *   The property id.
+ * Collection : VARCHAR(255)
+ *   The collection, e.g. "LIST"
+ */
+CREATE PROCEDURE db_5_0.insertEntityCollection(in PropertyID VARCHAR(255), in Collection VARCHAR(255))
+BEGIN
+    DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id=PropertyID;
+
+    INSERT INTO collection_type (domain_id, entity_id, property_id, collection) SELECT 0, 0, InternalPropertyID, Collection;
+
+END;
+//
+DELIMITER ;
diff --git a/procedures/insertEntityProperty.sql b/procedures/insertEntityProperty.sql
index 1cfd38bac3f0bd455779d7398d46f3dcf3df1243..ee26c168612cacf93f19576e21e36d23ff4270ca 100644
--- a/procedures/insertEntityProperty.sql
+++ b/procedures/insertEntityProperty.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,112 +18,153 @@
  *
  * 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 temp.internal_id INTO InternalDomainID FROM (SELECT internal_id AS internal_id FROM entity_ids WHERE id = DomainID UNION SELECT DomainID AS internal_id) AS temp LIMIT 1;
+    SELECT temp.internal_id INTO InternalEntityID FROM (SELECT internal_id AS internal_id FROM entity_ids WHERE id = EntityID UNION SELECT EntityID AS internal_id) AS temp LIMIT 1;
+    SELECT temp.internal_id INTO InternalPropertyID FROM (SELECT internal_id AS internal_id FROM entity_ids WHERE id = PropertyID UNION SELECT PropertyID AS internal_id) AS temp LIMIT 1;
 
     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;
 
         ELSE
-            SET ReferenceValue = PropertyValue;
+            SELECT temp.internal_id INTO ReferenceValue FROM (SELECT internal_id AS internal_id FROM entity_ids WHERE id = PropertyValue UNION SELECT PropertyValue AS internal_id) AS temp LIMIT 1;
         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 9d1bf1c529e8b33d33cd6c6eb794afc09e65dbea..f08ff610c9cb68fcfde4a305b770a3ba254f5329 100644
--- a/procedures/insertIsaCache.sql
+++ b/procedures/insertIsaCache.sql
@@ -1,10 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -18,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DROP PROCEDURE IF EXISTS db_5_0.insertIsa;
 DELIMITER //
@@ -32,16 +30,22 @@ DELIMITER //
  *
  * Parameters
  * ==========
- * 
- * c : UNSIGNED
- * The child entity
- * 
- * p : UNSIGNED
- * The parent entity
+ *
+ * ChildID : VARCHAR(255)
+ *     The child entity.
+ *
+ * ParentID : VARCHAR(255)
+ *     The parent entity.
  */
-CREATE PROCEDURE db_5_0.insertIsa(IN c INT UNSIGNED, IN p INT UNSIGNED)
+CREATE PROCEDURE db_5_0.insertIsa(IN ChildID VARCHAR(255), IN ParentID VARCHAR(255))
 insert_is_a_proc: BEGIN
 
+    DECLARE c INT UNSIGNED DEFAULT NULL;
+    DECLARE p INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO c FROM entity_ids WHERE id = ChildID;
+    SELECT internal_id INTO p FROM entity_ids WHERE id = ParentID;
+
     INSERT INTO isa_cache (child, parent, rpath) VALUES (c, p, c);
 
     IF p = c THEN
@@ -69,17 +73,17 @@ insert_is_a_proc: BEGIN
     INSERT IGNORE INTO isa_cache SELECT
         l.child,    -- Descendant as found in isa_cache
         r.parent,   -- Ancestor as found in isa_cache
-        if(l.rpath=l.child and r.rpath=c,  -- if distance=1 for left and right:
+        IF(l.rpath=l.child AND r.rpath=c,  -- if distance=1 for left and right:
            c,                              -- rpath = current child
-           concat(if(l.rpath=l.child,        -- if dist=1 for descendant:
+           concat(IF(l.rpath=l.child,        -- if dist=1 for descendant:
                      c,                         -- rpath starts with c
                      concat(l.rpath, '>', c)),  -- rpath starts with "desc.rpath > c"
-                  if(r.rpath=c,              -- if dist=1 for ancestor
+                  IF(r.rpath=c,              -- if dist=1 for ancestor
                      '',                        -- rpath is finished
                      concat('>', r.rpath))))    -- rpath continuees with " > ancest.rpath"
             AS rpath
         FROM
-            isa_cache as l INNER JOIN isa_cache as r
+            isa_cache AS l INNER JOIN isa_cache AS r
             ON (l.parent = c AND c = r.child AND l.child != l.parent); -- Left: descendants of c, right: ancestors
 
 END;
diff --git a/procedures/isSubtype.sql b/procedures/isSubtype.sql
index f97c13f8f6ac75900ceca96e12cb285979a90a28..3a25612ef5121b4d644555e7a81b05f5ac0750b3 100644
--- a/procedures/isSubtype.sql
+++ b/procedures/isSubtype.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,18 +18,37 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
 DROP PROCEDURE IF EXISTS db_5_0.isSubtype;
 delimiter //
 
-CREATE PROCEDURE db_5_0.isSubtype(in c INT UNSIGNED, in p INT UNSIGNED)
+/*
+ * Return TRUE if the given Child is indeed a (direct or indirect) child of the
+ * given Parent.
+ *
+ * Parameters
+ * ----------
+ * ChildID : VARCHAR(255)
+ *     The entity id of the child.
+ * ParentID : VARCHAR(255)
+ *     The entity id of the parent.
+ *
+ * Returns
+ * -------
+ * ISA : BOOLEAN
+ */
+CREATE PROCEDURE db_5_0.isSubtype(in ChildID VARCHAR(255), in ParentID VARCHAR(255))
 BEGIN
-	DECLARE ret BOOLEAN DEFAULT FALSE;
-	SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1;
+    DECLARE c INT UNSIGNED DEFAULT NULL;
+    DECLARE p INT UNSIGNED DEFAULT NULL;
+    DECLARE ret BOOLEAN DEFAULT FALSE;
+
+    SELECT internal_id INTO c from entity_ids WHERE id = ChildID;
+    SELECT internal_id INTO p from entity_ids WHERE id = ParentID;
+
+    SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1;
     SELECT ret as ISA;
 END;
 //
diff --git a/procedures/overrideName.sql b/procedures/overrideName.sql
index ace102b25a72f0f4159a0769efce4209449d5bc4..cbd74fd00de550630e8a402b048cbc242479389c 100644
--- a/procedures/overrideName.sql
+++ b/procedures/overrideName.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.overrideName;
@@ -26,21 +25,61 @@ DROP PROCEDURE IF EXISTS db_5_0.overrideDesc;
 DROP PROCEDURE IF EXISTS db_5_0.overrideType;
 
 DELIMITER //
-CREATE PROCEDURE db_5_0.overrideName(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Name VARCHAR(255))
+/*
+ * Insert a name override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * Name : VARCHAR(255)
+ */
+CREATE PROCEDURE db_5_0.overrideName(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Name VARCHAR(255))
 BEGIN
-	INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (DomainID, EntityID, PropertyID, Name);
+    INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Name);
 END;
 //
 
-CREATE PROCEDURE db_5_0.overrideDesc(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Description TEXT)
+/*
+ * Insert a description override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * Description : TEXT
+ */
+CREATE PROCEDURE db_5_0.overrideDesc(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Description TEXT)
 BEGIN
-	INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (DomainID, EntityID, PropertyID, Description);
+    INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Description);
 END;
 //
 
-CREATE PROCEDURE db_5_0.overrideType(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Datatype INT UNSIGNED)
+/*
+ * Insert a data type override.
+ *
+ * Parameters
+ * ----------
+ * InternalDomainID : INT UNSIGNED
+ *     The *internal* id of the domain.
+ * InternalEntityID : INT UNSIGNED
+ *     The *internal* id of the entity.
+ * InternalPropertyID : INT UNSIGNED
+ *     The *internal* id of the property.
+ * InternalDatatypeID : INT UNSIGNED
+ *     The *internal* id of the data type.
+ */
+CREATE PROCEDURE db_5_0.overrideType(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in InternalDataTypeID INT UNSIGNED)
 BEGIN
-	INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (DomainID, EntityID, PropertyID, Datatype);
+    INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, InternalDataTypeID);
 END;
 //
 
diff --git a/procedures/query/applyIDFilter.sql b/procedures/query/applyIDFilter.sql
index b1c26b7ca63442c2d6b1b8dbc41fbb22d17f6d95..2b249471a0e70c673be1159eaffda7b0fa519ec2 100644
--- a/procedures/query/applyIDFilter.sql
+++ b/procedures/query/applyIDFilter.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.applyIDFilter;
@@ -32,71 +31,114 @@ DELIMITER //
  *
  * The `versioned` flag currently only has the effect that an `_iversion` column is also copied to
  * the target.
+ *
+ * Parameters
+ * ----------
+ * sourceSet : VARCHAR(255)
+ *     The name of the table from where we start.
+ * targetSet : VARCHAR(255)
+ *     The name of the table where we collect all the "good" ids (or NULL or same as sourceSet).
+ * o : CHAR(2)
+ *     The operator used for filtering, e.g. '=', '!=', '>', ...
+ * EntityID : VARCHAR(255)
+ *     An entity id, existing or non-existing, which we use to compare the
+ *     existing entities to using the operator.
+ * agg : CHAR(3)
+ *     An aggregate function, e.g. 'max' or 'min'. This only makes sense for number-based ids.
+ * versioned : BOOLEAN
+ *     The filter belongs to a version-aware query (e.g. FIND ANY VERSION OF
+ *     ...) and hence the sourceSet and targetSet have an `_iversion` column.
  */
 CREATE PROCEDURE db_5_0.applyIDFilter(in sourceSet VARCHAR(255), in targetSet VARCHAR(255),
-    in o CHAR(2), in vInt BIGINT, in agg CHAR(3), in versioned BOOLEAN)
+    in o CHAR(2), in EntityID VARCHAR(255), in agg CHAR(3), in versioned BOOLEAN)
 IDFILTER_LABEL: BEGIN
 DECLARE data VARCHAR(20000) DEFAULT NULL;
 DECLARE aggVal VARCHAR(255) DEFAULT NULL;
+DECLARE direction CHAR(4) DEFAULT NULL;
+DECLARE entity_id_type VARCHAR(255) DEFAULT "eids.id ";
 
 #-- get aggVal if possible
 IF agg IS NOT NULL THEN
     IF versioned THEN
         -- TODO versioned queries
         SELECT 1 FROM id_agg_with_versioning_not_implemented;
+    ELSEIF agg = "max" THEN
+        SET direction = "DESC";
+    ELSEIF agg = "min" THEN
+        SET direction = "ASC ";
+    ELSE
+        SELECT 1 FROM unknown_agg_parameter;
     END IF;
+
     SET @stmtIDAggValStr = CONCAT(
-        "SELECT ",
-        agg,
-        "(id) INTO @sAggVal FROM `",
+        "SELECT e.internal_id INTO @sAggVal FROM `",
         sourceSet,
-        "`");
+        "` AS s LEFT JOIN entity_ids AS e ON (s.id=e.internal_id) WHERE s.id>99 ORDER BY CAST(e.id AS UNSIGNED INT) ",
+        direction,
+        " LIMIT 1");
+
     PREPARE stmtIDAggVal FROM @stmtIDAggValStr;
     EXECUTE stmtIDAggVal;
     DEALLOCATE PREPARE stmtIDAggVal;
     SET aggVal = @sAggVal;
 END IF;
 
+IF o = ">" OR o = ">=" OR o = "<" or o = "<=" THEN
+    SET entity_id_type = "CAST(eids.id AS UNSIGNED INT) ";
+END IF;
+
 #-- generate stmt string
 IF targetSet IS NULL OR targetSet = sourceSet THEN
     SET data = CONCAT(
         "DELETE FROM `",
         sourceSet,
         "` WHERE ",
-        IF(o IS NULL OR vInt IS NULL,
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("NOT id",
+            CONCAT("NOT EXISTS (SELECT 1 FROM entity_ids AS eids WHERE ",
+                entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '" ',
+                " AND eids.internal_id = `",
+                sourceSet,
+                "`.id)"
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id!=",
+            CONCAT(" AND `", sourceSet, "`.id!=",
                 aggVal)));
 ELSEIF versioned AND sourceSet = "entities" THEN
-
     -- ################# VERSIONING #####################
     SET data = CONCAT(
         "INSERT IGNORE INTO `",
         targetSet,
-        '` (id, _iversion) SELECT id, _get_head_iversion(id) FROM `entities` WHERE ',
-        IF(o IS NULL OR vInt IS NULL,
+        '` (id, _iversion) SELECT e.id, _get_head_iversion(e.id) FROM `entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ',
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id=",
+            CONCAT(" AND e.id=",
                 aggVal)),
-        ' UNION SELECT id, _iversion FROM `archive_entities` WHERE ',
-        IF(o IS NULL OR vInt IS NULL,
+        ' UNION SELECT e.id, _iversion FROM `archive_entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ',
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
-            CONCAT(" AND id=",
+            CONCAT(" AND e.id=",
                 aggVal)));
     -- ##################################################
 
@@ -108,12 +150,15 @@ ELSE
             '` (id, _iversion) SELECT data.id, data._iversion FROM `',
             '` (id) SELECT data.id FROM `'),
         sourceSet,
-        "` AS data WHERE ",
-        IF(o IS NULL OR vInt IS NULL,
+        "` AS data JOIN entity_ids AS eids ON (eids.internal_id = data.id) WHERE ",
+        IF(o IS NULL OR EntityID IS NULL,
             "1=1",
-            CONCAT("data.id",
+            CONCAT(entity_id_type,
                 o,
-                vInt)),
+                ' "',
+                EntityID,
+                '"'
+            )),
         IF(aggVal IS NULL,
             "",
             CONCAT(" AND data.id=",
diff --git a/procedures/query/applyPOV.sql b/procedures/query/applyPOV.sql
index 03e2f1d9eb6560b373c485e1f5105a705b935e69..d1d846784a5861237ef710fe90c40f42ef9c6d11 100644
--- a/procedures/query/applyPOV.sql
+++ b/procedures/query/applyPOV.sql
@@ -1,5 +1,4 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 /* Documentation including (?) has to be checked by an expert. */
@@ -37,8 +34,8 @@ 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. */
@@ -59,7 +56,7 @@ CREATE PROCEDURE db_5_0.applyPOV(in sourceSet VARCHAR(255), /* (?) Name of the t
                                  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 vDoubleStdUnit DOUBLE,
+                                 in vDoubleStdUnit DOUBLE, /* The numeric value, converted according to the unit rules. */
                                  in stdUnit_sig BIGINT,
                                  in vDateTime VARCHAR(255),
                                  in vDateTimeDotNotation VARCHAR(255),
diff --git a/procedures/query/applyTransactionFilter.sql b/procedures/query/applyTransactionFilter.sql
index 7a428b0702352677826efce0cc60bb794415102d..89b22258646740f6e8cc6138256227a168f5cbfe 100644
--- a/procedures/query/applyTransactionFilter.sql
+++ b/procedures/query/applyTransactionFilter.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,37 +18,65 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DROP PROCEDURE IF EXISTS db_5_0.applyTransactionFilter;
 DELIMITER //
 
+
+/*
+ * Apply a transaction filter to the sourceSet and collect the remaining
+ * entities in the targetSet.
+ *
+ * Parameters
+ * ----------
+ * sourceSet : VARCHAR(255)
+ *     The name of the table from where we start.
+ * targetSet : VARCHAR(255)
+ *     The name of the table where we collect all the "good" ids (or NULL or same as sourceSet).
+ * transaction : VARCHAR(255)
+ *     The transaction's type (INSERT, UPDATE,...)
+ * operator_u : CHAR(2)
+ *     The operator used for filtering by the user, e.g. '=', '!='.
+ * realm : VARCHAR(255)
+ *     The user's realm (if filtering by the user).
+ * userName : VARCHAR(255)
+ *     The user's name (if filtering by the user).
+ * ilb : BIGINT
+ *     Inclusive Lower Bound of seconds for the transactions time.
+ * ilb_nanos : BIGINT
+ *     Inclusive Lower Bound of nanoseconds for the transactions time.
+ * eub : BIGINT
+ *     Exclusive Upper Bound of seconds for the transactions time.
+ * eub_nanos : BIGINT
+ *     Exclusive Upper Bound of nanoseconds for the transactions time.
+ * operator_t : CHAR(2)
+ *     The operator used for filtering by the transaction time, e.g. '=', '!=', '<', '>='.
+ */
 CREATE PROCEDURE db_5_0.applyTransactionFilter(in sourceSet VARCHAR(255), targetSet VARCHAR(255), in transaction VARCHAR(255), in operator_u CHAR(2), in realm VARCHAR(255), in userName VARCHAR(255), in ilb BIGINT, in ilb_nanos INT UNSIGNED, in eub BIGINT, in eub_nanos INT UNSIGNED, in operator_t CHAR(2))
 BEGIN
-	DECLARE data TEXT default CONCAT('(SELECT entity_id FROM transaction_log AS t WHERE t.transaction=\'', 
-		transaction, 
-		'\'',
-		IF(userName IS NOT NULL, 
-			CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'),
-			'' 
-		),
-		IF(ilb IS NOT NULL, 
-			CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)),
-			""
-		),
-		')'
-	);
+    DECLARE data TEXT default CONCAT("(SELECT internal_id AS entity_id FROM transaction_log AS t JOIN entity_ids AS eids ON ( t.entity_id = eids.id ) WHERE t.transaction='",
+        transaction,
+        "'",
+        IF(userName IS NOT NULL,
+            CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'),
+            ''
+        ),
+        IF(ilb IS NOT NULL,
+            CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)),
+            ""
+        ),
+        ')'
+    );
 
-	SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE);
-	PREPARE stmtTransactionFilter from @stmtTransactionStr;
-	IF userName IS NOT NULL THEN
-		SET @userName = userName;
-		SET @realm = realm;
-		EXECUTE stmtTransactionFilter USING @realm, @userName;
-	ELSE
-		EXECUTE stmtTransactionFilter;
-	END IF;
+    SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE);
+    PREPARE stmtTransactionFilter from @stmtTransactionStr;
+    IF userName IS NOT NULL THEN
+        SET @userName = userName;
+        SET @realm = realm;
+        EXECUTE stmtTransactionFilter USING @realm, @userName;
+    ELSE
+        EXECUTE stmtTransactionFilter;
+    END IF;
 
 END;
 //
diff --git a/procedures/query/initBackReference.sql b/procedures/query/initBackReference.sql
index c425dbcc6ec6c20e9b5cb2e73c0b6e1dedad1cf0..2999fb999615ffc47879dfda2a9f89e6b2b387d5 100644
--- a/procedures/query/initBackReference.sql
+++ b/procedures/query/initBackReference.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,27 +18,52 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.initBackReference;
 DELIMITER //
-CREATE PROCEDURE db_5_0.initBackReference(in pid INT UNSIGNED, in pname VARCHAR(255), in entity_id INT UNSIGNED, in ename VARCHAR(255))
+
+/*
+ * Create and initialize two new temporary tables.
+ *
+ * This is used to initialize the filterin for backreferences to a
+ * particular entity (specified by EntityID or EntityName) or using a
+ * particular property (specified by PropertyID or PropertyName).
+ *
+ * The propertiesTable contains all properties matching the PropertyID or
+ * PropertyName. The entitiesTable contains all entities matching EntityID or
+ * EntityName.
+
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ * EntityID : VARCHAR(255)
+ *     The entity's (external) id.
+ * EntityName : VARCHAR(255)
+ *     The entity's name.
+ *
+ * Select
+ * ------
+ * Tuple (propertiesTable, entitiesTable)
+ */
+CREATE PROCEDURE db_5_0.initBackReference(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in EntityID VARCHAR(255), in EntityName VARCHAR(255))
 BEGIN
     DECLARE propertiesTable VARCHAR(255) DEFAULT NULL;
     DECLARE entitiesTable VARCHAR(255) DEFAULT NULL;
 
-    IF pname IS NOT NULL THEN
+    IF PropertyName IS NOT NULL THEN
         -- TODO versioning for properties
         call createTmpTable(propertiesTable, FALSE);
-        call initSubEntity(pid, pname, propertiesTable);
+        call initSubEntity(PropertyID, PropertyName, propertiesTable);
     END IF;
 
-    IF ename IS NOT NULL THEN
+    IF EntityName IS NOT NULL THEN
         -- TODO versioning for referencing entities
         call createTmpTable(entitiesTable, FALSE);
-        call initSubEntity(entity_id, ename, entitiesTable);
+        call initSubEntity(EntityID, EntityName, entitiesTable);
     END IF;
 
     SELECT propertiesTable, entitiesTable;
diff --git a/procedures/query/initPOV.sql b/procedures/query/initPOV.sql
index 52d6a26279c1d25cd605c3a1883db31bf6326150..31347ba9a7f2cde33e619e50e7721875232b8628 100644
--- a/procedures/query/initPOV.sql
+++ b/procedures/query/initPOV.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,15 +18,32 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 DELIMITER //
 
 
 DROP PROCEDURE IF EXISTS db_5_0.initPOVPropertiesTable//
 
-CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in pid INT UNSIGNED, in pname VARCHAR(255), in sourceSet VARCHAR(255))
+/*
+ * Create and initialize a new temporary table.
+ *
+ * This is used to initialize the POV filtering. The resulting table
+ * contains all properties matching the Property component of the POV filter.
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ * sourceSet : VARCHAR(255)
+ *     The name of the table which will be filtered by the POV filter.
+ *
+ * Select
+ * ------
+ * Tuple (propertiesTable, ... and a lot of debug output)
+ */
+CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in sourceSet VARCHAR(255))
 BEGIN
     DECLARE propertiesTable VARCHAR(255) DEFAULT NULL; /*table for property ids*/
     DECLARE replTbl VARCHAR(255) DEFAULT NULL;
@@ -38,24 +56,24 @@ 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 named "PropertyName"
         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 +109,33 @@ END //
 
 DROP PROCEDURE IF EXISTS db_5_0.initPOVRefidsTable //
 
-CREATE PROCEDURE db_5_0.initPOVRefidsTable(in vInt INT UNSIGNED, in vText VARCHAR(255))
+/*
+ * Create and initialize a new temporary table.
+ *
+ * This used to initialize the POV filtering. The resulting table
+ * contains all entities matching the Value component of the POV filter (i.e.
+ * the referenced entities).
+ *
+ * Parameters
+ * ----------
+ * PropertyID : VARCHAR(255)
+ *     The property's (external) id.
+ * PropertyName : VARCHAR(255)
+ *     The property's name.
+ *
+ * Select
+ * ------
+ * Tuple (refIdsTable)
+ */
+CREATE PROCEDURE db_5_0.initPOVRefidsTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255))
 BEGIN
     DECLARE refIdsTable VARCHAR(255) DEFAULT NULL; /*table for referenced entity ids*/
 
     #-- for reference properties: the value is interpreted as a record type name.
-    IF vText IS NOT NULL THEN
+    IF PropertyName IS NOT NULL THEN
         -- TODO versioned queries
         call createTmpTable(refIdsTable, FALSE);
-        call initSubEntity(vInt, vText, refIdsTable);
+        call initSubEntity(PropertyID, PropertyName, refIdsTable);
         #-- now, all ids are in the refIdsTable
     END IF;
     SELECT refIdsTable;
diff --git a/procedures/query/initSubEntity.sql b/procedures/query/initSubEntity.sql
index a2f5ea67e495e4cc8cc52f0248389bc44792451f..c60ddb61df7370f52ae8218720ad69c5d2bf5023 100644
--- a/procedures/query/initSubEntity.sql
+++ b/procedures/query/initSubEntity.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,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
  */
 
 
@@ -26,7 +25,22 @@ 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 and all of its children
+ * into the table (i.e. their internal ids).
+ *
+ * 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 '=';
@@ -47,10 +61,11 @@ BEGIN
     SET ecount = ROW_COUNT();
     DEALLOCATE PREPARE stmt;
 
-    IF e_id IS NOT NULL THEN
-        SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) VALUES (', e_id, ')');
+    IF EntityID IS NOT NULL THEN
+        SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) SELECT internal_id FROM entity_ids WHERE id = ?');
         PREPARE stmt FROM @stmtStr;
-        EXECUTE stmt;
+        SET @eid = EntityID;
+        EXECUTE stmt USING @eid;
         SET ecount = ecount + ROW_COUNT();
         DEALLOCATE PREPARE stmt;
     END IF;
diff --git a/procedures/registerSubdomain.sql b/procedures/registerReplacementIds.sql
similarity index 70%
rename from procedures/registerSubdomain.sql
rename to procedures/registerReplacementIds.sql
index 4cb18e46be422e6cc65db5b33913cf06b77c18d2..2fc04ccb082ef080b7b7ae238b32cc3a7f6b415f 100644
--- a/procedures/registerSubdomain.sql
+++ b/procedures/registerReplacementIds.sql
@@ -1,9 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
+ * Copyright (C) 2023 IndiScale GmbH <www.indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,33 +18,25 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
-
-
-
-
-
-
-
-
 DROP PROCEDURE IF EXISTS db_5_0.registerSubdomain;
+DROP PROCEDURE IF EXISTS db_5_0.registerReplacementIds;
 delimiter //
 
-CREATE PROCEDURE db_5_0.registerSubdomain(in amount INT UNSIGNED)
+CREATE PROCEDURE db_5_0.registerReplacementIds(in amount INT UNSIGNED)
 BEGIN
     DECLARE ED INTEGER DEFAULT NULL;
 
-    SELECT COUNT(id) INTO ED FROM entities WHERE Role='DOMAIN' AND id!=0;
+    SELECT COUNT(id) INTO ED FROM entities WHERE Role='_REPLACEMENT' AND id!=0;
 
     WHILE ED < amount DO
         INSERT INTO entities (description, role, acl) VALUES
-            (NULL, 'DOMAIN', 0);
+            (NULL, '_REPLACEMENT', 0);
+
         SET ED = ED + 1;
     END WHILE;
 
-    SELECT id as DomainID FROM entities WHERE Role='DOMAIN' and id!=0;
+    SELECT e.id as ReplacementID FROM entities AS e WHERE e.Role='_REPLACEMENT' and e.id!=0;
 
 END;
 //
diff --git a/procedures/retrieveDatatype.sql b/procedures/retrieveDatatype.sql
deleted file mode 100644
index c0ed52c30ffd506d9f0a214d2b59fd4691c4c510..0000000000000000000000000000000000000000
--- a/procedures/retrieveDatatype.sql
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-
-
-
-
-
-DROP PROCEDURE IF EXISTS db_5_0.retrieveDatatype;
-delimiter //
-CREATE PROCEDURE db_5_0.retrieveDatatype(in DatatypeName VARCHAR(255))
-BEGIN
-
-Select e.id INTO @DatatypeID from entities e where e.name=DatatypeName AND e.role='DATATYPE' LIMIT 1;
-
-call retrieveEntity(@DatatypeID);
-
-
-
-
-END;
-//
-delimiter ;
diff --git a/procedures/retrieveEntity.sql b/procedures/retrieveEntity.sql
index 42b283d1b9c9da08761900a45f439958ec9cc075..a4264e3d44fd0b9cddbd24192b118add7bdc4e15 100644
--- a/procedures/retrieveEntity.sql
+++ b/procedures/retrieveEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -36,9 +33,9 @@ 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`.
@@ -49,7 +46,7 @@ drop procedure if exists db_5_0.retrieveEntity //
  *           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;
@@ -59,7 +56,15 @@ retrieveEntityBody: BEGIN
     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 +78,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,7 +89,7 @@ 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;
 
@@ -93,7 +98,7 @@ retrieveEntityBody: BEGIN
                 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 +107,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;
 
@@ -119,10 +124,9 @@ retrieveEntityBody: BEGIN
                 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 +136,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 +149,33 @@ 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 DatatypeID
+        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 entity_id = DatatypeID
             AND property_id = 20 LIMIT 1 ) AS Datatype,
         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 +184,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 696447527b8c05f3b9aa57193a26c3d8fa48c874..f552a2c3b7ceafae5255ee69655af426f44b8bb7 100644
--- a/procedures/retrieveEntityOverrides.sql
+++ b/procedures/retrieveEntityOverrides.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 Indiscale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 Indiscale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,25 +18,59 @@
  *
  * 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_override,       # the datatype, e.g. DOUBLE
+ * 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). That's why we do the UNION here, falling back to the
+    -- EntityID.
+    SELECT temp.internal_id INTO InternalEntityID
+       FROM (SELECT internal_id AS internal_id FROM
+             entity_ids WHERE id = EntityID UNION SELECT EntityID AS internal_id) AS temp LIMIT 1;
+    -- 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 +80,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
@@ -62,11 +95,12 @@ retrieveOverridesBody: BEGIN
                 name AS name_override,
                 NULL AS desc_override,
                 NULL AS type_override,
-                entity_id,
-                property_id
+                EntityID AS entity_id,
+                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
@@ -77,11 +111,12 @@ retrieveOverridesBody: BEGIN
                 NULL AS name_override,
                 description AS desc_override,
                 NULL AS type_override,
-                entity_id,
-                property_id
+                EntityID AS entity_id,
+                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
@@ -96,11 +131,12 @@ retrieveOverridesBody: BEGIN
                     AND entity_id = datatype
                     AND property_id = 20
                     LIMIT 1), datatype) AS type_override,
-                entity_id,
-                property_id
+                EntityID AS entity_id,
+                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
@@ -111,11 +147,12 @@ retrieveOverridesBody: BEGIN
                 NULL AS name_override,
                 NULL AS desc_override,
                 NULL AS type_override,
-                entity_id,
-                property_id
+                EntityID AS entity_id,
+                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;
@@ -127,11 +164,12 @@ retrieveOverridesBody: BEGIN
         name AS name_override,
         NULL AS desc_override,
         NULL AS type_override,
-        entity_id,
-        property_id
+        EntityID AS entity_id,
+        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
 
@@ -140,11 +178,12 @@ retrieveOverridesBody: BEGIN
         NULL AS name_override,
         description AS desc_override,
         NULL AS type_override,
-        entity_id,
-        property_id
+        EntityID AS entity_id,
+        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
 
@@ -156,11 +195,12 @@ retrieveOverridesBody: BEGIN
             WHERE domain_id = 0
             AND entity_ID = datatype
             AND property_id = 20 LIMIT 1), datatype) AS type_override,
-        entity_id,
-        property_id
+        EntityID AS entity_id,
+        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
 
@@ -169,11 +209,12 @@ retrieveOverridesBody: BEGIN
         NULL AS name_override,
         NULL AS desc_override,
         NULL AS type_override,
-        entity_id,
-        property_id
+        EntityID AS entity_id,
+        property_id AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id
     FROM collection_type
-    WHERE domain_id = DomainID
-    AND entity_id = EntityID;
+    WHERE domain_id = InternalDomainID
+    AND entity_id = InternalEntityID;
 
 
 END;
diff --git a/procedures/retrieveEntityParents.sql b/procedures/retrieveEntityParents.sql
index 12b5c287881d2c10ee591986a654d974ac1feecc..6fa29054ff15869be035515a5556beb78ab9d66c 100644
--- a/procedures/retrieveEntityParents.sql
+++ b/procedures/retrieveEntityParents.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -28,37 +25,35 @@ DROP PROCEDURE IF EXISTS db_5_0.retrieveEntityParents;
 DELIMITER //
 
 /* Retrieve the parents of an Entity.
-
-Parameters
-==========
-
-EntityID : UNSIGNED
-Child entity for which all parental relations should be deleted.
-
-Returns
-=======
-ParentID : INT UNSIGNED
-  Each parent's ID
-
-ParentName :
-  The parent's name.
-
-ParentDescription :
-  The parent's description.
-
-ParentRole :
-  The parent's Role.
-
-ACL :
-  Access control list something
+ *
+ * Parameters
+ * ----------
+ * EntityID : VARCHAR(255)
+ *     Child entity for which all parental relations should be deleted.
+ *
+ * ResultSet
+ * ---------
+ * ParentID : VARCHAR(255)
+ *   Each parent's ID
+ * ParentName : VARCHAR(255)
+ *   The parent's name.
+ * ParentDescription : TEXT
+ *   The parent's description.
+ * ParentRole : VARCHAR(255)
+ *   The parent's Role.
+ * ACL : VARBINARY(65525)
+ *   Access control list.
 */
 CREATE PROCEDURE db_5_0.retrieveEntityParents(
-    in EntityID INT UNSIGNED,
+    in EntityID VARCHAR(255),
     in Version VARBINARY(255))
 retrieveEntityParentsBody: BEGIN
 
     DECLARE IVersion INT UNSIGNED DEFAULT NULL;
     DECLARE IsHead BOOLEAN DEFAULT TRUE;
+    DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL;
+
+    SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID;
 
     IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN
         IF Version IS NOT NULL THEN
@@ -68,7 +63,7 @@ retrieveEntityParentsBody: BEGIN
         IF IsHead IS FALSE THEN
             SELECT e._iversion INTO IVersion
                 FROM entity_version as e
-                WHERE e.entity_id = EntityID
+                WHERE e.entity_id = InternalEntityID
                 AND e.version = Version;
 
             IF IVersion IS NULL THEN
@@ -77,10 +72,10 @@ retrieveEntityParentsBody: BEGIN
             END IF;
 
             SELECT
-                i.parent AS ParentID,
+                ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID,
                 ( SELECT value FROM name_data
                     WHERE domain_id = 0
-                    AND entity_id = ParentID
+                    AND entity_id = i.parent
                     AND property_id = 20
                 ) AS ParentName, -- This is not necessarily the name of the parent at the time of
                                  -- IVersion but it is a good guess. Future implementations of the
@@ -92,7 +87,7 @@ retrieveEntityParentsBody: BEGIN
                 (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL
                 FROM archive_isa AS i JOIN entities AS e
                     ON (i.parent = e.id)
-                WHERE i.child = EntityID
+                WHERE i.child = InternalEntityID
                 AND i.child_iversion = IVersion
                 AND i.direct IS TRUE
                 ;
@@ -102,18 +97,18 @@ retrieveEntityParentsBody: BEGIN
     END IF;
 
     SELECT
-        i.parent AS ParentID,
+        ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID,
         ( SELECT value FROM name_data
             WHERE domain_id = 0
-            AND entity_id = ParentID
+            AND entity_id = i.parent
             AND property_id = 20 ) AS ParentName,
         e.description AS ParentDescription,
         e.role AS ParentRole,
         (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL
         FROM isa_cache AS i JOIN entities AS e
             ON (i.parent = e.id)
-        WHERE i.child = EntityID
-        AND i.rpath = EntityID;
+        WHERE i.child = InternalEntityID
+        AND i.rpath = InternalEntityID;
 END
 //
 
diff --git a/procedures/retrieveEntityProperties.sql b/procedures/retrieveEntityProperties.sql
index b8bc565d73cd75cbbb3726fc93e5826725aa1c0f..024f3b0cf2dfb6a83eb41078ec30060c88693f2c 100644
--- a/procedures/retrieveEntityProperties.sql
+++ b/procedures/retrieveEntityProperties.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 
@@ -28,30 +25,67 @@ 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). That's why we do the UNION here, falling back to the
+    -- EntityID.
+    SELECT temp.internal_id INTO InternalEntityID FROM (SELECT internal_id AS internal_id FROM entity_ids WHERE id = EntityID UNION SELECT EntityID AS internal_id) AS temp LIMIT 1;
+    -- 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 +95,135 @@ retrieveEntityPropertiesBody: BEGIN
 
             #-- double properties
             SELECT
-                property_id AS PropertyID,
+                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,
+                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,
+                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,
+                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,
+                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,
+                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,
+                property_id AS InternalPropertyID,
+                ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
+                IF(value_iversion IS NULL,
+                    IF(status = "REPLACEMENT",
+                        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,
+                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,
+                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 +233,129 @@ retrieveEntityPropertiesBody: BEGIN
 
     #-- double properties
     SELECT
-        property_id AS PropertyID,
+        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,
+        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,
+        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,
+        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,
+        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,
+        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)))
+        property_id AS InternalPropertyID,
+        ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID,
+        IF(value_iversion IS NULL,
+            IF(status = "REPLACEMENT",
+                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,
+        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,
+        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 7db1b89c6e0e407e63de29682d4ef033f56b5f92..0000000000000000000000000000000000000000
--- a/procedures/retrieveGroup.sql
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-Drop Procedure if exists db_5_0.retrieveGroup;
diff --git a/procedures/retrieveSubentity.sql b/procedures/retrieveSubentity.sql
deleted file mode 100644
index 406d668ab776451216d54ff3e2de9f4eb294872a..0000000000000000000000000000000000000000
--- a/procedures/retrieveSubentity.sql
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-DELIMITER //
-DROP PROCEDURE IF EXISTS db_5_0.retrieveSubEntity //
-/**
-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 33345d9625fadda9d1e182e7ea545e3b8fbf9e8a..0000000000000000000000000000000000000000
--- a/procedures/setPassword.sql
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * ** header v3.0
- * This file is a part of the CaosDB Project.
- *
- * Copyright (C) 2018 Research Group Biomedical Physics,
- * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
- */
-
-
-DROP PROCEDURE IF EXISTS db_5_0.setPassword;
-delimiter //
-
-CREATE PROCEDURE db_5_0.setPassword(in EntityID INT UNSIGNED, in NewPassword VARCHAR(255))
-BEGIN
-
-
-	DELETE FROM passwords where entity_id=EntityID;
-	INSERT INTO passwords (entity_id, password) VALUES (EntityID, NewPassword);
-
-END;
-//
-delimiter ;
diff --git a/procedures/updateEntity.sql b/procedures/updateEntity.sql
index f98e4795b344bbf0c4b68ac90a0848daf5e14188..3e0a53c11c2899bdea1fb9d90466ca0de0aa8cb1 100644
--- a/procedures/updateEntity.sql
+++ b/procedures/updateEntity.sql
@@ -1,11 +1,10 @@
 /*
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
  * Copyright (C) 2018 Research Group Biomedical Physics,
  * Max-Planck-Institute for Dynamics and Self-Organization Göttingen
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -19,8 +18,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 DROP PROCEDURE IF EXISTS db_5_0.updateEntity;
@@ -34,7 +31,7 @@ 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),
@@ -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,34 @@ 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
         INSERT INTO data_type (domain_id, entity_id, property_id, datatype)
-            SELECT 0, 0, EntityID,
+            SELECT 0, 0, InternalEntityID,
                 ( SELECT entity_id FROM name_data WHERE domain_id = 0
                     AND property_id = 20 AND value = Datatype LIMIT 1 );
 
         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/test_autotap.sql b/tests/test_autotap.sql
index ebec7304fd753261775a40a8ccfd8e765136ec0e..1ae650e346e3cd79e5396af177c6c14ffb875ea1 100644
--- a/tests/test_autotap.sql
+++ b/tests/test_autotap.sql
@@ -724,7 +724,7 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description'
 -- COLUMN entities.role
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','entities','role','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'DOMAIN\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\')','');
+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','');
@@ -1914,11 +1914,11 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','trans
 -- COLUMN transaction_log.entity_id
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','transaction_log','entity_id','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','int(10) unsigned','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','transaction_log','entity_id','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,'');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4_bin','');
 
 -- COLUMN transaction_log.username
 
@@ -2089,11 +2089,11 @@ SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','ut
 -- COLUMN user_info.entity
 
 SELECT tap.has_column('_caosdb_schema_unit_tests','user_info','entity','');
-SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','int(10) unsigned','');
+SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','varchar(255)','');
 SELECT tap.col_extra_is('_caosdb_schema_unit_tests','user_info','entity','','');
 SELECT tap.col_default_is('_caosdb_schema_unit_tests','user_info','entity','NULL','');
-SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity',NULL,'');
-SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity',NULL,'');
+SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4','');
+SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4_bin','');
 
 -- INDEXES
 SELECT tap.indexes_are('_caosdb_schema_unit_tests','user_info','`subject_entity`','');
@@ -2105,7 +2105,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,10 +2115,10 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','user_info','`realm`,`name`',''
 
 -- CONSTRAINT user_info.subjects_ibfk_1
 
-SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','');
-SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','FOREIGN KEY','');
-SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT','');
-SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT','');
+SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','');
+SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','FOREIGN KEY','');
+SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT','');
+SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT','');
 
 -- ***************************************************************
 -- TABLE _caosdb_schema_unit_tests.user_roles
@@ -2509,20 +2509,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','');
@@ -2649,12 +2635,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 +2663,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 +2670,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 +2726,5 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insert_single
 SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insert_single_child_version','DEFINER','');
 SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insert_single_child_version','CONTAINS SQL','');
 
--- PROCEDURES _caosdb_schema_unit_tests.delete_all_entity_versions
-
-SELECT tap.has_procedure('_caosdb_schema_unit_tests', 'delete_all_entity_versions', '');
-SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','delete_all_entity_versions','NO','');
-SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','delete_all_entity_versions','DEFINER','');
-SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','delete_all_entity_versions','CONTAINS SQL','');
-
 CALL tap.finish();
 ROLLBACK;
diff --git a/tests/test_entity_versioning.sql b/tests/test_entity_versioning.sql
index 26efd8c029e9ad01f8966ddd687ed31f3c4a2b49..f7c52a210c8baef8e781142ff645122ce95ec4fe 100644
--- a/tests/test_entity_versioning.sql
+++ b/tests/test_entity_versioning.sql
@@ -1,9 +1,8 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
@@ -34,6 +31,13 @@ CALL tap.no_plan();
 
 -- SETUP
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+SET @EntityID3 = 10003;
+SET @EntityID4 = 10004;
+SET @EntityID5 = 10005;
+SET @EntityID6 = 10006;
+
 -- Disable versioning because we want to test `insert_single_child_version`
 -- separately from `insertEntity` but the former is called inside the latter
 -- when versioning is enabled.
@@ -46,22 +50,22 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES
 ("SRIDblieb", 3456, 4576, "you", "home");
 DELETE FROM entities WHERE id > 99;
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
+CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+SELECT entity_id INTO @InternalEntityID1 FROM name_data WHERE value="EntityName";
 
 
 -- TEST insert_single_child_version
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 0, "no versions there yet");
 
-CALL insert_single_child_version(@EntityID, "hashbla", "versionbla", NULL, "SRIDbla");
+CALL insert_single_child_version(@InternalEntityID1, "hashbla", "versionbla", NULL, "SRIDbla");
 SELECT _ipparent INTO @x from entity_version WHERE version="versionbla";
 SELECT tap.eq(@x, NULL, "no parent for the first version");
 
 -- add a second version
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 1, "one version there already");
-CALL insert_single_child_version(@EntityID, "hashblub", "versionblub", "versionbla", "SRIDblub");
+CALL insert_single_child_version(@InternalEntityID1, "hashblub", "versionblub", "versionbla", "SRIDblub");
 
 SELECT _ipparent INTO @x from entity_version WHERE version="versionblub";
 SELECT tap.eq(@x, 1, "the original entity is the parent");
@@ -72,7 +76,7 @@ SELECT tap.eq(@x, 2, "two versions there already");
 
 CALL tap._assert_throws(
      concat("CALL insert_single_child_version(",
-            @EntityID, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'),
+            @InternalEntityID1, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'),
      "non existing parent throws");
 
 SELECT count(*) INTO @x FROM entity_version;
@@ -80,21 +84,24 @@ SELECT tap.eq(@x, 2, "still two versions there");
 
 
 -- TEST get_primary_parent_version
-SELECT tap.eq(get_primary_parent_version(@EntityID, "versionblub"), "versionbla", "returns correct parent for versionblub");
-SELECT tap.eq(get_primary_parent_version(@EntityID, "versionbla"), NULL, "versionbla has no parent");
+SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionblub"), "versionbla", "returns correct parent for versionblub");
+SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionbla"), NULL, "versionbla has no parent");
 
 
+-- Reactivate when versioning's FORGET is being implemented
 -- TEST delete_all_entity_versions
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.ok(@x > 0, "several versions in the table");
 
-CALL delete_all_entity_versions(@EntityID);
+-- CALL delete_all_entity_versions(@EntityID1);
+DELETE FROM entity_version WHERE entity_id = @InternalEntityID1;
 SELECT count(*) INTO @x FROM entity_version;
 SELECT tap.eq(@x, 0, "no versions there any more");
 
 
 -- TEARDOWN clean up
 DELETE FROM name_data WHERE entity_id > 99;
+DELETE FROM entity_ids WHERE internal_id > 99;
 DELETE FROM entities WHERE id > 99;
 
 -- #####################################################################
@@ -108,20 +115,20 @@ SELECT tap.eq(@x, 0, "before insertEntity, no versions there");
 
 -- TEST insertEntity - should produce a version w/o parent
 SET @SRID = "SRIDbla";
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
-CALL insertEntity("ParentName", "ParentDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+SELECT entity_id INTO @InternalEntityID2 FROM name_data WHERE value="EntityName";
+CALL insertEntity(@EntityID3, "ParentName", "ParentDesc", "RECORDTYPE", "{acl1}");
 SELECT entity_id INTO @ParentID FROM name_data WHERE value="ParentName";
-CALL insertIsa(@EntityID, @ParentID);
-CALL insertEntityProperty(0, @EntityID, 17, "null_data", NULL, NULL,
+CALL insertIsa(@EntityID2, @EntityID3);
+CALL insertEntityProperty(0, @EntityID2, 17, "null_data", NULL, NULL,
     "RECOMMENDED", NULL, "DescOverride", NULL, NULL, 0);
 
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 1, "after insertEntity, a version is there.");
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent is NULL;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent is NULL;
 SELECT tap.eq(@x, 1, "after insertEntity, the _iversion number is 1.");
 
-SELECT _ipparent INTO @x from entity_version WHERE entity_id = @EntityID;
+SELECT _ipparent INTO @x from entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, NULL, "no parent for the freshly inserted entity");
 SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update")
     FROM archive_entities;
@@ -129,14 +136,14 @@ SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update")
 
 -- TEST updateEntity - should produce a version with a parent
 SET @SRID = "SRIDblub";
-CALL deleteEntityProperties(@EntityID);
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}");
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL deleteEntityProperties(@EntityID2);
+CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}");
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 2, "after updateEntity, a second version is there.");
 
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1;
 SELECT tap.eq(@x, 2, "after updateEntity, the _iversion number incremented.");
-SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1;
+SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1;
 SELECT tap.eq(@x, 1, "after updateEntity, the _pparent points to the first version");
 
 SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities")
@@ -144,60 +151,60 @@ SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities")
 
 
 -- TEST get_version_history
-CALL get_version_history(@EntityID);
+CALL get_version_history(@EntityID2);
 
 -- TEST retrieveEntity
 
 SELECT version INTO @x FROM entity_version
-    WHERE entity_id = @EntityID
+    WHERE entity_id = @InternalEntityID2
     AND _iversion = 2;
-CALL retrieveEntity(@EntityID, NULL);
-CALL retrieveEntity(@EntityID, "non-existing-version");
-CALL retrieveEntity(@EntityID, get_head_version(@EntityID));
-CALL retrieveEntity(@EntityID, @x);
+CALL retrieveEntity(@EntityID2, NULL);
+CALL retrieveEntity(@EntityID2, "non-existing-version");
+CALL retrieveEntity(@EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntity(@EntityID2, @x);
 
 -- TEST retrieveEntityParents
 
-CALL retrieveEntityParents(@EntityID, NULL);
-CALL retrieveEntityParents(@EntityID, "non-existing-version");
-CALL retrieveEntityParents(@EntityID, get_head_version(@EntityID));
-CALL retrieveEntityParents(@EntityID, @x);
+CALL retrieveEntityParents(@EntityID2, NULL);
+CALL retrieveEntityParents(@EntityID2, "non-existing-version");
+CALL retrieveEntityParents(@EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntityParents(@EntityID2, @x);
 
 -- TEST retrieveEntityProperties
 
-CALL retrieveEntityProperties(0, @EntityID, NULL);
-CALL retrieveEntityProperties(0, @EntityID, "non-existing-version");
-CALL retrieveEntityProperties(0, @EntityID, get_head_version(@EntityID));
-CALL retrieveEntityProperties(0, @EntityID, @x);
+CALL retrieveEntityProperties(0, @EntityID2, NULL);
+CALL retrieveEntityProperties(0, @EntityID2, "non-existing-version");
+CALL retrieveEntityProperties(0, @EntityID2, get_head_version(@EntityID2));
+CALL retrieveEntityProperties(0, @EntityID2, @x);
 
 -- TEST retrieveOverrides
 
-CALL retrieveOverrides(0, @EntityID, NULL);
-CALL retrieveOverrides(0, @EntityID, "non-existing-version");
-CALL retrieveOverrides(0, @EntityID, get_head_version(@EntityID));
-CALL retrieveOverrides(0, @EntityID, @x);
+CALL retrieveOverrides(0, @EntityID2, NULL);
+CALL retrieveOverrides(0, @EntityID2, "non-existing-version");
+CALL retrieveOverrides(0, @EntityID2, get_head_version(@EntityID2));
+CALL retrieveOverrides(0, @EntityID2, @x);
 
 
 -- and 2nd updateEntity
 SET @SRID = "SRIDblieb";
-CALL updateEntity(@EntityID, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}");
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL updateEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}");
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 3, "after 2nd updateEntity, a 3rd version is there.");
 
-SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 2;
+SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 2;
 SELECT tap.eq(@x, 3, "after 2nd updateEntity, the _iversion number incremented again.");
-SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _iversion = 3;
+SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _iversion = 3;
 SELECT tap.eq(@x, 2, "after 2nd updateEntity, the _pparent points to the 2nd version");
-SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @EntityID AND _ipparent = 2;
+SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @InternalEntityID2 AND _ipparent = 2;
 
 
 -- TEST deleteEntity - should remove all versions
-CALL deleteIsa(@EntityID);
-CALL deleteEntity(@EntityID);
-SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID;
+CALL deleteIsa(@EntityID3);
+CALL deleteEntity(@EntityID2);
+SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2;
 SELECT tap.eq(@x, 0, "no versions there any more");
 
-CALL deleteEntity(@ParentID);
+CALL deleteEntity(@EntityID3);
 
 CALL tap.finish();
 ROLLBACK;
@@ -217,21 +224,21 @@ DELETE FROM transactions;
 -- insert entity without versioning
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID4, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
 SELECT count(*) INTO @NumOfEntities FROM entities;
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
+SELECT entity_id INTO @InternalEntityID4 FROM name_data WHERE value="EntityName";
 
 SET @TheUser = "TheUser"; -- used to identify the matching entry in transaction_log
 -- fill transaction_log: one entity with two updates (and one insert) and another entity with insert and delete.
 INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds, nanos)
     -- the first entry is the one which is be found by _fix_unversioned
     VALUES
-        ("Update", @EntityID, @TheUser,     "CaosDB",  23458, 254),
+        ("Update", @InternalEntityID4, @TheUser,     "CaosDB",  23458, 254),
         -- the rest is dummy data
-        ("Update", @EntityID, "OtherUser",  "CaosDB",   2345, 633), -- not the latest transaction
-        ("Insert", @EntityID, "OtherUser",  "CaosDB",    245, 633), -- not the latest transaction
-        ("Insert", @EntityID + 1, @TheUser, "CaosDB",   2325, 653), -- not the right entity, inserted before our target
-        ("Delete", @EntityID + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target
+        ("Update", @InternalEntityID4, "OtherUser",  "CaosDB",   2345, 633), -- not the latest transaction
+        ("Insert", @InternalEntityID4, "OtherUser",  "CaosDB",    245, 633), -- not the latest transaction
+        ("Insert", @InternalEntityID4 + 1, @TheUser, "CaosDB",   2325, 653), -- not the right entity, inserted before our target
+        ("Delete", @InternalEntityID4 + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target
 
 
 SELECT tap.eq(COUNT(*), 5, "five entries in transaction_log") FROM transaction_log;
@@ -251,11 +258,11 @@ SELECT tap.eq(COUNT(*), 2,
     "after _fix_unversioned, one entry for our test entity in transactions, one for the standard entities.")
     FROM transactions;
 
-SELECT tap.eq(entity_id, @EntityID, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99;
+SELECT tap.eq(entity_id, @InternalEntityID4, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99;
 SELECT tap.ok(srid IS NOT NULL, "srid was generated and user/time matches entries from transaction_log")
     FROM transactions AS t JOIN transaction_log AS l
     ON (l.seconds = t.seconds AND l.nanos = t.nanos AND l.username = t.username AND l.realm = t.realm)
-    WHERE l.entity_id = @EntityID AND l.username = @TheUser;
+    WHERE l.entity_id = @InternalEntityID4444 AND l.username = @TheUser;
 
 CALL tap.finish();
 ROLLBACK;
@@ -275,18 +282,18 @@ DELETE FROM transactions;
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 
 CALL entityACL(@ACLID1, "{acl1}");
-CALL insertEntity("EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}");
-CALL insertEntity("EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID5, "EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID6, "EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}");
 SELECT count(*) INTO @NumOfEntities FROM entities;
-SELECT entity_id INTO @EntityID1 FROM name_data WHERE value="EntityName1";
-SELECT entity_id INTO @EntityID2 FROM name_data WHERE value="EntityName2";
+SELECT entity_id INTO @InternalEntityID5 FROM name_data WHERE value="EntityName1";
+SELECT entity_id INTO @InternalEntityID6 FROM name_data WHERE value="EntityName2";
 
 INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds,
         nanos)
     -- the first entry is the one which will be found by _fix_unversioned
-    VALUES ("INSERT", @EntityID1, "User", "CaosDB", 10000, 250),
-        ("INSERT", @EntityID2, "User", "CaosDB", 10000, 250),
-        ("UPDATE", @EntityID2, "User", "CaosDB", 20000, 250);
+    VALUES ("INSERT", @InternalEntityID5, "User", "CaosDB", 10000, 250),
+        ("INSERT", @InternalEntityID6, "User", "CaosDB", 10000, 250),
+        ("UPDATE", @InternalEntityID6, "User", "CaosDB", 20000, 250);
 
 
 SELECT tap.eq(COUNT(*), 3, "three entries in transaction_log") FROM transaction_log;
@@ -309,10 +316,10 @@ SELECT tap.eq(COUNT(*), 3,
 
 SELECT tap.eq(seconds, 10000, "version seconds of entity 1 is correct")
     FROM entity_version AS v JOIN transactions AS t
-    ON (v.srid = t.srid) WHERE v.entity_id = @EntityID1;
+    ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID1;
 SELECT tap.eq(seconds, 20000, "version seconds of entity 2 is correct")
     FROM entity_version AS v JOIN transactions AS t
-    ON (v.srid = t.srid) WHERE v.entity_id = @EntityID2;
+    ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID2;
 
 CALL tap.finish();
 ROLLBACK;
diff --git a/tests/test_insert_update_delete.sql b/tests/test_insert_update_delete.sql
index a11b05e3d9a72d6038800adebf5b73c699c2a2b8..ff1e4ec3acc6fe0121ff168279fe7659e05a914c 100644
--- a/tests/test_insert_update_delete.sql
+++ b/tests/test_insert_update_delete.sql
@@ -1,9 +1,31 @@
+/**
+ * This file is a part of the CaosDB Project.
+ *
+ * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
 USE _caosdb_schema_unit_tests;
 BEGIN;
 CALL tap.no_plan();
 
 -- SETUP
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+
 -- Disable versioning and only test the non-versioning behavior
 DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING";
 
@@ -16,31 +38,31 @@ SELECT entity_id into @TextDatatypeID FROM name_data WHERE value ="TEXT";
 -- TEST insertEntity
 SELECT tap.eq(COUNT(id), 0, "No entities")
     FROM entities WHERE id>=100;
-CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}");
 
 SELECT tap.eq(COUNT(entity_id), 1, "Entity has been inserted")
     FROM name_data WHERE value="EntityName";
 
-SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName";
-SELECT tap.ok(@EntityID >= 100, "EntityID greater 99");
+SELECT entity_id INTO @InternalEntityID FROM name_data WHERE value="EntityName";
+SELECT tap.ok(@InternalEntityID >= 100, "EntityID greater 99");
 
 SELECT tap.eq(acl, @ACLID1, "correct acl id had been assigned")
-    FROM entities WHERE id=@EntityID;
+    FROM entities WHERE id=@InternalEntityID;
 
 
 -- TEST insertEntityProperty
-CALL insertEntity("AProperty", "APropDesc", "PROPERTY", "{acl1}");
-SELECT entity_id INTO @PropID FROM name_data WHERE value="AProperty";
-INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @PropID, @TextDatatypeID);
+CALL insertEntity(@EntityID2, "AProperty", "APropDesc", "PROPERTY", "{acl1}");
+SELECT entity_id INTO @InternalPropertyID FROM name_data WHERE value="AProperty";
+INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @InternalPropertyID, @TextDatatypeID);
 
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 0, "No data in null_data table");
-CALL insertEntityProperty(0, @EntityID, @PropID, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0);
+CALL insertEntityProperty(0, @EntityID1, @EntityID2, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0);
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 1, "One row in null_data table");
 
 -- TEST updateEntity
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID1, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
 
 SELECT tap.eq(COUNT(entity_id), 0, "Old Entity name not present")
     FROM name_data WHERE value="EntityName";
@@ -48,21 +70,21 @@ SELECT tap.eq(COUNT(entity_id), 1, "Entity name has been updated")
     FROM name_data WHERE value="NewEntityName";
 
 SELECT tap.eq(acl, @ACLID2, "acl has been updated")
-    FROM entities WHERE id=@EntityID;
+    FROM entities WHERE id=@InternalEntityID;
 
 -- CALL updateEntity again an update the Name
-CALL updateEntity(@EntityID, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}");
-CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID2, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}");
+CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}");
 
 
 -- TEST deleteEntityProperties
-CALL deleteEntityProperties(@EntityID);
+CALL deleteEntityProperties(@EntityID1);
 SELECT COUNT(*) INTO @x FROM null_data;
 SELECT tap.eq(@x, 0, "data removed from null_data table");
 
 -- TEST deleteEntity
-CALL deleteEntity(@EntityID);
-CALL deleteEntity(@PropID);
+CALL deleteEntity(@EntityID1);
+CALL deleteEntity(@EntityID2);
 SELECT COUNT(id) INTO @x FROM entities WHERE id>100;
 SELECT tap.eq(@x, 0, "entity deleted");
 
diff --git a/tests/test_issues.sql b/tests/test_issues.sql
index ab64de844e01c2ad3e273d6ea1e0c24709781a09..ef5abd400387410e18057a5a2281f1d9c391a38d 100644
--- a/tests/test_issues.sql
+++ b/tests/test_issues.sql
@@ -1,9 +1,9 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
  * Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com>
+ * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,14 +17,16 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
 BEGIN;
 CALL tap.no_plan();
 
+SET @EntityID1 = 10001;
+SET @EntityID2 = 10002;
+SET @EntityID3 = 10003;
+SET @EntityID4 = 10004;
 
 -- ########################################################################
 -- TEST Issues from https://gitlab.com/caosdb/caosdb-mysqlbackend/-/issues
@@ -42,23 +44,18 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES
 CALL entityACL(@ACLID1, "{acl1}");
 
 -- Insert entities and obtain IDs
-CALL insertEntity("A", "Desc A", "RECORDTYPE", "{acl1}");
-CALL insertEntity("B", "Desc B", "RECORDTYPE", "{acl1}");
-CALL insertEntity("C", "Desc C", "RECORDTYPE", "{acl1}");
-CALL insertEntity("rec", "Desc rec", "RECORD", "{acl1}");
-
-SELECT entity_id INTO @ID_A FROM name_data WHERE value="A";
-SELECT entity_id INTO @ID_B FROM name_data WHERE value="B";
-SELECT entity_id INTO @ID_C FROM name_data WHERE value="C";
-SELECT entity_id INTO @ID_rec FROM name_data WHERE value="rec";
+CALL insertEntity(@EntityID1, "A", "Desc A", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID2, "B", "Desc B", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID3, "C", "Desc C", "RECORDTYPE", "{acl1}");
+CALL insertEntity(@EntityID4, "rec", "Desc rec", "RECORD", "{acl1}");
 
 -- Insert is-a relationships
-CALL insertIsA(@ID_A, @ID_B);
-CALL insertIsA(@ID_B, @ID_C);
-CALL insertIsA(@ID_rec, @ID_A);
+CALL insertIsA(@EntityID1, @EntityID2);
+CALL insertIsA(@EntityID2, @EntityID3);
+CALL insertIsA(@EntityID4, @EntityID1);
 
 -- Try to delete last child
 -- leads to failure in issue #21
-CALL deleteIsa(@ID_rec);
+CALL deleteIsa(@EntityID4);
 
 ROLLBACK;
diff --git a/tests/test_reference_values.sql b/tests/test_reference_values.sql
index 47b4db4d33cd7e841da610aca886a3d6bd4947d3..2b9dcefc8f6244f1753185fe86e351c847baa3a2 100644
--- a/tests/test_reference_values.sql
+++ b/tests/test_reference_values.sql
@@ -1,9 +1,8 @@
 /**
- * ** header v3.0
  * This file is a part of the CaosDB Project.
  *
- * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com>
- * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com>
+ * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com>
+ * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com>
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Affero General Public License as
@@ -17,8 +16,6 @@
  *
  * You should have received a copy of the GNU Affero General Public License
  * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * ** end header
  */
 
 USE _caosdb_schema_unit_tests;
@@ -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/make_db b/utils/make_db
index c9fffc4589621e64a1877d0d2db1d744186b222e..071de0a3270fd0e3480cb54bbc692635983bd287 100755
--- a/utils/make_db
+++ b/utils/make_db
@@ -136,6 +136,11 @@ name in your .config file "
 function restore_db() {
     SQL_FILE="$1"
     $MYSQL_CMD $(get_mysql_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
+can use the 'grant' action of this script to do this.
+EOF
 }
 
 function test-connection() {
@@ -174,6 +179,9 @@ function grant() {
 
     for host in ${DATABASE_USER_HOST_LIST//,/ } ; do
         echo "Granting admin privileges to '$DATABASE_USER'@'$host'"
+        # 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
 CREATE USER IF NOT EXISTS
     '$DATABASE_USER'@'$host' identified by '$DATABASE_USER_PW';