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