diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 5c49eb7e9c88346b8423a611dc14aca2e85cf346..f9a4145fdf1a70e7be1ede3649261757a12d2c65 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:buster +FROM debian:bookworm RUN apt-get update \ && \ apt-get install -y \ @@ -11,4 +11,8 @@ RUN apt-get update \ python3-sqlparse \ python3-sphinx \ doxygen -RUN pip3 install breathe sphinx-rtd-theme recommonmark +RUN pip3 install --break-system-packages \ + breathe \ + sphinx-rtd-theme \ + pytest \ + recommonmark diff --git a/.docker/docker-compose.yml b/.docker/docker-compose.yml new file mode 100644 index 0000000000000000000000000000000000000000..8c6555eb457a992f69625c55bfced34d9b1c51fd --- /dev/null +++ b/.docker/docker-compose.yml @@ -0,0 +1,23 @@ +version: '3.6' +services: + sqldb: + image: mariadb:11.4 + volumes: + - type: volume + source: "caosdb-sqldata" + target: /var/lib/mysql + environment: + MYSQL_ROOT_PASSWORD: caosdb1234 + networks: + # available on port 3306, host name 'sqldb' + - caosnet + ports: + - 3306:3306 + + +# A well-defined network for caosdb +volumes: + caosdb-sqldata: +networks: + caosnet: + driver: bridge diff --git a/.gitignore b/.gitignore index 26060c8b9c3986ed5a0803bcf1e1e2a88acee1a3..6f952db9ec3600b624a0151d97db6d299cbd53ca 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ libs/* # Generated files _doxygen/ _generated/ -/build/ \ No newline at end of file +/build/ +*~ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 1e54f4c213acfb9f2b67e01b2ad38b64171c31c0..3137b6ad8ddc686c563e78e6e2c5ee3f0a6ca3fe 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -3,7 +3,9 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen +# Copyright (C) 2024 Indiscale GmbH <info@indiscale.com> # Copyright (C) 2019 Henrik tom Wörden +# Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -59,43 +61,35 @@ unittests-mariadb: tags: [ docker ] stage: test services: - - mariadb:10.4 - + - mariadb:10.11 script: - make pipeline-test SQL_HOST=mariadb -# Run the unit tests with MySQL 8 -unittests-mysql-8: - tags: [ docker ] - stage: test - # Should not stop the pipeline from continuing. - allow_failure: true - services: - - name: mysql:8.0 - command: ["--default-authentication-plugin=mysql_native_password"] - - script: - - sed "s/NO_AUTO_CREATE_USER,//" -i tests/example.dump.sql - - rm tests/test_autotap.sql - - make pipeline-test SQL_HOST=mysql - -# Run the unit tests with MySQL 5 -unittests-mysql-5: +# Run the dump update tests +test-dump-update: tags: [ docker ] stage: test - # Should not stop the pipeline from continuing. - allow_failure: true - services: - - name: mysql:5.7 - command: ["--default-authentication-plugin=mysql_native_password"] - script: - # remove some lines from autotap because the checks of column default - # values don't work with mysql-5 - - sed -i "/col_default_is.*NULL/d" tests/test_autotap.sql - - sed -i "/col_default_is.*INACTIVE/d" tests/test_autotap.sql - - sed -i "/col_default_is.*SHA/d" tests/test_autotap.sql - - make pipeline-test SQL_HOST=mysql + - make test-dump-update + +# # Run the unit tests with MySQL 5 +# unittests-mysql-5: +# tags: [ docker ] +# stage: test +# # Should not stop the pipeline from continuing. +# allow_failure: true +# services: +# - name: mysql:5.7.36 +# command: ["--default-authentication-plugin=mysql_native_password"] +# +# script: +# # remove some lines from autotap because the checks of column default +# # values don't work with mysql-5 +# - sed -i "/col_default_is.*NULL/d" tests/test_autotap.sql +# - sed -i "/col_default_is.*INACTIVE/d" tests/test_autotap.sql +# - sed -i "/col_default_is.*SHA/d" tests/test_autotap.sql +# - sed -i "s/utf8mb3/utf8/" tests/test_autotap.sql +# - make pipeline-test SQL_HOST=mysql ######## Deploy ######## diff --git a/CHANGELOG.md b/CHANGELOG.md index 22588269882a81dd299b2e56120576d2382d9426..3bd316eb5605e52ad4c4ee60e84a6d40db5512c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,31 +5,166 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] ## +## [Unreleased] + +### Added + +- New version requirement: MariaDB 11.2 or later. + +### Changed + +* Changed names from CaosDB to LinkAhead. + +### Deprecated + +### Removed + +- MySQL support. See the deprecation in the 7.0.0 release. + +### Fixed + +- [SQL dump migration can now be applied + twice](https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/60): + Fixed an error in the regex. +- [linkahead-server#264](https://gitlab.com/linkahead/linkahead-server/-/issues/264) + Queries ignore accents and umlauts: Changed to more appropriate + collation and character sets. This requires MariaDB 11.2 or later, + see above. + +### Security + +## [8.0.0] - 2024-10-24 ## + +### Added ### + +- Script to update outdated database dumps. + +### Changed ### + +- `OFFSET` is a reserved keyword in MariaDB 10.6, so the former + `OFFSET` parameter name in the `get_head_relative` function was + changed to HeadOffset. See + [`update_dumps/README.md`](update_dumps/README.md) for information + on how to update old SQL dumps to be compatible with this renaming + and MariaDB >= 10.6. + +## [7.0.2] - 2023-12-12 ## +(Timm Fitschen) + +### Fixed ### + +* make install: Could not connect to MariaDB in local docker + container + [linkahead-mariadbbackend](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues/33) +* Wrong ids in data_type table due to a bug in the `linkahead-server < v0.11.0` + which has been fixed but left broken data. This resulted in server errors + [linkahead-mariadbbackend#34](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues/34) + +## [7.0.1] - 2023-11-01 +(Timm Fitschen) ### Added ### +* Sanity checks during `make install` and `make upgrade`. + +## [7.0.0] - 2023-10-25 ## +(Timm Fitschen) + ### Changed ### -* Changed names from CaosDB to LinkAhead. +* Change signature of procedure `insertEntityDataType`: expect the data type ID + instead of the name. +* Change result set of procedure `retrieveEntity`: Rename column `Datatype` to + `DatatypeName` and add column `DatatypeID`. +* Change result set of procedure `retrieveOverrides`: Rename column + `type_override` to `type_name_override` and add `type_id_override`. +* Change signature of procedure `updateEntity`: expect the data type ID instead + to the name. +* Internal ids, when returned by `retrieveEntityProperties`, + `registerReplacementIds`, or `retrieveOverrides`, are prefixed by a special + character which serves as a ephemeral marker. Currently this is `$` but this + may change in the future if there is a more suitable candidate. ### Deprecated ### -### Removed ### +* MySQL Support. Last version which is known to work well with LinkAhead is MySQL 5.7.36 ### Fixed ### -### Security ### +* Unknown Server Error when inserting an Entity. + [linkahead-mariadbbackend#48](https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/48). +* Fix broken `initEntity` procedure (and change the first parameters type from + INT UNSIGNED to VARCHAR(255) which is non-breaking). -## [5.0.0] - 2021-10-28 ## +## [6.0.1 2023-10-18] ## + +### Fixed ### +* Old passwords table is removed from dumps where it still exists. + +## [6.0.0 2023-10-17] ## + +This is a major update. Switching from integer ids for internal and external use to string ids for the external use while keeping the old integer ids for internal use. ### Added ### -* #33 CI pipeline for MySQL (was only MariaDB before). +* Table `entity_ids` +* Procedure `getIdByName` +* Procedure `insertEntityDataType` and `insertEntityCollection` +* Procedure `setFileProperties`. ### Changed ### -### Deprecated ### +* Rename PROCEDURE `registerSubdomain` to `registerReplacementIds`. +* Change column `entities.role` datatype: replace 'DOMAIN' enum value with `_REPLACEMENT`. +* Change column `transactions_log.entity_id` to VARCHAR(255) +* Change column `user_info.entity` to VARCHAR(255) +* Change signature of procedure `applyIDFilter` - `EntityID VARCHAR(255)` +* Change signature of procedure `initBackreference` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)` +* Change signature of procedure `initPOVPropertiesTable` - `PropertyID VARCHAR(255)` +* Change signature of procedure `initPOVRefidsTable` - `PropertyID VARCHAR(255)` +* Change signature of procedure `initSubEntity` - `EntityID VARCHAR(255)` +* Change signature of procedure `deleteEntity` - `EntityID VARCHAR(255)` +* Change signature of procedure `deleteEntityProperties` - `EntityID VARCHAR(255)` +* Change signature of procedure `get_primary_parent_version` - `EntityID VARCHAR(255)` +* Change signature of procedure `get_version_timestamp` - `EntityID VARCHAR(255)` +* Change signature of procedure `get_head_version` - `EntityID VARCHAR(255)` +* Change signature of procedure `get_head_relative` - `EntityID VARCHAR(255)` +* Change signature of procedure `get_version_history` - `EntityID VARCHAR(255)` +* Change signature of procedure `retrieveQueryTemplateDef` - `EntityID VARCHAR(255)` +* Change signature of procedure `getDependentEntities` - `EntityID VARCHAR(255)` +* Change signature of procedure `insertEntity` - Add parameter `EntityID VARCHAR(255)` +* Change signature of procedure `insertEntityProperty` - `EntityID VARCHAR(255)` and `PropertyID VARCHAR(255)`, `DomainID VARCHAR(255)`, `DatatypeOverride VARCHAR(255)` +* Change signature of procedure `insertIsa` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`. +* Change signature of procedure `isSubtype` - `ChildID VARCHAR(255)`, `ParentID VARCHAR(255)`. +* Change signature of procedure `retrieveEntity` - `EntityID VARCHAR(255)` +* Change signature of procedure `retrieveOverrides` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)` +* Change signature of procedure `retrieveEntityParents` - `EntityID VARCHAR(255)` +* Change signature of procedure `retrieveEntityProperties` - `EntityID VARCHAR(255)`, `DomainID VARCHAR(255)` +* Change signature of procedure `updateEntity` - `EntityID VARCHAR(255)` + +### Removed ### + +* Deactivate procedure `delete_all_entity_versions`. This might be used in the + future, that is why we keep the code in a comment. +* Drop procedure `retrieveSubEntity` +* Drop procedure `retrieveDatatype` +* Drop procedure `retrieveGroup` +* Drop procedure `getInfo` +* Drop procedure `getRole` +* Drop procedure `setPassword` +* Drop procedure `initAutoIncrement` +* Delete special entity 50 (SQLite Datatype) +* Delete special entity 99 (Work-around for the auto-increment) + +### Fixed ### + +* Change signature of procedure `getFileIdByPath` - `FilePath TEXT` - this length is needed for the path column of `file_entities`. + +## [5.0.0] - 2021-10-28 ## + +### Added ### + +* #33 CI pipeline for MySQL (was only MariaDB before). ### Removed ### @@ -43,8 +178,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * #32 Removed unused `groups` table from installation routines which prevented the installation with MySQL 8. -### Security ### - ## [4.1.0] - 2021-06-11 ## ### Added ### @@ -65,31 +198,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * `get_version_history` returns two additional columns, `child_username` and `child_realm`. * Added a `versioned` flag to the following procedures: - * `applyBackReference` - * `applyIDFilter` - * `applyPOV` - * `applyRefPOV` - * `makeStmt` - * `calcComplementUnion` - * `calcDifference` - * `calcIntersection` - * `finishSubProperty` - * `getChildren` - * `initEmptyTargetSet` - * `initDisjunctionFilter` - * `initEntity` - * `initQuery` - * `createTmpTable` + * `applyBackReference` + * `applyIDFilter` + * `applyPOV` + * `applyRefPOV` + * `makeStmt` + * `calcComplementUnion` + * `calcDifference` + * `calcIntersection` + * `finishSubProperty` + * `getChildren` + * `initEmptyTargetSet` + * `initDisjunctionFilter` + * `initEntity` + * `initQuery` + * `createTmpTable` * Added a `direct` column to `archive_isa` table -### Deprecated ### - ### Removed ### * unused procedures: - * `initNegationFilter` - * `initConjunctionFilter` - * `finishNegationFilter` + * `initNegationFilter` + * `initConjunctionFilter` + * `finishNegationFilter` ### Fixed ### @@ -109,8 +240,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 version resultet in an error. See corresponding test in `linkahead-pyinttest` `tests/test_versioning.py::test_datatype_without_name` -### Security ### - ## [3.0.0] - 2020-09-01 ## ### Added ### @@ -128,20 +257,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 with a lot of additions to the API. E.g. * New `entity_version`. * All `*_data` tables have a new twin, the `archive_*_data` table, where all - old versions of entities are stored. The `*_data` tables only contain the - data of the latest version. + old versions of entities are stored. The `*_data` tables only contain the + data of the latest version. * Additional `archive_isa` for the history entities' parents. * Additional `_iversion` column for the `reference_data` table for storing - references to particular versions of an entity. + references to particular versions of an entity. * New `setFileProperties` and `retrieveQueryTemplateDef` procedures which reduce server code and let the - backend decide which tables to use. Also, this is necessary for the - versioning, because these procedures behave differently depending on the - ENTITY_VERSIONING feature being enabled or disabled. + backend decide which tables to use. Also, this is necessary for the + versioning, because these procedures behave differently depending on the + ENTITY_VERSIONING feature being enabled or disabled. * Several functions and procedures for the interaction with the - `entity_version` table and the `transactions` table. E.g. - `insert_single_child_version`, `delete_all_entity_versions`, - `get_iversion`, `get_primary_parent_version`, `get_version_timestamp`, - `get_head_version`, `get_head_relative`, `get_version_history`. + `entity_version` table and the `transactions` table. E.g. + `insert_single_child_version`, `delete_all_entity_versions`, + `get_iversion`, `get_primary_parent_version`, `get_version_timestamp`, + `get_head_version`, `get_head_relative`, `get_version_history`. The versions are tracked internally by the `_iversion` field which is an integer and which should not be used outside of the backend. * New makefile targets for testing with MariaDB instance from Docker image: call @@ -164,5 +293,3 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Bug in `updateEntity.sql` (when updating the primary name without a prior call to `deleteEntityProperties`). Same thing for `deleteEntity`. * #21 Bug which prevented deletion of deeply inheriting entities, if versioning was enabled. - -### Security ### diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000000000000000000000000000000000..3d997f969ded2b5b3b8f9975835e51be7e86b30a --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,28 @@ +cff-version: 1.2.0 +message: "If you use this software, please cite it as below." +authors: + - family-names: Fitschen + given-names: Timm + orcid: https://orcid.org/0000-0002-4022-432X + - family-names: Schlemmer + given-names: Alexander + orcid: https://orcid.org/0000-0003-4124-9649 + - family-names: Hornung + given-names: Daniel + orcid: https://orcid.org/0000-0002-7846-6375 + - family-names: tom Wörden + given-names: Henrik + orcid: https://orcid.org/0000-0002-5549-578X + - family-names: Spreckelsen + given-names: Florian + orcid: https://orcid.org/0000-0002-6856-2910 + - family-names: Parlitz + given-names: Ulrich + orcid: https://orcid.org/0000-0003-3058-1435 + - family-names: Luther + given-names: Stefan + orcid: https://orcid.org/0000-0001-7214-8125 +title: "LinkAhead - MariaDB Backend" +version: 8.0.0 +doi: 10.3390/data4020083 +date-released: 2024-10-10 diff --git a/Makefile b/Makefile index e776ee0babe292158c9e886730b4a41448375ac2..c2cbce0edc270234c9af76167eeaa0b6fe777abc 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ +# This file is a part of the Linkahead Project. # -# ** header v3.0 -# This file is a part of the LinkAhead Project. -# +# Copyright (C) 2025 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (C) 2025 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen # @@ -18,8 +18,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header -# + SHELL=/bin/bash INSTALL_SQL_FILE=db_5_0.sql @@ -34,6 +33,7 @@ test-connection: .PHONY: upgrade upgrade: @cd patches; ./applyPatches.sh --env=../.config + @./utils/make_db sanity_check .PHONY: install install: _install _grant upgrade @@ -55,23 +55,26 @@ drop-%: test: ./utils/make_db test --fresh -# Run tests with a database which is started in a Docker container +.PHONY: test-dump-update +test-dump-update: + pytest dump_updates + +# Run tests with a database which is started in a MariaDB Docker container .PHONY: test-docker test-docker: @docker kill linkahead-mysqlserver-test || true - @docker container rm linkahead-mysqlserver-test || true + @docker container rm -v linkahead-mysqlserver-test || true @docker run --name linkahead-mysqlserver-test -p "3306:3306" \ - -e MYSQL_ROOT_PASSWORD="pass-for-test" -d mariadb + -e MYSQL_ROOT_PASSWORD="pass-for-test" -d mariadb:11.4 @sleep 10 MAINPATH=$(realpath tests/docker_env) utils/make_db test --fresh - @docker kill linkahead-mysqlserver-test - @docker container rm linkahead-mysqlserver-test + make test-docker-stop # if automatic stopping failed .PHONY: test-docker-stop test-docker-stop: docker kill linkahead-mysqlserver-test - docker container rm linkahead-mysqlserver-test + docker container rm -v linkahead-mysqlserver-test # Compile the standalone documentation .PHONY: doc @@ -85,7 +88,9 @@ pipeline-test: echo 'DATABASE_USER_HOST_LIST="%,"' >> .config echo "MYSQL_USER_PASSWORD=$(MYSQL_ROOT_PASSWORD)" >> .config echo "MYSQL_HOST=$(SQL_HOST)" >> .config + echo "MYSQL_OPTS=--protocol=TCP" >> .config sleep 10 make install ./utils/make_db restore_db tests/example.dump.sql + make upgrade ./tests/test_utils.sh diff --git a/README.md b/README.md index 9e9d7c929cf872f8f8662e8912a3bec310cf293c..3c714592bc1ce7f71a7492c7c6ab53cbea48d5fc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ ## Welcome -This is the **LinkAhead MySQL Backend** repository and a part of the +This is the **LinkAhead MariaDB Backend** repository and a part of the LinkAhead project. ## Setup @@ -18,30 +18,32 @@ Please refer to the [official documentation](https://docs.linkahead.org/linkahea ## Contributing -Thank you very much to all contributers—[past, present](https://gitlab.com/linkahead/linkahead/-/blob/dev/HUMANS.md), and prospective ones. +Thank you very much to all contributers—[past, +present](https://gitlab.com/linkahead/linkahead/-/blob/main/HUMANS.md), and prospective +ones. ### Code of Conduct -By participating, you are expected to uphold our [Code of Conduct](https://gitlab.com/linkahead/linkahead/-/blob/dev/CODE_OF_CONDUCT.md). +By participating, you are expected to uphold our [Code of +Conduct](https://gitlab.com/linkahead/linkahead/-/blob/main/CODE_OF_CONDUCT.md). ### How to Contribute -* You found a bug, have a question, or want to request a feature? Please -[create an issue](https://gitlab.com/linkahead/linkahead-mysqlbackend/-/issues). -* You want to contribute code? Please fork the repository and create a merge -request in GitLab and choose this repository as target. Make sure to select -"Allow commits from members who can merge the target branch" under Contribution -when creating the merge request. This allows our team to work with you on your request. -- If you have a suggestion for the [documentation](https://docs.indiscale.com/linkahead-mysqlbackend/), -the preferred way is also a merge request as describe above (the documentation resides in `src/doc`). -However, you can also create an issue for it. -- You can also contact us at **info (AT) linkahead.org**. +* You found a bug, have a question, or want to request a feature? Please +[create an issue](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/issues). +* You want to contribute code? + * **Forking:** Please fork the repository and create a merge request in GitLab and choose this repository as + target. Make sure to select "Allow commits from members who can merge the target branch" under + Contribution when creating the merge request. This allows our team to work with you on your + request. +* You can also join the LinkAhead community on + [#linkahead:matrix.org](https://matrix.to/#/!unwwlTfOznjEnMMXxf:matrix.org). ## License * Copyright (C) 2018 Research Group Biomedical Physics, Max Planck Institute for Dynamics and Self-Organization Göttingen. -* Copyright (C) 2020-2023 Indiscale GmbH <info@indiscale.com> +* Copyright (C) 2020-2025 Indiscale GmbH <info@indiscale.com> All files in this repository are licensed under a [GNU Affero General Public License](LICENCE.md) (version 3 or later). diff --git a/README_SETUP.md b/README_SETUP.md index 88fbe41de13229faac502a89a4b767c15ae013e3..689852903dc4e0530fc464fe9e1cb95e2f3e5455 100644 --- a/README_SETUP.md +++ b/README_SETUP.md @@ -1,9 +1,9 @@ -# Setup of the LinkAhead SQL back end +# Setup of the LinkAhead MariaDB backend ## Dependencies -* `MariaDB Client 10.1`, `MySQL Client 5.5`, or later versions. In the case of - MySQL, version 5.6 is recommended. -- make + +* `MariaDB Client 11.2` or later. +* make ## Create the configuration * Create an empty `.config` file. For the default values and the meaning of @@ -12,7 +12,7 @@ parameter that you want to change, add a corresponding line in your `.config` file. You probably want to change the passwords. As the passwords are stored unencrypted in the `.config` file, make sure nobody else can read it. - * If there is no `mysql-config-editor` (`MySQL 5.5`. and `MariaDB`) then the + * If there is no `mysql-config-editor` program, then the `MYSQL_USER_PASSWORD` must be provided, that is the password of the `MYSQL_USER`. * If you are using MariaDB and the `root` database user uses pam @@ -22,7 +22,7 @@ ## Setup the SQL database for LinkAhead -* Run `make install`. If a there is a database with the name you have choosen +* Run `make install`. If a there is a database with the name you have chosen during the configuration, you need to reconfigure or delete the database first. * *Required database privileges:* @@ -88,19 +88,46 @@ with the then current version of the stored entities. * Alternatively, to run the tests in a containerized MariaDB instance, run `make test-docker`, followed by `make test-docker-stop`. + +### Running in a Docker Container + +You can use `.docker/docker-compose.yml` to start a docker container +(`docker-compose -f .docker/docker-compose.yml up -d`) that runs mariadb. You +need appropriate settings in `.config`: +* `MYSQL_OPTS="--protocol=TCP"` and +* `DATABASE_USER_HOST_LIST=%,` +After the first start, you need to install the database: `make install`. +Then, you can connect to it with `mariadb --protocol=TCP -u caosdb -prandom1234 +caosdb`. + +### Developing tests ### + +To use the mytap framework: + +```console +$ cd libs; unzip mytap-1.0.zip; cd mytap-1.0 +# Use the necessary mariadb options for connecting to the server in the following commands +$ mariadb ... < mytap.sql # Set up the "tap" database and functions. +$ mariadb ... < scripts/autotap.sql # Insert the "autotap" function. +# Create autotap file (for comparison with current state) +$ mariadb ... --raw -B --skip-column-names -e "call tap.autotap('_caosdb_schema_unit_tests')" > test_autotap.current.sql +# Run the autotap tests (may fail unfortunately with current MariaDB): +$ mariadb ... < test_autotap.current.sql +``` + ### Troubleshooting -#### MySQL has failing tests +#### Failure to restore a database dump created with an older MariaDB version #### -Our test suite is developed with MariaDB. That is why some tests, those which -check constraints based on auto-generated names, fail because MySQL generates -other names. +Have a look into the `dump_updates/README.md`. In cases of version +incompatibilities, the necessary steps to migrate the dump are +probably described there and scripts for the migrations are provided +in the same directory. -Also some test fail with the message "Expected: NULL / Was: NULL" which is -obviously what was expected. +#### MySQL has failing tests -Please look carefully through the tests. If something more serious than that -comes up, please report a bug. +*Note: Since we switched from MySQL to MariaDB, the two DBMS projects have diverged quite far. As a +result, we no longer support MySQL. ## Documentation # diff --git a/RELEASE_GUIDELINES.md b/RELEASE_GUIDELINES.md index 9b06342c9d4a91f1add4bd61559ecd1d8e94546a..41c47136c1ab7160578950a384ce9c6ab2182b5b 100644 --- a/RELEASE_GUIDELINES.md +++ b/RELEASE_GUIDELINES.md @@ -1,12 +1,13 @@ -# Release Guidelines for the LinkAhead MySQL Backend +# Release Guidelines for the LinkAhead MariaDB backend This document specifies release guidelines in addition to the general release -guidelines of the LinkAhead Project -([RELEASE_GUIDELINES.md](https://gitlab.com/linkahead/linkahead/blob/dev/RELEASE_GUIDELINES.md)) +guidelines of the CaosDB Project +([RELEASE_GUIDELINES.md](https://gitlab.com/caosdb/caosdb-meta/-/blob/dev/RELEASE_GUIDELINES.md)) ## General Prerequisites -* All tests are passing. +* All tests are passing. (Note that pipelines may fail if the major + version increased. Rely on manual tests in that case.) * (FEATURES.md is up-to-date and a public API is being declared in that document.) * CHANGELOG.md is up-to-date. * (DEPENDENCIES.md is up-to-date.) @@ -19,10 +20,23 @@ guidelines of the LinkAhead Project 2. Check all general prerequisites. -4. Merge the release branch into the main branch. +3. Assure that the latest patch actually updates the CaosDBVersion() procedure + and that the version matches the version you are about to release. -5. Tag the latest commit of the main branch with `v<VERSION>`. +4. Update version in `doc/conf.py` and in `CITATION.cff`. -6. Delete the release branch. +5. Merge the release branch into the main branch. -7. Merge the main branch back into the dev branch. +6. Wait for the main branch pipeline to pass. + +7. Tag the latest commit of the main branch with `v<VERSION>`. + +8. Delete the release branch. + +9. Merge the main branch back into the dev branch and add the `[UNRELEASED]` + section to the CHANGELOG. + +10. Create a release at the [gitlab repo](https://gitlab.com/linkahead/linkahead-mariadbbackend/-/releases) + +11. If necessary, i.e., if the patch or major versions were increased + with the release, do a LinkAhead server release. diff --git a/config.defaults b/config.defaults index 79ebcba154f01dd86ad3b4399bca2eb84656632b..aba6e0c25d6d275c653f6e6b063d8d25bd281678 100644 --- a/config.defaults +++ b/config.defaults @@ -1,7 +1,7 @@ -# -# ** header v2.0 # This file is a part of the LinkAhead Project. # +# Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com> # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen # @@ -15,11 +15,9 @@ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # -# You should have received a copy of the GNU General Public License +# You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header -# # # Commands # The MySQL client program. @@ -40,6 +38,12 @@ MYSQL_PORT=3306 # which will then be used by the LinkAhead Server. MYSQL_USER=root MYSQL_USER_PASSWORD=caosdb1234 +# Additional options for the connection +# e.g. if you want to connect a dockerized MariaDB at localhost you need to put +# "--protocol=TCP" here because when host=localhost the connection defaults to +# SOCKET. +# MYSQL_OPTS='--protocol=TCP' +MYSQL_OPTS= # # DATABASE # The name of the SQL database. diff --git a/doc/Maintenance.rst b/doc/Maintenance.rst index fbdef943a3b579c2457b746d09cfcd6d530c128a..ec8d8f3f6a677527a5a581096dc9bbd9c7068d97 100644 --- a/doc/Maintenance.rst +++ b/doc/Maintenance.rst @@ -1,12 +1,9 @@ - Maintenance =========== - Creating a Backup ----------------- - You can use the Python script ``utils/backup.py`` to create a backup (SQL dump) of the SQL-Backend:: diff --git a/doc/conf.py b/doc/conf.py index 20f21f40728038c43e98725f6929bd1905d66dc6..1c33c3faa66aae1a78f2c9cd333b442ed227f7f3 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -22,13 +22,13 @@ import sphinx_rtd_theme # -- Project information ----------------------------------------------------- project = 'linkahead-mysqlbackend' -copyright = '2023, IndiScale GmbH' +copyright = '2021 - 2024, IndiScale GmbH' author = 'Daniel Hornung' # The short X.Y version -version = '6.0' +version = '8.0.1' # The full version, including alpha/beta/rc tags -release = '6.0.0-SNAPSHOT' +release = '8.0.1-SNAPSHOT' # -- General configuration --------------------------------------------------- diff --git a/doc/index.rst b/doc/index.rst index 652b8556ca4cbbf29a6d29063e0d6d12d9b8b83e..fc6fd46750fa5cd4459f440e7ca7ac5afc041cb3 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -10,7 +10,9 @@ Welcome to documentation of LinkAhead's MySQL Backend! Getting started <README_SETUP> Concepts <concepts> Maintenance - API documentation<functions> + API documentation <functions> + Related Projects <related_projects/index> + Back to Overview <https://docs.indiscale.com/> This documentation helps you to :doc:`get started<README_SETUP>`, explains the most important :doc:`concepts<concepts>` . diff --git a/doc/related_projects/index.rst b/doc/related_projects/index.rst new file mode 100644 index 0000000000000000000000000000000000000000..78abfd939a097245042a8487eee8ae0d6b4d9e44 --- /dev/null +++ b/doc/related_projects/index.rst @@ -0,0 +1,25 @@ +Related Projects +++++++++++++++++ + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + :hidden: + +.. container:: projects + + For in-depth documentation for users, administrators and developers, you may want to visit the subproject-specific documentation pages for: + + :`Server <https://docs.indiscale.com/caosdb-server>`_: The Java part of the LinkAhead server. + + :`WebUI <https://docs.indiscale.com/caosdb-webui>`_: The default web frontend for the LinkAhead server. + + :`PyLinkAhead <https://docs.indiscale.com/caosdb-pylib>`_: The LinkAhead Python library. + + :`Advanced user tools <https://docs.indiscale.com/caosdb-advanced-user-tools>`_: The advanced Python tools for LinkAhead. + + :`LinkAhead Crawler <https://docs.indiscale.com/caosdb-crawler/>`_: The crawler is the main tool for automatic data integration in LinkAhead. + + :`LinkAhead <https://docs.indiscale.com/caosdb-deploy>`_: Your all inclusive LinkAhead software package. + + :`Back to Overview <https://docs.indiscale.com/>`_: LinkAhead Documentation. diff --git a/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh b/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b9e4843c349a9281526953d6e0c40712a2b1c1a --- /dev/null +++ b/dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash + +# This file is a part of the LinkAhead Project. +# +# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +# About this script +# ================= +# +# Fix the use of "offset" as a procedure parameter name. "OFFSET" became a reserved keyword in +# MariaDB 10.6. +# +# This script takes an SQL dump from stdin and prints the fixed SQL to stdout. +# +# Usage +# ----- +# +# 2024-10-02.dump_fix_mariadb_10_6.sh < yourdump.sql > yourdump.fixed.sql + +set -euo pipefail +IFS=$'\n\t' + +script=' +/^[[:blank:]]+Offset INT UNSIGNED/s/Offset INT UNSIGNED\) RETURNS varbinary\(255\)/HeadOffset INT UNSIGNED\) RETURNS varbinary(255)/ +s/LIMIT 1 OFFSET Offset/LIMIT 1 OFFSET HeadOffset/ +' + +sed -E -e "$script" + +unset script diff --git a/dump_updates/README.md b/dump_updates/README.md new file mode 100644 index 0000000000000000000000000000000000000000..704ea80321a9a873185d0c6959e2000ad26fa10d --- /dev/null +++ b/dump_updates/README.md @@ -0,0 +1,21 @@ +# SQL dump updates # + +## Dump ## + +This directory contains scripts to update database dumps to newer versions of the MariaDB server. + +## Background ## + +In some cases, restoring the database content from existing SQL dumps may not be possible in a +straightforward manner. For those cases, this directory contains scripts to help with known issues. + +Examples for problems include: + +- New reserved keywords in MariaDB, that were previously used as identifiers in code. + +# Known issues and their fix # + +- SQL syntax error near `Offset INT UNSIGNED`: If a dump was made before MariaDB 10.6 (LinkAhead < + 0.15) and with the SQL backend before 7.0.3, there was a pramater named `Offset`. With MariaDB + 10.6 however, `OFFSET` became a reserved keyword. This can be fixed by running + `2024-10-02.dump_fix_mariadb_10_6.sh < yourdump.sql > yourdump.fixed.sql` diff --git a/dump_updates/test/test_all.py b/dump_updates/test/test_all.py new file mode 100644 index 0000000000000000000000000000000000000000..acdeeeceb341c396c91b764e60bd8b30a7bcd19d --- /dev/null +++ b/dump_updates/test/test_all.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python3 + +# This file is a part of the LinkAhead Project. +# +# Copyright (C) 2024 IndiScale GmbH <www.indiscale.com> +# Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. + +"""Testing the dump update scripts + +As a general rule, dump updaters should be idempotent, so tests should run the update again after +the first checks are successlful. + +TODO: Reduce the boilerplate for the tests. +""" + +import filecmp +from pathlib import Path +from subprocess import run +from tempfile import NamedTemporaryFile + + +def get_basedir() -> str: + """Return the assumped base dir for the dump updates. + """ + path = Path(__file__).parents[1] + return str(path) + + +def get_test_data(basename: str) -> list[tuple[str, str]]: + """Return a list of [input, expectedoutput] tuples. + + The output may be an empty string if no corresponding file can be found. + """ + basedir = get_basedir() + datadir = Path(basedir) / "test" / "test_data" + results = [] + for input_path in datadir.glob(f"{basename}.example*[0-9].sql"): + expected_path = datadir / f"{input_path.name[:-4]}.expected.sql" + if expected_path.exists(): + expected = str(expected_path) + else: + expected = "" + results.append((str(input_path), expected)) + return results + + +def test_2024_10_02(tmpdir): + """``Offset`` became a reserved keyword in MariaDB 10.6. + """ + script = "2024-10-02.dump_fix_mariadb_10_6.sh" + script_fullname = str(Path(get_basedir()) / script) + test_data = get_test_data(script[:-3]) + for infile, expectedfile in test_data: + with (NamedTemporaryFile(dir=tmpdir, suffix=".sql", delete=True) as output, + open(infile, mode="rb") as infile_stream + ): + run([script_fullname], + stdin=infile_stream, + stdout=output, + check=True + ) + assert filecmp.cmp(output.name, expectedfile), "Output does not match expected output." + with (NamedTemporaryFile(dir=tmpdir, suffix=".sql", delete=True) as output2, + open(output.name, mode="rb") as infile_stream + ): + run([script_fullname], + stdin=infile_stream, + stdout=output2, + check=True + ) + assert filecmp.cmp(output2.name, expectedfile), ( + "Run 2: Output does not match expected output.") diff --git a/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql new file mode 100644 index 0000000000000000000000000000000000000000..1a58223ba65827231ce658f1a655a68706bf8088 --- /dev/null +++ b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.expected.sql @@ -0,0 +1,36 @@ +/* Just a short snippt with the problem */ + + +/*!50003 SET @saved_col_connection = @@collation_connection */ ; +/*!50003 SET character_set_client = utf8 */ ; +/*!50003 SET character_set_results = utf8 */ ; +/*!50003 SET collation_connection = utf8_general_ci */ ; +DELIMITER ;; +CREATE DEFINER=`root`@`%` FUNCTION `get_head_relative`(EntityID VARCHAR(255), + HeadOffset INT UNSIGNED) RETURNS varbinary(255) + READS SQL DATA +BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + + + + + + RETURN ( + SELECT e.version + FROM entity_version AS e + WHERE e.entity_id = InternalEntityID + ORDER BY e._iversion DESC + LIMIT 1 OFFSET HeadOffset + ); +END ;; +DELIMITER ; +/*!50003 SET sql_mode = @saved_sql_mode */ ; +/*!50003 SET character_set_client = @saved_cs_client */ ; +/*!50003 SET character_set_results = @saved_cs_results */ ; +/*!50003 SET collation_connection = @saved_col_connection */ ; +/*!50003 SET @saved_sql_mode = @@sql_mode */ ; +/*!50003 SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ; +/*!50003 D */ diff --git a/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5476af3268360476f2c1ef741cb25007e29ce5d --- /dev/null +++ b/dump_updates/test/test_data/2024-10-02.dump_fix_mariadb_10_6.example1.sql @@ -0,0 +1,36 @@ +/* Just a short snippt with the problem */ + + +/*!50003 SET @saved_col_connection = @@collation_connection */ ; +/*!50003 SET character_set_client = utf8 */ ; +/*!50003 SET character_set_results = utf8 */ ; +/*!50003 SET collation_connection = utf8_general_ci */ ; +DELIMITER ;; +CREATE DEFINER=`root`@`%` FUNCTION `get_head_relative`(EntityID VARCHAR(255), + Offset INT UNSIGNED) RETURNS varbinary(255) + READS SQL DATA +BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + + + + + + RETURN ( + SELECT e.version + FROM entity_version AS e + WHERE e.entity_id = InternalEntityID + ORDER BY e._iversion DESC + LIMIT 1 OFFSET Offset + ); +END ;; +DELIMITER ; +/*!50003 SET sql_mode = @saved_sql_mode */ ; +/*!50003 SET character_set_client = @saved_cs_client */ ; +/*!50003 SET character_set_results = @saved_cs_results */ ; +/*!50003 SET collation_connection = @saved_col_connection */ ; +/*!50003 SET @saved_sql_mode = @@sql_mode */ ; +/*!50003 SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ; +/*!50003 D */ diff --git a/libs/mytap-1.0.zip b/libs/mytap-1.0.zip index 9e04965cd40320bde2e598c585119ffa7f6b1eab..75341f8c8f8725fca94e2a34bc3dd58e8fa8e641 100644 Binary files a/libs/mytap-1.0.zip and b/libs/mytap-1.0.zip differ diff --git a/patches/applyPatches.sh b/patches/applyPatches.sh index ffaa06a782c3dfeababff092158bc5990f11220e..306e6d976aae09410c8c24db791448842a740162 100755 --- a/patches/applyPatches.sh +++ b/patches/applyPatches.sh @@ -47,4 +47,5 @@ do done cd ../ + $UTILSPATH/update_sql_procedures.sh diff --git a/patches/patch20170316-2.0.27/patch.sh b/patches/patch20170316-2.0.27/patch.sh index 504b5dcca20004806cf49ec16b574f3128af8d5b..fb46b77407e819d7f0984752bfa4047858960ece 100755 --- a/patches/patch20170316-2.0.27/patch.sh +++ b/patches/patch20170316-2.0.27/patch.sh @@ -35,7 +35,12 @@ fi check_version $OLD_VERSION -mysql_execute 'DELETE FROM `entities` WHERE id=6; ALTER TABLE `entities` MODIFY COLUMN `role` ENUM("RECORDTYPE","RECORD","FILE","DOMAIN","PROPERTY","DATATYPE","ROLE","QUERYTEMPLATE") NOT NULL; INSERT INTO entities (id, name, description, role, acl) VALUES (8,"QUERYTEMPLATE","The QueryTemplate role.","ROLE",0); UPDATE `entities` SET role="ROLE" WHERE id<100 and name=role; CREATE TABLE `query_template_def` (id INT UNSIGNED PRIMARY KEY, definition MEDIUMTEXT NOT NULL, CONSTRAINT `query_template_def_ibfk_1` FOREIGN KEY (`id`) REFERENCES `entities` (`id`));' +mysql_execute ' +DELETE FROM `entities` WHERE id=6; +ALTER TABLE `entities` MODIFY COLUMN `role` ENUM("RECORDTYPE","RECORD","FILE","DOMAIN","PROPERTY","DATATYPE","ROLE","QUERYTEMPLATE") NOT NULL; +INSERT INTO entities (id, name, description, role, acl) VALUES (8,"QUERYTEMPLATE","The QueryTemplate role.","ROLE",0); +UPDATE `entities` SET role="ROLE" WHERE id<100 and name=role; +CREATE TABLE `query_template_def` (id INT UNSIGNED PRIMARY KEY, definition MEDIUMTEXT NOT NULL, CONSTRAINT `query_template_def_ibfk_1` FOREIGN KEY (`id`) REFERENCES `entities` (`id`));' update_version $NEW_VERSION diff --git a/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql b/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql new file mode 100644 index 0000000000000000000000000000000000000000..41297c918f0213017ebba22e1871ece2f515f782 --- /dev/null +++ b/patches/patch20221122-6.0-SNAPSHOT/create_entity_ids_table.sql @@ -0,0 +1,63 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2022-2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2022-2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +-- a little bit of house keeping +DROP PROCEDURE IF EXISTS retrieveSubEntity; +DROP PROCEDURE IF EXISTS retrieveDatatype; +DROP PROCEDURE IF EXISTS retrieveGroup; +DROP PROCEDURE IF EXISTS getInfo; +DROP PROCEDURE IF EXISTS getRole; +DROP PROCEDURE IF EXISTS setPassword; +DROP PROCEDURE IF EXISTS initAutoIncrement; +DELETE FROM name_data WHERE entity_id=50; +DELETE FROM entities WHERE id=50; +DELETE FROM entities WHERE id=99; + +-- this simply is the more appropriate name +ALTER TABLE entities MODIFY COLUMN + `role` enum('RECORDTYPE','RECORD','FILE','DOMAIN','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', '_REPLACEMENT') COLLATE utf8_unicode_ci NOT NULL; +ALTER TABLE archive_entities MODIFY COLUMN + `role` enum('RECORDTYPE','RECORD','FILE','DOMAIN','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE', '_REPLACEMENT') COLLATE utf8_unicode_ci NOT NULL; +UPDATE entities SET role = "_REPLACEMENT" WHERE role="DOMAIN"; +UPDATE archive_entities SET role = "_REPLACEMENT" WHERE role="DOMAIN"; +ALTER TABLE entities MODIFY COLUMN + `role` enum('RECORDTYPE','RECORD','FILE','_REPLACEMENT','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE') COLLATE utf8_unicode_ci NOT NULL; +ALTER TABLE archive_entities MODIFY COLUMN + `role` enum('RECORDTYPE','RECORD','FILE','_REPLACEMENT','PROPERTY','DATATYPE','ROLE','QUERYTEMPLATE') COLLATE utf8_unicode_ci NOT NULL; + + + +-- new entity_ids table +DROP TABLE IF EXISTS `entity_ids`; +CREATE TABLE `entity_ids` ( + `id` VARCHAR(255) NOT NULL, + `internal_id` int(10) unsigned NOT NULL COMMENT 'Internal ID of an entity. This id is used internally in the *_data tables and elsewhere. This ID is never exposed via the CaosDB API.', + PRIMARY KEY `entity_ids_pk` (`id`), + CONSTRAINT `entity_ids_internal_id` FOREIGN KEY (`internal_id`) REFERENCES `entities` (`id`) +) ENGINE=InnoDB COLLATE utf8mb4_bin; + +-- fill all existing entities into the new entity_ids table. +INSERT INTO entity_ids (id, internal_id) SELECT id, id FROM entities WHERE id>0 AND role!="_REPLACEMENT"; + +ALTER TABLE transaction_log MODIFY COLUMN `entity_id` VARCHAR(255) COLLATE utf8mb4_bin NOT NULL; + +ALTER TABLE user_info DROP FOREIGN KEY `subjects_ibfk_1`; +ALTER TABle user_info MODIFY COLUMN `entity` VARCHAR(255) COLLATE utf8mb4_bin DEFAULT NULL; +ALTER TABLE user_info ADD CONSTRAINT `subjects_ibfk_2` FOREIGN KEY (`entity`) REFERENCES `entity_ids` (`id`); diff --git a/patches/patch20221122-6.0-SNAPSHOT/patch.sh b/patches/patch20221122-6.0-SNAPSHOT/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..9833f5ad953799afc33133014ec4db2ac6320beb --- /dev/null +++ b/patches/patch20221122-6.0-SNAPSHOT/patch.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v5.0.0 +# Drop the 'rules' table. + +NEW_VERSION="v6.0.0-SNAPSHOT-EXTIDS" +OLD_VERSION="v5.0.0" + +DROP_TABLE_PASSWORDS='DROP TABLE IF EXISTS passwords;' + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +mysql_execute "$DROP_TABLE_PASSWORDS" +mysql_execute_file $PATCH_DIR/create_entity_ids_table.sql + +update_version $NEW_VERSION + + +success + diff --git a/patches/patch20231018-6.1.0/patch.sh b/patches/patch20231018-6.1.0/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..e91f487216ce254fb3b1a78a911f38fcc263d8c7 --- /dev/null +++ b/patches/patch20231018-6.1.0/patch.sh @@ -0,0 +1,42 @@ +#!/bin/bash +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v6.1.0 +# No migration of the schema, updating procedures only + +NEW_VERSION="v6.1.0" +OLD_VERSION="v6.0.0-SNAPSHOT-EXTIDS" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +# Drop insertUser procedure +mysql_execute "DROP PROCEDURE IF EXISTS insertUser;" + +update_version $NEW_VERSION + +success + diff --git a/patches/patch20231025-7.0.0/patch.sh b/patches/patch20231025-7.0.0/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..06a7dc85c75897b7c47e6094f634b5421f92c794 --- /dev/null +++ b/patches/patch20231025-7.0.0/patch.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v7.0.0 +# No migration of the schema, updating procedures only + +NEW_VERSION="v7.0.0" +OLD_VERSION="v6.1.0" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +update_version $NEW_VERSION + +success + diff --git a/patches/patch20231101-7.0.1/patch.sh b/patches/patch20231101-7.0.1/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..869a014317b3a51246562052560adcecb841eebe --- /dev/null +++ b/patches/patch20231101-7.0.1/patch.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v7.0.1 +# Removing remnant tables. This patch version also adds new sanity checks +# during installation/upgrade + +NEW_VERSION="v7.0.1" +OLD_VERSION="v7.0.0" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +mysql_execute "DROP TABLE IF EXISTS groups"; +mysql_execute "DROP TABLE IF EXISTS passwords"; +mysql_execute "DROP TABLE IF EXISTS logging"; +mysql_execute "DROP TABLE IF EXISTS isa"; + +update_version $NEW_VERSION + +success diff --git a/patches/patch20231211-7.0.2/patch.sh b/patches/patch20231211-7.0.2/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..422fc00b9083808446d74776b446c072bdfd73bc --- /dev/null +++ b/patches/patch20231211-7.0.2/patch.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v7.0.2 +# Patch the broken data_type table (fix id for file references as per +# https://gitlab.com/linkahead/linkahead-server/-/issues/246) + +NEW_VERSION="v7.0.2" +OLD_VERSION="v7.0.1" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +mysql_execute "UPDATE data_type SET datatype=17 WHERE datatype=3" + +update_version $NEW_VERSION + +success diff --git a/patches/patch20241024-8.0.0/patch.sh b/patches/patch20241024-8.0.0/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..2573c95864518363088af121a705d87f786b07ca --- /dev/null +++ b/patches/patch20241024-8.0.0/patch.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# This file is a part of the LinkAhead Project. +# +# Copyright (C) 2024 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2024 Timm Fitschen <t.fitschen@indiscale.com> +# Copyright (C) 2024 Florian Spreckelsen <f.spreckelsen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v8.0.0 +# +# The patch is empty because the change has to be applied manually +# from ../../dump_updates/2024-10-02.dump_fix_mariadb_10_6.sh if necessary. + +NEW_VERSION="v8.0.0" +OLD_VERSION="v7.0.2" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +update_version $NEW_VERSION + +success diff --git a/patches/patch20250130-8.1.0/patch.sh b/patches/patch20250130-8.1.0/patch.sh new file mode 100755 index 0000000000000000000000000000000000000000..5a092150f217c44d100a15735523ef74ea613a8b --- /dev/null +++ b/patches/patch20250130-8.1.0/patch.sh @@ -0,0 +1,99 @@ +#!/bin/bash +# +# This file is a part of the Linkahead Project. +# +# Copyright (C) 2025 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2025 Daniel Hornung <d.hornung@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# + +# Update mysql schema to version v8.1.0 +# +# Set the collation so that accents on characters become relevant. + +OLD_VERSION="v8.0.0" +NEW_VERSION="v8.1.0" + +if [ -z "$UTILSPATH" ]; then + UTILSPATH="../utils" +fi + +. $UTILSPATH/patch_header.sh $* + +check_version $OLD_VERSION + +# Update charsets and collations. + +# Change database default. +mysql_execute "ALTER DATABASE \`$DATABASE_NAME\` COLLATE = 'uca1400_as_ci';" + +# Some columns should be changed manually to prevent text length changes. +mysql_execute "ALTER TABLE desc_overrides MODIFY description TEXT CHARACTER SET utf8mb4;" +mysql_execute "ALTER TABLE entities MODIFY description TEXT CHARACTER SET utf8mb4;" +mysql_execute "ALTER TABLE permissions MODIFY permissions MEDIUMTEXT CHARACTER SET utf8mb4 NOT NULL;" +mysql_execute "ALTER TABLE query_template_def MODIFY definition MEDIUMTEXT CHARACTER SET utf8mb4 NOT NULL;" +mysql_execute "ALTER TABLE roles MODIFY description MEDIUMTEXT CHARACTER SET utf8mb4;" +mysql_execute "ALTER TABLE text_data MODIFY value TEXT CHARACTER SET utf8mb4 NOT NULL;" + +# Remove some constraints first. +mysql_execute 'ALTER TABLE user_info DROP FOREIGN KEY `subjects_ibfk_2`;' + +# Get all tables, drop first line, take first column +tables=$(mysql_execute "SHOW TABLE status where Collation='utf8mb3_unicode_ci';" -B | tail +2 | awk '{print $1}') +for table in $tables; do + mysql_execute "ALTER TABLE $table CONVERT TO CHARACTER SET utf8mb4 COLLATE uca1400_as_ci;" +done + +# Add constraints again. +mysql_execute 'ALTER TABLE user_info MODIFY COLUMN `entity` VARCHAR(255) COLLATE utf8mb4_bin DEFAULT NULL;' +mysql_execute 'ALTER TABLE user_info ADD CONSTRAINT `subjects_ibfk_2` FOREIGN KEY (`entity`) REFERENCES `entity_ids` (`id`);' + +# Set custom collations for columns +mysql_execute "ALTER TABLE transaction_log MODIFY entity_id VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL;" + + +### Finished ### + +update_version $NEW_VERSION + +success + + +##### Useful commands ##### + +# cd git/caosdb-mysqlbackend/ +# UTILSPATH=utils +# . utils/patch_header.sh + + +# show table status where Collation='utf8mb3_unicode_ci'; + +# name_data +# text_data + +# show table status like 'name_data'; +# select * from name_data where value like 'Yield%'; +# update name_data SET value='Yield-stréss' where entity_id=354; +# update name_data SET value='Yield-strés😋s' where entity_id=354; +# select * from name_data where value='Yield-stress'; + +# # Unicode 14.0.0 +# ALTER TABLE name_data CONVERT TO CHARACTER SET utf8mb4 COLLATE uca1400_as_ci; + +# FULL_COLLATION_NAME: utf8mb4_uca1400_as_ci; +# COLLATION_NAME: uca1400_as_ci; + +# mariadb -h sqldb -u caosdb -prandom1234 --default-character-set=utf8mb4 caosdb + diff --git a/procedures/deleteEntity.sql b/procedures/deleteEntity.sql index 7a195399b6c71ae68b26e2f74c53ab871ae05b0e..986a7908cb5ceb06c986c46cb7deac1b880e8f69 100644 --- a/procedures/deleteEntity.sql +++ b/procedures/deleteEntity.sql @@ -1,10 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -18,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ /* Delete a (sparse) Entity from the database. @@ -31,37 +29,43 @@ have been deleted before. This can be done for example with the Parameters ========== -EntityID : UNSIGNED -The ID of the Entity. +EntityID : VARCHAR(255) + The ID of the Entity. */ DROP PROCEDURE IF EXISTS db_5_0.deleteEntity; delimiter // -CREATE PROCEDURE db_5_0.deleteEntity(in EntityID INT UNSIGNED) +CREATE PROCEDURE db_5_0.deleteEntity(in EntityID VARCHAR(255)) BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; -- detele file properties - DELETE FROM files where file_id=EntityID; + DELETE FROM files where file_id=InternalEntityID; -- delete datatype stuff DELETE FROM data_type WHERE ( domain_id = 0 AND entity_id = 0 - AND property_id = EntityID ) - OR datatype = EntityID; + AND property_id = InternalEntityID ) + OR datatype = InternalEntityID; DELETE FROM collection_type WHERE domain_id = 0 AND entity_id = 0 - AND property_id = EntityID; + AND property_id = InternalEntityID; -- delete primary name (in case this is called without a prior call to deleteEntityProperties) DELETE FROM name_data WHERE domain_id = 0 - AND entity_id = EntityID + AND entity_id = InternalEntityID AND property_id = 20; - DELETE FROM entities where id=EntityID; + DELETE FROM entity_ids + WHERE internal_id = InternalEntityID; + + DELETE FROM entities where id=InternalEntityID; -- clean up unused acl DELETE FROM entity_acl diff --git a/procedures/deleteEntityProperties.sql b/procedures/deleteEntityProperties.sql index 916ddcba2751b9251ff2ddc387201e0ad9eebc3b..9216d9436c3b139ea68199940a5259512aa16133 100644 --- a/procedures/deleteEntityProperties.sql +++ b/procedures/deleteEntityProperties.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,23 +18,34 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.deleteEntityProperties; delimiter // -CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID INT UNSIGNED) +/* + * Delete all properties of an entity (i.e. remove them from the *_data tables + * and the isa_cache table). + * + * Parameters + * ========== + * + * EntityID : VARCHAR(255) + * The entity's id. + */ +CREATE PROCEDURE db_5_0.deleteEntityProperties(in EntityID VARCHAR(255)) BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; - CALL deleteIsa(EntityID); + CALL deleteIsa(InternalEntityID); IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN SELECT max(e._iversion) INTO IVersion -- What's the latest version? FROM entity_version AS e - WHERE e.entity_id = EntityID; + WHERE e.entity_id = InternalEntityID; -- Copy the rows from *_data to archive_*_data --------------------- INSERT INTO archive_reference_data (domain_id, entity_id, @@ -43,142 +53,142 @@ BEGIN SELECT domain_id, entity_id, property_id, value, value_iversion, status, pidx, IVersion AS _iversion FROM reference_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_null_data (domain_id, entity_id, property_id, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, status, pidx, IVersion AS _iversion FROM null_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_text_data (domain_id, entity_id, property_id, value, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion FROM text_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_name_data (domain_id, entity_id, property_id, value, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion FROM name_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_enum_data (domain_id, entity_id, property_id, value, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion FROM enum_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_integer_data (domain_id, entity_id, property_id, value, status, pidx, _iversion, unit_sig) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion, unit_sig FROM integer_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_double_data (domain_id, entity_id, property_id, value, status, pidx, _iversion, unit_sig) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion, unit_sig FROM double_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_datetime_data (domain_id, entity_id, property_id, value, value_ns, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, value, value_ns, status, pidx, IVersion AS _iversion FROM datetime_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_date_data (domain_id, entity_id, property_id, value, status, pidx, _iversion) SELECT domain_id, entity_id, property_id, value, status, pidx, IVersion AS _iversion FROM date_data - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_name_overrides (domain_id, entity_id, property_id, name, _iversion) SELECT domain_id, entity_id, property_id, name, IVersion AS _iversion FROM name_overrides - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_desc_overrides (domain_id, entity_id, property_id, description, _iversion) SELECT domain_id, entity_id, property_id, description, IVersion AS _iversion FROM desc_overrides - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_data_type (domain_id, entity_id, property_id, datatype, _iversion) SELECT domain_id, entity_id, property_id, datatype, IVersion AS _iversion FROM data_type - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_collection_type (domain_id, entity_id, property_id, collection, _iversion) SELECT domain_id, entity_id, property_id, collection, IVersion AS _iversion FROM collection_type - WHERE (domain_id = 0 AND entity_id = EntityID) - OR domain_id = EntityID; + WHERE (domain_id = 0 AND entity_id = InternalEntityID) + OR domain_id = InternalEntityID; INSERT INTO archive_query_template_def (id, definition, _iversion) SELECT id, definition, IVersion AS _iversion FROM query_template_def - WHERE id = EntityID; + WHERE id = InternalEntityID; END IF; DELETE FROM reference_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM null_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM text_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM name_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM enum_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM integer_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM double_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM datetime_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM date_data - where (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + where (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM name_overrides - WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM desc_overrides - WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM data_type - WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; DELETE FROM collection_type - WHERE (domain_id=0 AND entity_id=EntityID) OR domain_id=EntityID; + WHERE (domain_id=0 AND entity_id=InternalEntityID) OR domain_id=InternalEntityID; - DELETE FROM query_template_def WHERE id=EntityID; + DELETE FROM query_template_def WHERE id=InternalEntityID; END; // diff --git a/procedures/deleteIsaCache.sql b/procedures/deleteIsaCache.sql index cc9acd08059b2656ee934ba4a47f1c48dcdf5601..517912b73527ab7725d433c0cd91d7702b447e1c 100644 --- a/procedures/deleteIsaCache.sql +++ b/procedures/deleteIsaCache.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ SET GLOBAL log_bin_trust_function_creators = 1; @@ -38,30 +35,30 @@ parameter entity is a child or inside the rpath. Parameters ========== -EntityID : UNSIGNED -Child entity for which all parental relations should be deleted. +InternalEntityID : UNSIGNED + Child entity for which all parental relations should be deleted. */ -CREATE PROCEDURE db_5_0.deleteIsa(IN EntityID INT UNSIGNED) +CREATE PROCEDURE db_5_0.deleteIsa(IN InternalEntityID INT UNSIGNED) BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN SELECT max(_iversion) INTO IVersion FROM entity_version - WHERE entity_id = EntityID; + WHERE entity_id = InternalEntityID; -- move to archive_isa before deleting INSERT IGNORE INTO archive_isa (child, child_iversion, parent, direct) - SELECT e.child, IVersion AS child_iversion, e.parent, rpath = EntityID + SELECT e.child, IVersion AS child_iversion, e.parent, rpath = InternalEntityID FROM isa_cache AS e - WHERE e.child = EntityID; + WHERE e.child = InternalEntityID; END IF; DELETE FROM isa_cache - WHERE child = EntityID - OR rpath = EntityID - OR rpath LIKE concat('%>', EntityID) - OR rpath LIKE concat('%>', EntityID, '>%'); + WHERE child = InternalEntityID + OR rpath = InternalEntityID + OR rpath LIKE concat('%>', InternalEntityID) + OR rpath LIKE concat('%>', InternalEntityID, '>%'); END; // diff --git a/procedures/entityVersioning.sql b/procedures/entityVersioning.sql index 241474cb8dbf20f9caa9050aed9cbb600a8cef6d..a71c0c729f9fae5e710b8cfd8e37618e7615ff20 100644 --- a/procedures/entityVersioning.sql +++ b/procedures/entityVersioning.sql @@ -1,9 +1,9 @@ /* * This file is a part of the LinkAhead Project. * - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> - * + * Copyright (C) 2020-2024 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2024 Daniel Hornung <d.hornung@indiscale.com> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the @@ -27,23 +27,23 @@ DROP PROCEDURE IF EXISTS db_5_0.insert_single_child_version // * * Parameters * ---------- - * EntityID - * The ID of the versioned entity. - * Hash + * InternalEntityID : INT UNSIGNED + * The internal ID of the versioned entity. + * Hash : VARBINARY(255) * A hash of the entity. This is currently not implemented properly and only * there for future use. - * Version + * Version : VARBINARY(255) * The new version ID of the entity, must be produced by the caller. Must be unique for each * EntityID. - * Parent + * Parent : VARBINARY(255) * The version ID of the primary parent (i.e. predecessor). May be NULL; but if given, it must * exist. - * Transaction + * Transaction : VARBINARY(255) * The transaction ID which created this entity version (by inserting * or updating an entity). */ CREATE PROCEDURE db_5_0.insert_single_child_version( - in EntityID INT UNSIGNED, + in InternalEntityID INT UNSIGNED, in Hash VARBINARY(255), in Version VARBINARY(255), in Parent VARBINARY(255), @@ -57,12 +57,12 @@ BEGIN IF Parent IS NOT NULL THEN SELECT e._iversion INTO newipparent FROM entity_version AS e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e.version = Parent; IF newipparent IS NULL THEN -- throw error; SELECT concat("This parent does not exists: ", Parent) - FROM nonexisting; + FROM parent_version_does_not_exist; END IF; END IF; @@ -70,7 +70,7 @@ BEGIN -- generate _iversion SELECT max(e._iversion)+1 INTO newiversion FROM entity_version AS e - WHERE e.entity_id=EntityID; + WHERE e.entity_id=InternalEntityID; IF newiversion IS NULL THEN SET newiversion = 1; END IF; @@ -78,7 +78,7 @@ BEGIN INSERT INTO entity_version (entity_id, hash, version, _iversion, _ipparent, srid) VALUES - (EntityID, Hash, Version, newiversion, newipparent, Transaction); + (InternalEntityID, Hash, Version, newiversion, newipparent, Transaction); @@ -87,22 +87,28 @@ END; DROP PROCEDURE IF EXISTS db_5_0.delete_all_entity_versions // +/* THIS PROCEDURE HAS NEVER BEEN USED (outside of the tests). Reactivate when + * versioning's FORGET is being implemented. */ /** * Remove all records in the entity_version table for the given entity. * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The id of the versioned entity. */ -CREATE PROCEDURE db_5_0.delete_all_entity_versions( - in EntityID INT UNSIGNED) +/* CREATE PROCEDURE db_5_0.delete_all_entity_versions( + in EntityID VARCHAR(255)) BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; - DELETE FROM entity_version WHERE entity_id = EntityID; + DELETE FROM entity_version WHERE entity_id = InternalEntityID; END; // +*/ DROP FUNCTION IF EXISTS db_5_0.get_iversion // @@ -111,9 +117,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion // * * Parameters * ---------- - * EntityID - * The entity's id. - * Version + * InternalEntityID : INT UNSIGNED + * The entity's internal id. + * Version : VARBINARY(255) * The (official, externally used) version id. * * Returns @@ -121,7 +127,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_iversion // * The internal version id. */ CREATE FUNCTION db_5_0.get_iversion( - EntityID INT UNSIGNED, + InternalEntityID INT UNSIGNED, Version VARBINARY(255)) RETURNS INT UNSIGNED READS SQL DATA @@ -129,7 +135,7 @@ BEGIN RETURN ( SELECT e._iversion FROM entity_version AS e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e.version = Version ); END; @@ -143,9 +149,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity id. - * Version + * Version : VARBINARY(255) * The version id. * * Returns @@ -153,17 +159,21 @@ DROP FUNCTION IF EXISTS db_5_0.get_primary_parent_version // * The id of the given version's primary parent version. */ CREATE FUNCTION db_5_0.get_primary_parent_version( - EntityID INT UNSIGNED, + EntityID VARCHAR(255), Version VARBINARY(255)) RETURNS VARBINARY(255) READS SQL DATA BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + RETURN ( SELECT p.version FROM entity_version AS e INNER JOIN entity_version AS p ON (e._ipparent = p._iversion AND e.entity_id = p.entity_id) - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e.version = Version ); END; @@ -177,9 +187,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity id. - * Version + * Version : VARBINARY(255) * The version id. * * Returns @@ -188,16 +198,20 @@ DROP FUNCTION IF EXISTS db_5_0.get_version_timestamp // * Note that the dot `.` here is not necessarily a decimal separator. */ CREATE FUNCTION db_5_0.get_version_timestamp( - EntityID INT UNSIGNED, + EntityID VARCHAR(255), Version VARBINARY(255)) RETURNS VARCHAR(255) READS SQL DATA BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + RETURN ( SELECT concat(t.seconds, '.', t.nanos) FROM entity_version AS e INNER JOIN transactions AS t ON ( e.srid = t.srid ) - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e.version = Version ); END; @@ -210,7 +224,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity id. * * Returns @@ -218,7 +232,7 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_version // * The version id of the HEAD. */ CREATE FUNCTION db_5_0.get_head_version( - EntityID INT UNSIGNED) + EntityID VARCHAR(255)) RETURNS VARBINARY(255) READS SQL DATA BEGIN @@ -233,15 +247,15 @@ DROP FUNCTION IF EXISTS db_5_0._get_head_iversion // * * Parameters * ---------- - * EntityID - * The entity id. + * InternalEntityID : INT UNSIGNED + * The entity's internal id. * * Returns * ------- * The _iversion of the HEAD. */ CREATE FUNCTION db_5_0._get_head_iversion( - EntityID INT UNSIGNED) + InternalEntityID INT UNSIGNED) RETURNS INT UNSIGNED READS SQL DATA BEGIN @@ -252,7 +266,7 @@ BEGIN RETURN ( SELECT e._iversion FROM entity_version AS e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID ORDER BY e._iversion DESC LIMIT 1 ); @@ -267,9 +281,9 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity id. - * Offset + * HeadOffset : INT UNSIGNED * Distance in the sequence of primary parents of the entity. E.g. `0` is the * HEAD itself. `1` is the primary parent of the HEAD. `2` is the primary * parent of the primary parent of the HEAD, and so on. @@ -279,11 +293,15 @@ DROP FUNCTION IF EXISTS db_5_0.get_head_relative // * The version id of the HEAD. */ CREATE FUNCTION db_5_0.get_head_relative( - EntityID INT UNSIGNED, - Offset INT UNSIGNED) + EntityID VARCHAR(255), + HeadOffset INT UNSIGNED) RETURNS VARBINARY(255) READS SQL DATA BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + -- This implementation assumes that the distance from the head equals the -- difference between the _iversion numbers. This will not be correct anymore -- as soon as branches may split and merge. Then, a walk over the primary @@ -291,9 +309,9 @@ BEGIN RETURN ( SELECT e.version FROM entity_version AS e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID ORDER BY e._iversion DESC - LIMIT 1 OFFSET Offset + LIMIT 1 OFFSET HeadOffset ); END; // @@ -304,24 +322,24 @@ DROP FUNCTION IF EXISTS db_5_0._get_version // * * Parameters * ---------- - * EntityID - * The entity id. + * InternalEntityID : INT UNSIGNED + * The entity's internal id. * IVersion * Internal version id (integer). * * Returns * ------- - * The version id. + * The (external) version id. */ CREATE FUNCTION db_5_0._get_version( - EntityID INT UNSIGNED, + InternalEntityID INT UNSIGNED, IVersion INT UNSIGNED) RETURNS VARBINARY(255) READS SQL DATA BEGIN RETURN ( SELECT version FROM entity_version - WHERE entity_id = EntityID + WHERE entity_id = InternalEntityID AND _iversion = IVersion ); END; @@ -335,7 +353,7 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity id. * * Selects @@ -344,8 +362,12 @@ DROP PROCEDURE IF EXISTS db_5_0.get_version_history // * child_realm). `child` and `parent` are version IDs. */ CREATE PROCEDURE db_5_0.get_version_history( - in EntityID INT UNSIGNED) + in EntityID VARCHAR(255)) BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + -- retrieve root(s) (initial versions) SELECT c.version AS child, NULL as parent, @@ -355,7 +377,7 @@ BEGIN t.realm AS child_realm FROM entity_version AS c INNER JOIN transactions as t ON ( c.srid = t.srid ) - WHERE c.entity_id = EntityID + WHERE c.entity_id = InternalEntityID AND c._ipparent is Null -- TODO This first SELECT statement is necessary because the second one @@ -375,7 +397,7 @@ BEGIN ON (c._ipparent = p._iversion AND c.entity_id = p.entity_id AND t.srid = c.srid) - WHERE p.entity_id = EntityID; + WHERE p.entity_id = InternalEntityID; END; // @@ -412,56 +434,6 @@ BEGIN END // - -DROP PROCEDURE IF EXISTS setFileProperties // -/** - * Insert/Update file properties. - * - * If ENTITY_VERSIONING is enabled the old file properties are moved to - * `archive_files`. - * - * Parameters - * ---------- - * EntityID - * The file's id. - * FilePath - * Path of the file in the internal file system. If NULL, an existing file - * entity is simply deleted. - * FileSize - * Size of the file in bytes. - * FileHash - * A Sha512 Hash of the file. - */ -CREATE PROCEDURE setFileProperties ( - in EntityID INT UNSIGNED, - in FilePath TEXT, - in FileSize BIGINT UNSIGNED, - in FileHash VARCHAR(255) -) -BEGIN - DECLARE IVersion INT UNSIGNED DEFAULT NULL; - IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN - SELECT max(e._iversion) INTO IVersion - FROM entity_version AS e - WHERE e.entity_id = EntityID; - - INSERT INTO archive_files (file_id, path, size, hash, - _iversion) - SELECT file_id, path, size, hash, IVersion AS _iversion - FROM files - WHERE file_id = EntityID; - END IF; - - DELETE FROM files WHERE file_id = EntityID; - - IF FilePath IS NOT NULL THEN - INSERT INTO files (file_id, path, size, hash) - VALUES (EntityID, FilePath, FileSize, unhex(FileHash)); - END IF; - -END // - - DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef // /** @@ -469,9 +441,9 @@ DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The QueryTemplate's id. - * Version + * Version : VARBINARY(255) * The QueryTemplate's version's id. * * Returns @@ -480,12 +452,16 @@ DROP PROCEDURE IF EXISTS retrieveQueryTemplateDef // * QueryTemplate. */ CREATE PROCEDURE retrieveQueryTemplateDef ( - in EntityID INT UNSIGNED, + in EntityID VARCHAR(255), in Version VARBINARY(255)) retrieveQueryTemplateDefBody: BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; DECLARE IsHead BOOLEAN DEFAULT TRUE; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN -- Are we at the head? @@ -494,11 +470,7 @@ retrieveQueryTemplateDefBody: BEGIN END IF; IF IsHead IS FALSE THEN - -- TODO Use get_iversion(EntityID, Version) instead? Or will that be much slower? - SELECT e._iversion INTO IVersion - FROM entity_version as e - WHERE e.entity_id = EntityID - AND e.version = Version; + SET IVersion = get_iversion(InternalEntityID, Version); IF IVersion IS NULL THEN -- RETURN EARLY - Version does not exist. @@ -507,7 +479,7 @@ retrieveQueryTemplateDefBody: BEGIN SELECT definition FROM archive_query_template_def - WHERE id = EntityID + WHERE id = InternalEntityID AND _iversion = IVersion; LEAVE retrieveQueryTemplateDefBody; @@ -516,7 +488,7 @@ retrieveQueryTemplateDefBody: BEGIN SELECT definition FROM query_template_def - WHERE id = EntityID; + WHERE id = InternalEntityID; END // diff --git a/procedures/getDependentEntities.sql b/procedures/getDependentEntities.sql index b99d6a6c1e80831c392a11a3b4212538afad5887..1eae0729db3af3b8c06cf4ea27bebf77a17679a7 100644 --- a/procedures/getDependentEntities.sql +++ b/procedures/getDependentEntities.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <www.indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -18,56 +19,76 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. * - * ** end header */ - DROP PROCEDURE IF EXISTS db_5_0.getDependentEntities; delimiter // -CREATE PROCEDURE db_5_0.getDependentEntities(in EntityID INT UNSIGNED) +/* + * Return all entities which either reference the given entity, use the given + * reference as data type, or are direct children of the given entity. + * + * This function used to make sure that no entity can be deleted which + * is still needed by others. + * + * Parameters + * ---------- + * EntityID : VARCHAR(255) + * The entity id. + * + * ResultSet + * --------- + * EntityID : VARCHAR(255) + * + */ +CREATE PROCEDURE db_5_0.getDependentEntities(in EntityID VARCHAR(255)) BEGIN -DROP TEMPORARY TABLE IF EXISTS refering; -CREATE TEMPORARY TABLE refering ( -id INT UNSIGNED UNIQUE -); + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + DROP TEMPORARY TABLE IF EXISTS referring; + CREATE TEMPORARY TABLE referring ( + id INT UNSIGNED UNIQUE + ); + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM reference_data WHERE (value=EntityID OR property_id=EntityID) AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM reference_data WHERE (value=EntityID OR property_id=EntityID) AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM reference_data WHERE (value=InternalEntityID OR property_id=InternalEntityID) AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM reference_data WHERE (value=InternalEntityID OR property_id=InternalEntityID) AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM text_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM text_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM text_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM text_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM enum_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM enum_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM enum_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM enum_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM name_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM name_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM name_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM name_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM integer_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM integer_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM integer_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM integer_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM double_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM double_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM double_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM double_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM datetime_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM datetime_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM datetime_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM datetime_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM date_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM date_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM date_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM date_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id FROM null_data WHERE property_id=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id FROM null_data WHERE property_id=EntityID AND domain_id!=EntityID AND entity_id!=EntityID AND domain_id!=0; + INSERT IGNORE INTO referring (id) SELECT entity_id FROM null_data WHERE property_id=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id FROM null_data WHERE property_id=InternalEntityID AND domain_id!=InternalEntityID AND entity_id!=InternalEntityID AND domain_id!=0; -INSERT IGNORE INTO refering (id) SELECT entity_id from data_type WHERE datatype=EntityID AND domain_id=0 AND entity_id!=EntityID; -INSERT IGNORE INTO refering (id) SELECT domain_id from data_type WHERE datatype=EntityID; + INSERT IGNORE INTO referring (id) SELECT entity_id from data_type WHERE datatype=InternalEntityID AND domain_id=0 AND entity_id!=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT domain_id from data_type WHERE datatype=InternalEntityID; + INSERT IGNORE INTO referring (id) SELECT child FROM isa_cache WHERE parent = InternalEntityID AND rpath = child; -Select id from refering WHERE id!=0 and id!=EntityID; + SELECT e.id FROM referring AS r LEFT JOIN entity_ids AS e ON r.id = e.internal_id WHERE r.id!=0 AND e.internal_id!=InternalEntityID; -DROP TEMPORARY TABLE refering; + DROP TEMPORARY TABLE referring; END; // diff --git a/procedures/getFileIdByPath.sql b/procedures/getFileIdByPath.sql index 81326400f8ca54b8474f4b0ae20283a5f3a82ceb..d73a20698d67c7c94b5057cba305a4922ff64495 100644 --- a/procedures/getFileIdByPath.sql +++ b/procedures/getFileIdByPath.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,16 +18,27 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ Drop Procedure if exists db_5_0.getFileIdByPath; Delimiter // -Create Procedure db_5_0.getFileIdByPath (in FilePath VARCHAR(255)) -BEGIN -Select file_id as FileID from files where path=FilePath LIMIT 1; +/* + * Return a file's id for a given path or nothing if the path is unknown. + * + * Parameters + * ---------- + * FilePath : TEXT + * The file's path. + * + * Returns + * ------- + * EntityID : VARCHAR(255) + */ +Create Procedure db_5_0.getFileIdByPath (in FilePath TEXT) +BEGIN + + SELECT e.id AS FileID FROM files AS f LEFT JOIN entity_ids ON e.internal_in = f.file_id WHERE f.path=FilePath LIMIT 1; END; // diff --git a/procedures/getIdByName.sql b/procedures/getIdByName.sql new file mode 100644 index 0000000000000000000000000000000000000000..781594eff9fba3b3582e2e2a4a828f3c7a98a10c --- /dev/null +++ b/procedures/getIdByName.sql @@ -0,0 +1,63 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +DROP PROCEDURE IF EXISTS db_5_0.getIdByName; +DELIMITER // + +/* + * Return the Entity id(s) for a given name. Optionally, filter by role and set + * a limit. + * + * Parameters + * ---------- + * Name : VARCHAR(255) + * The entity's name. + * Role : VARCHAR(255) + * E.g. RecordType, Record, Property,... + * Lmt : INT UNSIGNED + * Limit the number of returned entity ids. + * + * Returns + * ------- + * EntityID : VARCHAR(255) + */ +CREATE PROCEDURE db_5_0.getIdByName(in Name VARCHAR(255), in Role VARCHAR(255), in Lmt INT UNSIGNED) +BEGIN + + SET @stmtStr = "SELECT e.id AS id FROM name_data AS n JOIN entity_ids AS e ON (n.domain_id=0 AND n.property_id=20 AND e.internal_id = n.entity_id) JOIN entities AS i ON (i.id = e.internal_id) WHERE n.value = ?"; + + IF Role IS NULL THEN + SET @stmtStr = CONCAT(@stmtStr, " AND i.role!='ROLE'"); + ELSE + SET @stmtStr = CONCAT(@stmtStr, " AND i.role='", Role, "'"); + END IF; + + IF Lmt IS NOT NULL THEN + SET @stmtStr = CONCAT(@stmtStr, " LIMIT ", Lmt); + END IF; + + SET @vName = Name; + PREPARE stmt FROM @stmtStr; + EXECUTE stmt USING @vName; + DEALLOCATE PREPARE stmt; + +END; +// +DELIMITER ; diff --git a/procedures/getInfo.sql b/procedures/getInfo.sql deleted file mode 100644 index 649127105aca34c56ae8fb7eac1433c3f0898714..0000000000000000000000000000000000000000 --- a/procedures/getInfo.sql +++ /dev/null @@ -1,24 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -#-- old procedure. -Drop Procedure if exists db_5_0.getInfo; diff --git a/procedures/getRole.sql b/procedures/getRole.sql deleted file mode 100644 index ab1955d9416400d8d4ceeafc030bba29cd4ba2db..0000000000000000000000000000000000000000 --- a/procedures/getRole.sql +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - - - - - - - -DROP PROCEDURE IF EXISTS db_5_0.getRole; -delimiter // -CREATE PROCEDURE db_5_0.getRole(in RoleName VARCHAR(255)) -BEGIN - -Select e.id INTO @RoleID from entities e where e.name=RoleName AND e.role=RoleName LIMIT 1; - -call retrieveEntity(@RoleID); - - - - -END; -// -delimiter ; diff --git a/procedures/initAutoIncrement.sql b/procedures/initAutoIncrement.sql deleted file mode 100644 index d1350175acd198cfd645c1a54ec478f5409d1832..0000000000000000000000000000000000000000 --- a/procedures/initAutoIncrement.sql +++ /dev/null @@ -1,40 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - -DROP PROCEDURE IF EXISTS db_5_0.initAutoIncrement; -delimiter // - -CREATE PROCEDURE db_5_0.initAutoIncrement() -BEGIN - - SELECT @max := MAX(entity_id)+ 1 FROM transaction_log; - IF @max IS NOT NULL THEN - SET @stmtStr = CONCAT('ALTER TABLE entities AUTO_INCREMENT=',@max); - PREPARE stmt FROM @stmtStr; - EXECUTE stmt; - DEALLOCATE PREPARE stmt; - END IF; - -END; -// -delimiter ; diff --git a/procedures/insertEntity.sql b/procedures/insertEntity.sql index e05fdb4e008213b619ac47e4125fc3cc9844a47a..6b47b505f296d3dc662852bb609552643efc0dc1 100644 --- a/procedures/insertEntity.sql +++ b/procedures/insertEntity.sql @@ -1,11 +1,10 @@ /* * ** header v3.0 - * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ @@ -31,12 +28,14 @@ delimiter // Parameters ========== +EntityID : VARCHAR(255) + The entity id. EntityName : VARCHAR(255) EntityDesc : TEXT EntityRole : VARCHAR(255) -Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'DOMAIN', 'PROPERTY', +Currently one of 'RECORDTYPE', 'RECORD', 'FILE', 'PROPERTY', 'DATATYPE', 'ROLE', 'QUERYTEMPLATE' ACL : VARBINARY(65525) @@ -44,17 +43,17 @@ ACL : VARBINARY(65525) Select ====== -A tuple (EntityID, Version) +(Version) */ -CREATE PROCEDURE db_5_0.insertEntity(in EntityName VARCHAR(255), in EntityDesc TEXT, in EntityRole VARCHAR(255), in ACL VARBINARY(65525)) +CREATE PROCEDURE db_5_0.insertEntity(in EntityID VARCHAR(255), in EntityName VARCHAR(255), in EntityDesc TEXT, in EntityRole VARCHAR(255), in ACL VARBINARY(65525)) BEGIN - DECLARE NewEntityID INT UNSIGNED DEFAULT NULL; DECLARE NewACLID INT UNSIGNED DEFAULT NULL; DECLARE Hash VARBINARY(255) DEFAULT NULL; DECLARE Version VARBINARY(255) DEFAULT NULL; DECLARE Transaction VARBINARY(255) DEFAULT NULL; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; - -- insert the acl. the new acl id is being written (c-style) into the + -- insert the acl. The new acl id is written (c-style) into the -- variable NewACLID. call entityACL(NewACLID, ACL); @@ -63,13 +62,15 @@ BEGIN VALUES (EntityDesc, EntityRole, NewACLID); -- ... and return the generated id - SET NewEntityID = LAST_INSERT_ID(); + SET InternalEntityID = LAST_INSERT_ID(); + + INSERT INTO entity_ids (internal_id, id) VALUES (InternalEntityID, EntityID); IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN -- TODO this is transaction-scoped variable. Is this a good idea? SET Transaction = @SRID; SET Version = SHA1(UUID()); - CALL insert_single_child_version(NewEntityID, Hash, Version, Null, Transaction); + CALL insert_single_child_version(InternalEntityID, Hash, Version, Null, Transaction); END IF; -- insert the name of the entity into name_data table @@ -77,10 +78,10 @@ BEGIN IF EntityName IS NOT NULL THEN INSERT INTO name_data (domain_id, entity_id, property_id, value, status, pidx) - VALUES (0, NewEntityID, 20, EntityName, "FIX", 0); + VALUES (0, InternalEntityID, 20, EntityName, "FIX", 0); END IF; - SELECT NewEntityID as EntityID, Version as Version; + SELECT Version as Version; END; // diff --git a/procedures/insertEntityDataType.sql b/procedures/insertEntityDataType.sql new file mode 100644 index 0000000000000000000000000000000000000000..bd75099ba5317d997ca7a6bc9b4ae00d5f0a04c7 --- /dev/null +++ b/procedures/insertEntityDataType.sql @@ -0,0 +1,71 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +DROP PROCEDURE IF EXISTS db_5_0.insertEntityDataType; +DELIMITER // + +/* + * Insert the (default) datatype of a property. + * + * Parameters + * ---------- + * PropertyID : VARCHAR(255) + * The property id. + * DataTypeID : VARCHAR(255) + * The data type id (not the name!) + */ +CREATE PROCEDURE db_5_0.insertEntityDataType(in PropertyID VARCHAR(255), in DataTypeID VARCHAR(255)) +BEGIN + DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id=PropertyID; + + INSERT INTO data_type (domain_id, entity_id, property_id, datatype) SELECT 0, 0, InternalPropertyID, ( SELECT internal_id FROM entity_ids WHERE id = DataTypeID); + + +END; +// +DELIMITER ; + + +DROP PROCEDURE IF EXISTS db_5_0.insertEntityCollection; +DELIMITER // + +/* + * Insert the (default) collection type of a property. + * + * Parameters + * ---------- + * PropertyID : VARCHAR(255) + * The property id. + * Collection : VARCHAR(255) + * The collection, e.g. "LIST" + */ +CREATE PROCEDURE db_5_0.insertEntityCollection(in PropertyID VARCHAR(255), in Collection VARCHAR(255)) +BEGIN + DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id=PropertyID; + + INSERT INTO collection_type (domain_id, entity_id, property_id, collection) SELECT 0, 0, InternalPropertyID, Collection; + +END; +// +DELIMITER ; diff --git a/procedures/insertEntityProperty.sql b/procedures/insertEntityProperty.sql index b2e926a1659f76e50242e40e2d318062564dea17..872ee1d47dea7fca09b60586efbd4189a5a6149a 100644 --- a/procedures/insertEntityProperty.sql +++ b/procedures/insertEntityProperty.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,112 +18,166 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.insertEntityProperty; delimiter // + + +/* + * Insert the property of an entity (level 1 and 2, only one *_data table entry at a time). + * + * Parameters + * ---------- + * DomainID : VARCHAR(255) + * The domain id (0 or the entity's id for level-2-data) + * EntityID : VARCHAR(255) + * The entity id (or the property's id for level-2-data) + * PropertyID : VARCHAR(255) + * The property id (or the sub-property's id for level-2-data) + * Datatable : VARCHAR(255) + * Name of the *_data table, e.g. 'double_data'. + * PropertyValue : TEXT + * The property's value + * PropertyUnitSig : BIGINT + * The unit signature. + * PropertyStatus : VARCHAR(255) + * E.g. OBLIGATORY, FIX,... + * NameOverride : VARCHAR(255) + * The overridden name + * DescOverride : TEXT + * The overridden description + * DatatypeOverride : VARCHAR(255) + * The overridden datatype + * Collection : VARCHAR(255) + * The overridden collection (only if DatatypeOverride is present). + * PropertyIndex : INT UNSIGNED + * The property's index (for ordering of properties and values). + */ CREATE PROCEDURE db_5_0.insertEntityProperty( - in DomainID INT UNSIGNED, - in EntityID INT UNSIGNED, - in PropertyID INT UNSIGNED, + in DomainID VARCHAR(255), + in EntityID VARCHAR(255), + in PropertyID VARCHAR(255), in Datatable VARCHAR(255), in PropertyValue TEXT, in PropertyUnitSig BIGINT, in PropertyStatus VARCHAR(255), in NameOverride VARCHAR(255), in DescOverride TEXT, - in DatatypeOverride INT UNSIGNED, + in DatatypeOverride VARCHAR(255), in Collection VARCHAR(255), in PropertyIndex INT UNSIGNED) BEGIN DECLARE ReferenceValueIVersion INT UNSIGNED DEFAULT NULL; DECLARE ReferenceValue INT UNSIGNED DEFAULT NULL; DECLARE AT_PRESENT INTEGER DEFAULT NULL; + DECLARE InternalDataTypeID INT UNSIGNED DEFAULT NULL; + DECLARE InternalPropertyID INT UNSIGNED DEFAULT NULL; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + DECLARE InternalDomainID INT UNSIGNED DEFAULT 0; + + SELECT internal_id INTO InternalDomainID FROM entity_ids WHERE id = DomainID; + -- When DomainID != 0 the EntityID could possibly be a 'replacement id' + -- which are internal ids by definition (and do not have external + -- equivalents). + IF LOCATE("$", EntityID) = 1 THEN + SET InternalEntityID=SUBSTRING(EntityID, 2); + ELSE + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + END IF; + IF LOCATE("$", PropertyID) = 1 THEN + SET InternalPropertyID=SUBSTRING(PropertyID, 2); + ELSE + SELECT internal_id INTO InternalPropertyID FROM entity_ids WHERE id = PropertyID; + END IF; CASE Datatable WHEN 'double_data' THEN INSERT INTO double_data (domain_id, entity_id, property_id, value, unit_sig, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex); WHEN 'integer_data' THEN INSERT INTO integer_data (domain_id, entity_id, property_id, value, unit_sig, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyUnitSig, PropertyStatus, PropertyIndex); WHEN 'datetime_data' THEN INSERT INTO datetime_data (domain_id, entity_id, property_id, value, value_ns, status, pidx) VALUES - (DomainID, EntityID, PropertyID, SUBSTRING_INDEX(PropertyValue, 'UTC', 1), IF(SUBSTRING_INDEX(PropertyValue, 'UTC', -1)='',NULL,SUBSTRING_INDEX(PropertyValue, 'UTC', -1)), PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, SUBSTRING_INDEX(PropertyValue, 'UTC', 1), IF(SUBSTRING_INDEX(PropertyValue, 'UTC', -1)='',NULL,SUBSTRING_INDEX(PropertyValue, 'UTC', -1)), PropertyStatus, PropertyIndex); WHEN 'reference_data' THEN -- special handling if versioning enabled and specific version of referenced entity is given. SET AT_PRESENT=LOCATE("@", PropertyValue); IF is_feature_config("ENTITY_VERSIONING", "ENABLED") AND AT_PRESENT > 0 THEN - SET ReferenceValue = SUBSTRING_INDEX(PropertyValue, '@', 1); + SELECT internal_id INTO ReferenceValue FROM entity_ids WHERE id = SUBSTRING_INDEX(PropertyValue, '@', 1); SET ReferenceValueIVersion = get_iversion(ReferenceValue, SUBSTRING_INDEX(PropertyValue, '@', -1)); - -- TODO raise error when @ present but iversion is null IF ReferenceValueIVersion IS NULL THEN + -- Raise error when @ present but iversion is null SELECT 0 from `ReferenceValueIVersion_WAS_NULL`; END IF; + ELSEIF LOCATE("$", PropertyValue) = 1 THEN + SET ReferenceValue = SUBSTRING(PropertyValue, 2); ELSE - SET ReferenceValue = PropertyValue; + SELECT internal_id INTO ReferenceValue FROM entity_ids WHERE id = PropertyValue; END IF; + INSERT INTO reference_data (domain_id, entity_id, property_id, value, value_iversion, status, pidx) VALUES - (DomainID, EntityID, PropertyID, ReferenceValue, + (InternalDomainID, InternalEntityID, InternalPropertyID, ReferenceValue, ReferenceValueIVersion, PropertyStatus, PropertyIndex); WHEN 'enum_data' THEN INSERT INTO enum_data (domain_id, entity_id, property_id, value, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex); WHEN 'date_data' THEN INSERT INTO date_data (domain_id, entity_id, property_id, value, status, pidx) VALUES - (DomainID, EntityID, PropertyID, SUBSTRING_INDEX(PropertyValue, '.', 1), PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, SUBSTRING_INDEX(PropertyValue, '.', 1), PropertyStatus, PropertyIndex); WHEN 'text_data' THEN INSERT INTO text_data (domain_id, entity_id, property_id, value, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex); WHEN 'null_data' THEN INSERT INTO null_data (domain_id, entity_id, property_id, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyStatus, PropertyIndex); WHEN 'name_data' THEN INSERT INTO name_data (domain_id, entity_id, property_id, value, status, pidx) VALUES - (DomainID, EntityID, PropertyID, PropertyValue, PropertyStatus, PropertyIndex); + (InternalDomainID, InternalEntityID, InternalPropertyID, PropertyValue, PropertyStatus, PropertyIndex); ELSE + -- raise error SELECT * FROM table_does_not_exist; END CASE; IF DatatypeOverride IS NOT NULL THEN - call overrideType(DomainID, EntityID, PropertyID, DatatypeOverride); + SELECT internal_id INTO InternalDataTypeID from entity_ids WHERE id = DatatypeOverride; + call overrideType(InternalDomainID, InternalEntityID, InternalPropertyID, InternalDataTypeID); IF Collection IS NOT NULL THEN - INSERT INTO collection_type (domain_id, entity_id, property_id, collection) VALUES (DomainID, EntityID, PropertyID, Collection); + INSERT INTO collection_type (domain_id, entity_id, property_id, collection) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Collection); END IF; END IF; IF NameOverride IS NOT NULL THEN - call overrideName(DomainID, EntityID, PropertyID, NameOverride); + call overrideName(InternalDomainID, InternalEntityID, InternalPropertyID, NameOverride); END IF; IF DescOverride IS NOT NULL THEN - call overrideDesc(DomainID, EntityID, PropertyID, DescOverride); + call overrideDesc(InternalDomainID, InternalEntityID, InternalPropertyID, DescOverride); END IF; END; diff --git a/procedures/insertIsaCache.sql b/procedures/insertIsaCache.sql index eaa83f104a273997f80f7276da548af3a812db50..d0273e39b88ce4c37ca2a9a2dcd32852403d199a 100644 --- a/procedures/insertIsaCache.sql +++ b/procedures/insertIsaCache.sql @@ -1,10 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -18,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.insertIsa; DELIMITER // @@ -32,16 +30,22 @@ DELIMITER // * * Parameters * ========== - * - * c : UNSIGNED - * The child entity - * - * p : UNSIGNED - * The parent entity + * + * ChildID : VARCHAR(255) + * The child entity. + * + * ParentID : VARCHAR(255) + * The parent entity. */ -CREATE PROCEDURE db_5_0.insertIsa(IN c INT UNSIGNED, IN p INT UNSIGNED) +CREATE PROCEDURE db_5_0.insertIsa(IN ChildID VARCHAR(255), IN ParentID VARCHAR(255)) insert_is_a_proc: BEGIN + DECLARE c INT UNSIGNED DEFAULT NULL; + DECLARE p INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO c FROM entity_ids WHERE id = ChildID; + SELECT internal_id INTO p FROM entity_ids WHERE id = ParentID; + INSERT INTO isa_cache (child, parent, rpath) VALUES (c, p, c); IF p = c THEN @@ -69,17 +73,17 @@ insert_is_a_proc: BEGIN INSERT IGNORE INTO isa_cache SELECT l.child, -- Descendant as found in isa_cache r.parent, -- Ancestor as found in isa_cache - if(l.rpath=l.child and r.rpath=c, -- if distance=1 for left and right: + IF(l.rpath=l.child AND r.rpath=c, -- if distance=1 for left and right: c, -- rpath = current child - concat(if(l.rpath=l.child, -- if dist=1 for descendant: + concat(IF(l.rpath=l.child, -- if dist=1 for descendant: c, -- rpath starts with c concat(l.rpath, '>', c)), -- rpath starts with "desc.rpath > c" - if(r.rpath=c, -- if dist=1 for ancestor + IF(r.rpath=c, -- if dist=1 for ancestor '', -- rpath is finished concat('>', r.rpath)))) -- rpath continuees with " > ancest.rpath" AS rpath FROM - isa_cache as l INNER JOIN isa_cache as r + isa_cache AS l INNER JOIN isa_cache AS r ON (l.parent = c AND c = r.child AND l.child != l.parent); -- Left: descendants of c, right: ancestors END; diff --git a/procedures/insertUser.sql b/procedures/insertUser.sql deleted file mode 100644 index 392b6668c7e1fe8bb743afa37cb51f35e52b624c..0000000000000000000000000000000000000000 --- a/procedures/insertUser.sql +++ /dev/null @@ -1,43 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - -Drop Procedure if exists db_5_0.insertUser; -Delimiter // -Create Procedure db_5_0.insertUser(in Name VARCHAR(255), in Password VARCHAR(255)) - -BEGIN - - -INSERT INTO entities (name, role, acl) VALUES (Name, 'USER', 0); - -SET @LAST_UserID = LAST_INSERT_ID(); - -INSERT INTO passwords VALUES (@LAST_UserID, Password); - -Select @LAST_UserID as UserID; - -END; -// - - -delimiter ; diff --git a/procedures/isSubtype.sql b/procedures/isSubtype.sql index 489a63e47a1185d6e221fedbe5a3aec65f0470f3..98d9387077d89f3173fa939f6d7517bfbe95ebff 100644 --- a/procedures/isSubtype.sql +++ b/procedures/isSubtype.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,18 +18,37 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.isSubtype; delimiter // -CREATE PROCEDURE db_5_0.isSubtype(in c INT UNSIGNED, in p INT UNSIGNED) +/* + * Return TRUE if the given Child is indeed a (direct or indirect) child of the + * given Parent. + * + * Parameters + * ---------- + * ChildID : VARCHAR(255) + * The entity id of the child. + * ParentID : VARCHAR(255) + * The entity id of the parent. + * + * Returns + * ------- + * ISA : BOOLEAN + */ +CREATE PROCEDURE db_5_0.isSubtype(in ChildID VARCHAR(255), in ParentID VARCHAR(255)) BEGIN - DECLARE ret BOOLEAN DEFAULT FALSE; - SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1; + DECLARE c INT UNSIGNED DEFAULT NULL; + DECLARE p INT UNSIGNED DEFAULT NULL; + DECLARE ret BOOLEAN DEFAULT FALSE; + + SELECT internal_id INTO c from entity_ids WHERE id = ChildID; + SELECT internal_id INTO p from entity_ids WHERE id = ParentID; + + SELECT TRUE INTO ret FROM isa_cache AS i WHERE i.child=c AND i.parent=p LIMIT 1; SELECT ret as ISA; END; // diff --git a/procedures/overrideName.sql b/procedures/overrideName.sql index 8ee39d25739220705d20688fe217a06fc0a18694..f8921330fcfa44c5f056dd2072fb8d781b7e2993 100644 --- a/procedures/overrideName.sql +++ b/procedures/overrideName.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.overrideName; @@ -26,21 +25,61 @@ DROP PROCEDURE IF EXISTS db_5_0.overrideDesc; DROP PROCEDURE IF EXISTS db_5_0.overrideType; DELIMITER // -CREATE PROCEDURE db_5_0.overrideName(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Name VARCHAR(255)) +/* + * Insert a name override. + * + * Parameters + * ---------- + * InternalDomainID : INT UNSIGNED + * The *internal* id of the domain. + * InternalEntityID : INT UNSIGNED + * The *internal* id of the entity. + * InternalPropertyID : INT UNSIGNED + * The *internal* id of the property. + * Name : VARCHAR(255) + */ +CREATE PROCEDURE db_5_0.overrideName(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Name VARCHAR(255)) BEGIN - INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (DomainID, EntityID, PropertyID, Name); + INSERT INTO name_overrides (domain_id, entity_id, property_id, name) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Name); END; // -CREATE PROCEDURE db_5_0.overrideDesc(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Description TEXT) +/* + * Insert a description override. + * + * Parameters + * ---------- + * InternalDomainID : INT UNSIGNED + * The *internal* id of the domain. + * InternalEntityID : INT UNSIGNED + * The *internal* id of the entity. + * InternalPropertyID : INT UNSIGNED + * The *internal* id of the property. + * Description : TEXT + */ +CREATE PROCEDURE db_5_0.overrideDesc(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in Description TEXT) BEGIN - INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (DomainID, EntityID, PropertyID, Description); + INSERT INTO desc_overrides (domain_id, entity_id, property_id, description) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, Description); END; // -CREATE PROCEDURE db_5_0.overrideType(in DomainID INT UNSIGNED, in EntityID INT UNSIGNED, in PropertyID INT UNSIGNED, in Datatype INT UNSIGNED) +/* + * Insert a data type override. + * + * Parameters + * ---------- + * InternalDomainID : INT UNSIGNED + * The *internal* id of the domain. + * InternalEntityID : INT UNSIGNED + * The *internal* id of the entity. + * InternalPropertyID : INT UNSIGNED + * The *internal* id of the property. + * InternalDatatypeID : INT UNSIGNED + * The *internal* id of the data type. + */ +CREATE PROCEDURE db_5_0.overrideType(in InternalDomainID INT UNSIGNED, in InternalEntityID INT UNSIGNED, in InternalPropertyID INT UNSIGNED, in InternalDataTypeID INT UNSIGNED) BEGIN - INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (DomainID, EntityID, PropertyID, Datatype); + INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (InternalDomainID, InternalEntityID, InternalPropertyID, InternalDataTypeID); END; // diff --git a/procedures/query/applyIDFilter.sql b/procedures/query/applyIDFilter.sql index 642e7806b47dae6848e77126f6a5c413ac9615db..062de92d9f1dc477a72dfda3285af9133b24ae98 100644 --- a/procedures/query/applyIDFilter.sql +++ b/procedures/query/applyIDFilter.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.applyIDFilter; @@ -32,71 +31,114 @@ DELIMITER // * * The `versioned` flag currently only has the effect that an `_iversion` column is also copied to * the target. + * + * Parameters + * ---------- + * sourceSet : VARCHAR(255) + * The name of the table from where we start. + * targetSet : VARCHAR(255) + * The name of the table where we collect all the "good" ids (or NULL or same as sourceSet). + * o : CHAR(2) + * The operator used for filtering, e.g. '=', '!=', '>', ... + * EntityID : VARCHAR(255) + * An entity id, existing or non-existing, which we use to compare the + * existing entities to using the operator. + * agg : CHAR(3) + * An aggregate function, e.g. 'max' or 'min'. This only makes sense for number-based ids. + * versioned : BOOLEAN + * The filter belongs to a version-aware query (e.g. FIND ANY VERSION OF + * ...) and hence the sourceSet and targetSet have an `_iversion` column. */ CREATE PROCEDURE db_5_0.applyIDFilter(in sourceSet VARCHAR(255), in targetSet VARCHAR(255), - in o CHAR(2), in vInt BIGINT, in agg CHAR(3), in versioned BOOLEAN) + in o CHAR(2), in EntityID VARCHAR(255), in agg CHAR(3), in versioned BOOLEAN) IDFILTER_LABEL: BEGIN DECLARE data VARCHAR(20000) DEFAULT NULL; DECLARE aggVal VARCHAR(255) DEFAULT NULL; +DECLARE direction CHAR(4) DEFAULT NULL; +DECLARE entity_id_type VARCHAR(255) DEFAULT "eids.id "; #-- get aggVal if possible IF agg IS NOT NULL THEN IF versioned THEN -- TODO versioned queries SELECT 1 FROM id_agg_with_versioning_not_implemented; + ELSEIF agg = "max" THEN + SET direction = "DESC"; + ELSEIF agg = "min" THEN + SET direction = "ASC "; + ELSE + SELECT 1 FROM unknown_agg_parameter; END IF; + SET @stmtIDAggValStr = CONCAT( - "SELECT ", - agg, - "(id) INTO @sAggVal FROM `", + "SELECT e.internal_id INTO @sAggVal FROM `", sourceSet, - "`"); + "` AS s LEFT JOIN entity_ids AS e ON (s.id=e.internal_id) WHERE s.id>99 ORDER BY CAST(e.id AS UNSIGNED INT) ", + direction, + " LIMIT 1"); + PREPARE stmtIDAggVal FROM @stmtIDAggValStr; EXECUTE stmtIDAggVal; DEALLOCATE PREPARE stmtIDAggVal; SET aggVal = @sAggVal; END IF; +IF o = ">" OR o = ">=" OR o = "<" or o = "<=" THEN + SET entity_id_type = "CAST(eids.id AS UNSIGNED INT) "; +END IF; + #-- generate stmt string IF targetSet IS NULL OR targetSet = sourceSet THEN SET data = CONCAT( "DELETE FROM `", sourceSet, "` WHERE ", - IF(o IS NULL OR vInt IS NULL, + IF(o IS NULL OR EntityID IS NULL, "1=1", - CONCAT("NOT id", + CONCAT("NOT EXISTS (SELECT 1 FROM entity_ids AS eids WHERE ", + entity_id_type, o, - vInt)), + ' "', + EntityID, + '" ', + " AND eids.internal_id = `", + sourceSet, + "`.id)" + )), IF(aggVal IS NULL, "", - CONCAT(" AND id!=", + CONCAT(" AND `", sourceSet, "`.id!=", aggVal))); ELSEIF versioned AND sourceSet = "entities" THEN - -- ################# VERSIONING ##################### SET data = CONCAT( "INSERT IGNORE INTO `", targetSet, - '` (id, _iversion) SELECT id, _get_head_iversion(id) FROM `entities` WHERE ', - IF(o IS NULL OR vInt IS NULL, + '` (id, _iversion) SELECT e.id, _get_head_iversion(e.id) FROM `entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ', + IF(o IS NULL OR EntityID IS NULL, "1=1", - CONCAT("id", + CONCAT(entity_id_type, o, - vInt)), + ' "', + EntityID, + '"' + )), IF(aggVal IS NULL, "", - CONCAT(" AND id=", + CONCAT(" AND e.id=", aggVal)), - ' UNION SELECT id, _iversion FROM `archive_entities` WHERE ', - IF(o IS NULL OR vInt IS NULL, + ' UNION SELECT e.id, _iversion FROM `archive_entities` AS e JOIN entity_ids AS eids ON (e.id = eids.internal_id) WHERE ', + IF(o IS NULL OR EntityID IS NULL, "1=1", - CONCAT("id", + CONCAT(entity_id_type, o, - vInt)), + ' "', + EntityID, + '"' + )), IF(aggVal IS NULL, "", - CONCAT(" AND id=", + CONCAT(" AND e.id=", aggVal))); -- ################################################## @@ -108,12 +150,15 @@ ELSE '` (id, _iversion) SELECT data.id, data._iversion FROM `', '` (id) SELECT data.id FROM `'), sourceSet, - "` AS data WHERE ", - IF(o IS NULL OR vInt IS NULL, + "` AS data JOIN entity_ids AS eids ON (eids.internal_id = data.id) WHERE ", + IF(o IS NULL OR EntityID IS NULL, "1=1", - CONCAT("data.id", + CONCAT(entity_id_type, o, - vInt)), + ' "', + EntityID, + '"' + )), IF(aggVal IS NULL, "", CONCAT(" AND data.id=", diff --git a/procedures/query/applyPOV.sql b/procedures/query/applyPOV.sql index 9fb9101260e61b33439cb7d5ea6e2e3a9ff5ca2d..a038e4c7961c9c3a01f725c210dec4cfb9029eeb 100644 --- a/procedures/query/applyPOV.sql +++ b/procedures/query/applyPOV.sql @@ -1,5 +1,4 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, @@ -17,8 +16,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ /* Documentation including (?) has to be checked by an expert. */ @@ -37,30 +34,31 @@ DELIMITER // * ---------- * * versioned : boolean - * If True, sourceSet and targetSet have an _iversion column, otherwise that column will be -* ignored (or only HEAD will be inserted into targetSet). + * If True, sourceSet and targetSet have an _iversion column, otherwise that column will be ignored + * (or only HEAD will be inserted into targetSet). */ -CREATE PROCEDURE db_5_0.applyPOV(in sourceSet VARCHAR(255), /* (?) Name of the table that the POV will be applied to. This can be a temporary table. */ - in targetSet VARCHAR(255), /* (?) Name of the result table of this POV. */ +CREATE PROCEDURE db_5_0.applyPOV(in sourceSet VARCHAR(255), /* Name of the table that the POV will be applied to. This can be a temporary table or the `entities` table */ + in targetSet VARCHAR(255), /* Name of the result table of this POV. After the filter has been applied this table only contains matching + entity ids. This may be NULL or same as sourceSet. In that case the filter is applied in-place (delete non-matching). Otherwise the filter is applied by copying only the matching ids from the *source* set to the *target* set. */ in propertiesTable VARCHAR(255), - in refIdsTable VARCHAR(255), + in refIdsTable VARCHAR(255), /* Name of a tmp table that contains all ids of children of the value interpreted as entity name or id */ in o CHAR(4), /* The operator for this operation. can be one of: 0 check for "equals NULL" !0 check for "not NULL" -> check whether a reference exists - ( (?) check for datetime intervals - !( (?) check for being outside of datetime intervals - other operators (all SQL operators (?)) + ( check for datetime interval (say "in") + !( check for being outside of datetime intervals (say "not in") + other operators (all valid SQL operators) these other operators can be used either with or without an aggregation to use an aggregation set agg to non-zero all SQL aggregations can be used */ - in vText VARCHAR(255), /* (?) the text value to be checked against using operator o */ + in vText VARCHAR(255), /* the text value to be checked against using operator o */ in vInt INT, /* the integer value to be checked against using operator o */ in vDouble DOUBLE, /* the double value to be checked against using operator o */ - in unit_sig BIGINT, + in unit_sig BIGINT, /* signatur of the unit given by the user. used when we need to convert units. */ in vDoubleStdUnit DOUBLE, /* The numeric value, converted according to the unit rules. */ - in stdUnit_sig BIGINT, + in stdUnit_sig BIGINT, /* signatur of the normalized/standardized unit, e.g when unit_sig is "km/h" this might be "m/s". */ in vDateTime VARCHAR(255), in vDateTimeDotNotation VARCHAR(255), in agg CHAR(3), /* an SQL aggregate function or NULL when no aggregation should be used */ @@ -84,6 +82,10 @@ POV_LABEL: BEGIN DECLARE keepTabl VARCHAR(255) DEFAULT NULL; DECLARE existence_op VARCHAR(255) DEFAULT "EXISTS"; + #-- ######### HINT ############## + #-- first the appropriate statement is created which in the end prepared and executed + #-- ############################# + IF o = '->' THEN #-- special case: pure reference property call applyRefPOV(sourceSet,targetSet, propertiesTable, refIdsTable, versioned); @@ -232,6 +234,8 @@ POV_LABEL: BEGIN IF o = "!=" AND refIdsTable IS NOT NULL THEN SET existence_op = "NOT EXISTS"; END IF; + /* select all entities that reference the entity or a child of the + * value interpreted as ID*/ SET sRefData = IF(vText IS NULL, ' UNION ALL SELECT DISTINCT domain_id, entity_id, property_id FROM `reference_data`', IF(refIdsTable IS NULL, @@ -246,6 +250,7 @@ POV_LABEL: BEGIN END IF; + #-- create array of statement parts (and replace null with empty string) (?) SET data = CONCAT('(',sTextData, IF(sNameData IS NULL, '', sNameData), IF(sEnumData IS NULL, '', sEnumData), @@ -262,6 +267,7 @@ POV_LABEL: BEGIN call createTmpTable(keepTabl, versioned); IF versioned THEN #-- generate statement from statement parts + #-- (versioned section) SET @stmtPOVkeepTblStr = CONCAT( 'INSERT IGNORE INTO `', keepTabl, '` (id, _iversion) SELECT entity_id AS id, _iversion FROM ', data, ' as data', IF(propertiesTable IS NULL, '', CONCAT( @@ -302,7 +308,14 @@ POV_LABEL: BEGIN DEALLOCATE PREPARE stmtPOVkeepTbl; ELSE #-- generate statement from statement parts - SET @stmtPOVkeepTblStr = CONCAT('INSERT IGNORE INTO `', keepTabl, '` (id) SELECT DISTINCT entity_id AS id FROM ', data, ' as data', IF(propertiesTable IS NULL, '', CONCAT(' WHERE EXISTS (Select 1 from `', propertiesTable, '` AS prop WHERE prop.id = data.property_id AND (prop.id2=data.entity_id OR prop.id2=0))'))); + SET @stmtPOVkeepTblStr = CONCAT( + 'INSERT IGNORE INTO `', keepTabl, + '` (id) SELECT DISTINCT entity_id AS id FROM ', data, ' as data', + IF(propertiesTable IS NULL, '', + CONCAT(' WHERE EXISTS (Select 1 from `', propertiesTable, + '` AS prop WHERE prop.id = data.property_id AND + (prop.id2=data.entity_id OR prop.id2=0))'))); + #-- (unversioned section) SET @stmtPOVStr = CONCAT( IF(targetSet IS NULL, diff --git a/procedures/query/applyTransactionFilter.sql b/procedures/query/applyTransactionFilter.sql index 63267a4505040c186721a367d141ac566cb30bc4..0d2490b43b17ecc4157156db0d2d2be84bd58d3b 100644 --- a/procedures/query/applyTransactionFilter.sql +++ b/procedures/query/applyTransactionFilter.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,37 +18,65 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.applyTransactionFilter; DELIMITER // + +/* + * Apply a transaction filter to the sourceSet and collect the remaining + * entities in the targetSet. + * + * Parameters + * ---------- + * sourceSet : VARCHAR(255) + * The name of the table from where we start. + * targetSet : VARCHAR(255) + * The name of the table where we collect all the "good" ids (or NULL or same as sourceSet). + * transaction : VARCHAR(255) + * The transaction's type (INSERT, UPDATE,...) + * operator_u : CHAR(2) + * The operator used for filtering by the user, e.g. '=', '!='. + * realm : VARCHAR(255) + * The user's realm (if filtering by the user). + * userName : VARCHAR(255) + * The user's name (if filtering by the user). + * ilb : BIGINT + * Inclusive Lower Bound of seconds for the transactions time. + * ilb_nanos : BIGINT + * Inclusive Lower Bound of nanoseconds for the transactions time. + * eub : BIGINT + * Exclusive Upper Bound of seconds for the transactions time. + * eub_nanos : BIGINT + * Exclusive Upper Bound of nanoseconds for the transactions time. + * operator_t : CHAR(2) + * The operator used for filtering by the transaction time, e.g. '=', '!=', '<', '>='. + */ CREATE PROCEDURE db_5_0.applyTransactionFilter(in sourceSet VARCHAR(255), targetSet VARCHAR(255), in transaction VARCHAR(255), in operator_u CHAR(2), in realm VARCHAR(255), in userName VARCHAR(255), in ilb BIGINT, in ilb_nanos INT UNSIGNED, in eub BIGINT, in eub_nanos INT UNSIGNED, in operator_t CHAR(2)) BEGIN - DECLARE data TEXT default CONCAT('(SELECT entity_id FROM transaction_log AS t WHERE t.transaction=\'', - transaction, - '\'', - IF(userName IS NOT NULL, - CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'), - '' - ), - IF(ilb IS NOT NULL, - CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)), - "" - ), - ')' - ); + DECLARE data TEXT default CONCAT("(SELECT internal_id AS entity_id FROM transaction_log AS t JOIN entity_ids AS eids ON ( t.entity_id = eids.id ) WHERE t.transaction='", + transaction, + "'", + IF(userName IS NOT NULL, + CONCAT(' AND t.realm', operator_u, '? AND t.username', operator_u, '?'), + '' + ), + IF(ilb IS NOT NULL, + CONCAT(" AND", constructDateTimeWhereClauseForColumn("t.seconds", "t.nanos", ilb, ilb_nanos, eub, eub_nanos, operator_t)), + "" + ), + ')' + ); - SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE); - PREPARE stmtTransactionFilter from @stmtTransactionStr; - IF userName IS NOT NULL THEN - SET @userName = userName; - SET @realm = realm; - EXECUTE stmtTransactionFilter USING @realm, @userName; - ELSE - EXECUTE stmtTransactionFilter; - END IF; + SET @stmtTransactionStr = makeStmt(sourceSet, targetSet, data, NULL, FALSE); + PREPARE stmtTransactionFilter from @stmtTransactionStr; + IF userName IS NOT NULL THEN + SET @userName = userName; + SET @realm = realm; + EXECUTE stmtTransactionFilter USING @realm, @userName; + ELSE + EXECUTE stmtTransactionFilter; + END IF; END; // diff --git a/procedures/query/initBackReference.sql b/procedures/query/initBackReference.sql index 777ddcc90f87b1a9cfe2d3ae70b64ce2c5ce25f7..6b3be3cdd2f97737ec8cb92a77040076027f1927 100644 --- a/procedures/query/initBackReference.sql +++ b/procedures/query/initBackReference.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,27 +18,52 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.initBackReference; DELIMITER // -CREATE PROCEDURE db_5_0.initBackReference(in pid INT UNSIGNED, in pname VARCHAR(255), in entity_id INT UNSIGNED, in ename VARCHAR(255)) + +/* + * Create and initialize two new temporary tables. + * + * This is used to initialize the filterin for backreferences to a + * particular entity (specified by EntityID or EntityName) or using a + * particular property (specified by PropertyID or PropertyName). + * + * The propertiesTable contains all properties matching the PropertyID or + * PropertyName. The entitiesTable contains all entities matching EntityID or + * EntityName. + + * Parameters + * ---------- + * PropertyID : VARCHAR(255) + * The property's (external) id. + * PropertyName : VARCHAR(255) + * The property's name. + * EntityID : VARCHAR(255) + * The entity's (external) id. + * EntityName : VARCHAR(255) + * The entity's name. + * + * Select + * ------ + * Tuple (propertiesTable, entitiesTable) + */ +CREATE PROCEDURE db_5_0.initBackReference(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in EntityID VARCHAR(255), in EntityName VARCHAR(255)) BEGIN DECLARE propertiesTable VARCHAR(255) DEFAULT NULL; DECLARE entitiesTable VARCHAR(255) DEFAULT NULL; - IF pname IS NOT NULL THEN + IF PropertyName IS NOT NULL THEN -- TODO versioning for properties call createTmpTable(propertiesTable, FALSE); - call initSubEntity(pid, pname, propertiesTable); + call initSubEntity(PropertyID, PropertyName, propertiesTable); END IF; - IF ename IS NOT NULL THEN + IF EntityName IS NOT NULL THEN -- TODO versioning for referencing entities call createTmpTable(entitiesTable, FALSE); - call initSubEntity(entity_id, ename, entitiesTable); + call initSubEntity(EntityID, EntityName, entitiesTable); END IF; SELECT propertiesTable, entitiesTable; diff --git a/procedures/query/initEntity.sql b/procedures/query/initEntity.sql index cb7822b8426d95dad2c159a23deaa1882c46cd78..cd1d35b1a4301b978ecc6bbd70653d222f949c96 100644 --- a/procedures/query/initEntity.sql +++ b/procedures/query/initEntity.sql @@ -30,7 +30,7 @@ DELIMITER // * If `versioned` is `TRUE`, also add archived entities (for example if the name was changed in the * past). */ -CREATE PROCEDURE db_5_0.initEntity(in eid INT UNSIGNED, in ename VARCHAR(255), +CREATE PROCEDURE db_5_0.initEntity(in eid VARCHAR(255), in ename VARCHAR(255), in enameLike VARCHAR(255), in enameRegexp VARCHAR(255), in resultset VARCHAR(255), in versioned BOOLEAN) initEntityLabel: BEGIN @@ -78,11 +78,12 @@ initEntityLabel: BEGIN 'INSERT IGNORE INTO `', resultset, IF(versioned, - '` (id, _iversion) SELECT id, _get_head_iversion(id) ', - '` (id) SELECT id '), - 'FROM entities WHERE id=',eid,';'); + '` (id, _iversion) SELECT eids.internal_id, _get_head_iversion(eids.internal_id) ', + '` (id) SELECT eids.internal_id '), + 'FROM entity_ids AS eids WHERE eids.id=?;'); + SET @query_param = eid; PREPARE initEntityStmt FROM @initEntityStmtStr; - EXECUTE initEntityStmt; + EXECUTE initEntityStmt USING @query_param; DEALLOCATE PREPARE initEntityStmt; END IF; diff --git a/procedures/query/initPOV.sql b/procedures/query/initPOV.sql index f5c1d1d95d63bde8d18de8f6065ded150213594c..4f132219c3c0dc9fdea76a76f943199551d6f079 100644 --- a/procedures/query/initPOV.sql +++ b/procedures/query/initPOV.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,15 +18,32 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DELIMITER // DROP PROCEDURE IF EXISTS db_5_0.initPOVPropertiesTable// -CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in pid INT UNSIGNED, in pname VARCHAR(255), in sourceSet VARCHAR(255)) +/* + * Create and initialize a new temporary table. + * + * This is used to initialize the POV filtering. The resulting table + * contains all properties matching the Property component of the POV filter. + * + * Parameters + * ---------- + * PropertyID : VARCHAR(255) + * The property's (external) id. + * PropertyName : VARCHAR(255) + * The property's name. + * sourceSet : VARCHAR(255) + * The name of the table which will be filtered by the POV filter. + * + * Select + * ------ + * Tuple (propertiesTable, ... and a lot of debug output) + */ +CREATE PROCEDURE db_5_0.initPOVPropertiesTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255), in sourceSet VARCHAR(255)) BEGIN DECLARE propertiesTable VARCHAR(255) DEFAULT NULL; /*table for property ids*/ DECLARE replTbl VARCHAR(255) DEFAULT NULL; @@ -38,24 +56,31 @@ BEGIN DECLARE t6 BIGINT DEFAULT 0; - IF pname is NOT NULL THEN + IF PropertyName is NOT NULL THEN SELECT conv( concat( substring(uid,16,3), substring(uid,10,4), substring(uid,1,8)),16,10) div 10000 - (141427 * 24 * 60 * 60 * 1000) as current_mills INTO t1 from (select uuid() uid) as alias; call createTmpTable2(propertiesTable); - -- fill in all properties named "pname" + -- Fill in all properties (plus the domain id and entity id) named + -- "PropertyName", be it their default name or their overridden name. + -- We need *all* properties (mind, the properties of entities not + -- abstract properties) with the given name. If an abstract + -- property has the name "person" it might have the name "author" in + -- the "Article" record type. Now, if I want to collect all properties + -- of the Article named "author" I need to look into the name_overrides + -- table. SET @initPOVPropertiesTableStmt1 = CONCAT('INSERT IGNORE INTO `', propertiesTable, '` (id, id2, domain) SELECT property_id, entity_id, domain_id from name_overrides WHERE name = ? UNION ALL SELECT entity_id, domain_id, 0 FROM name_data WHERE value = ?;'); PREPARE stmt FROM @initPOVPropertiesTableStmt1; - SET @pname = pname; - EXECUTE stmt USING @pname, @pname; + SET @PropertyName = PropertyName; + EXECUTE stmt USING @PropertyName, @PropertyName; SET ecount = ROW_COUNT(); - -- fill in all properties with id="pid" + -- fill in all properties with id="PropertyID" SELECT conv( concat( substring(uid,16,3), substring(uid,10,4), substring(uid,1,8)),16,10) div 10000 - (141427 * 24 * 60 * 60 * 1000) as current_mills INTO t2 from (select uuid() uid) as alias; - IF pid IS NOT NULL THEN + IF PropertyID IS NOT NULL THEN SET @initPOVPropertiesTableStmt2 = CONCAT('INSERT IGNORE INTO `', propertiesTable, '` (id, id2, domain) VALUES (?, 0, 0)'); PREPARE stmt FROM @initPOVPropertiesTableStmt2; - SET @pid = pid; - EXECUTE stmt USING @pid; + SET @PropertyID = PropertyID; + EXECUTE stmt USING @PropertyID; SET ecount = ecount + ROW_COUNT(); END IF; @@ -91,15 +116,33 @@ END // DROP PROCEDURE IF EXISTS db_5_0.initPOVRefidsTable // -CREATE PROCEDURE db_5_0.initPOVRefidsTable(in vInt INT UNSIGNED, in vText VARCHAR(255)) +/* + * Create and initialize a new temporary table. + * + * This used to initialize the POV filtering. The resulting table + * contains all entities matching the Value component of the POV filter (i.e. + * the referenced entities). + * + * Parameters + * ---------- + * PropertyID : VARCHAR(255) + * The property's (external) id. + * PropertyName : VARCHAR(255) + * The property's name. + * + * Select + * ------ + * Tuple (refIdsTable) + */ +CREATE PROCEDURE db_5_0.initPOVRefidsTable(in PropertyID VARCHAR(255), in PropertyName VARCHAR(255)) BEGIN DECLARE refIdsTable VARCHAR(255) DEFAULT NULL; /*table for referenced entity ids*/ #-- for reference properties: the value is interpreted as a record type name. - IF vText IS NOT NULL THEN + IF PropertyName IS NOT NULL THEN -- TODO versioned queries call createTmpTable(refIdsTable, FALSE); - call initSubEntity(vInt, vText, refIdsTable); + call initSubEntity(PropertyID, PropertyName, refIdsTable); #-- now, all ids are in the refIdsTable END IF; SELECT refIdsTable; diff --git a/procedures/query/initSubEntity.sql b/procedures/query/initSubEntity.sql index 27fa2b0669bb8d4d776fce8baf0583bf5b8039b8..a6c4955954908699710849f1cc12e4f45b101c30 100644 --- a/procedures/query/initSubEntity.sql +++ b/procedures/query/initSubEntity.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,20 +18,35 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.initSubEntity; DELIMITER // - -CREATE PROCEDURE db_5_0.initSubEntity(in e_id INT UNSIGNED, in ename VARCHAR(255), in tableName VARCHAR(255)) +/* + * Initialize a new temporary table by loading an entity (by name or by id or + * both) and all of its children into the table (i.e. their internal ids). + * + * The table name has to be provided. + * + * This is used by initPOVRefidsTable and initBackReference for sub-property filtering. + * + * Parameters + * ---------- + * EntityID : VARCHAR(255) + * The entity's (external) id. + * EntityName : VARCHAR(255) + * The entity's name. + * tableName : VARCHAR(255) + * The table which is to be initialized. + */ +CREATE PROCEDURE db_5_0.initSubEntity(in EntityID VARCHAR(255), in ename VARCHAR(255), in tableName VARCHAR(255)) BEGIN DECLARE ecount INT DEFAULT 0; DECLARE op VARCHAR(255) DEFAULT '='; + IF LOCATE("%", ename) > 0 THEN SET op = "LIKE"; END IF; @@ -47,10 +63,11 @@ BEGIN SET ecount = ROW_COUNT(); DEALLOCATE PREPARE stmt; - IF e_id IS NOT NULL THEN - SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) VALUES (', e_id, ')'); + IF EntityID IS NOT NULL THEN + SET @stmtStr = CONCAT('INSERT IGNORE INTO `', tableName, '` (id) SELECT internal_id FROM entity_ids WHERE id = ?'); PREPARE stmt FROM @stmtStr; - EXECUTE stmt; + SET @eid = EntityID; + EXECUTE stmt USING @eid; SET ecount = ecount + ROW_COUNT(); DEALLOCATE PREPARE stmt; END IF; diff --git a/procedures/registerSubdomain.sql b/procedures/registerReplacementIds.sql similarity index 70% rename from procedures/registerSubdomain.sql rename to procedures/registerReplacementIds.sql index 03b0111dbcffea357ddadd8f1c4a1e842e7ad1a4..18d7082319866603a9abda158d357781112be37c 100644 --- a/procedures/registerSubdomain.sql +++ b/procedures/registerReplacementIds.sql @@ -1,9 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen + * Copyright (C) 2023 IndiScale GmbH <www.indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,33 +18,25 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ - - - - - - - - DROP PROCEDURE IF EXISTS db_5_0.registerSubdomain; +DROP PROCEDURE IF EXISTS db_5_0.registerReplacementIds; delimiter // -CREATE PROCEDURE db_5_0.registerSubdomain(in amount INT UNSIGNED) +CREATE PROCEDURE db_5_0.registerReplacementIds(in amount INT UNSIGNED) BEGIN DECLARE ED INTEGER DEFAULT NULL; - SELECT COUNT(id) INTO ED FROM entities WHERE Role='DOMAIN' AND id!=0; + SELECT COUNT(id) INTO ED FROM entities WHERE Role='_REPLACEMENT' AND id!=0; WHILE ED < amount DO INSERT INTO entities (description, role, acl) VALUES - (NULL, 'DOMAIN', 0); + (NULL, '_REPLACEMENT', 0); + SET ED = ED + 1; END WHILE; - SELECT id as DomainID FROM entities WHERE Role='DOMAIN' and id!=0; + SELECT CONCAT("$", e.id) as ReplacementID FROM entities AS e WHERE e.Role='_REPLACEMENT' and e.id!=0; END; // diff --git a/procedures/retrieveDatatype.sql b/procedures/retrieveDatatype.sql deleted file mode 100644 index 1a32d7f92a23b88dce5b71efc6e10d4dc733f1a8..0000000000000000000000000000000000000000 --- a/procedures/retrieveDatatype.sql +++ /dev/null @@ -1,44 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - - - - - - - -DROP PROCEDURE IF EXISTS db_5_0.retrieveDatatype; -delimiter // -CREATE PROCEDURE db_5_0.retrieveDatatype(in DatatypeName VARCHAR(255)) -BEGIN - -Select e.id INTO @DatatypeID from entities e where e.name=DatatypeName AND e.role='DATATYPE' LIMIT 1; - -call retrieveEntity(@DatatypeID); - - - - -END; -// -delimiter ; diff --git a/procedures/retrieveEntity.sql b/procedures/retrieveEntity.sql index 8ecfea0c787f165970fe0cbf22e344dd0c7398c3..3e0aeb580cdb3ff26da6bee6167b9ba5ad63a94d 100644 --- a/procedures/retrieveEntity.sql +++ b/procedures/retrieveEntity.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ @@ -36,30 +33,40 @@ drop procedure if exists db_5_0.retrieveEntity // * * Parameters * ---------- - * EntityID + * EntityID : VARCHAR(255) * The entity's id. - * Version + * Version : VARBINARY(255) * The version id. In this procedure only, the version may also be given as * `HEAD` for the latest version or as `HEAD~n`, which retrieves the n-th * ancestor of `HEAD`. * * ResultSet * --------- - * Tuple of (Datatype, Collection, EntityID, EntityName, EntityDesc, - * EntityRole, FileSize, FilePath, FileHash, ACL, Version) + * Tuple of (DatatypeID, DatatypeName, Collection, EntityID, EntityName, + * EntityDesc, EntityRole, FileSize, FilePath, FileHash, ACL, + * Version) */ create procedure db_5_0.retrieveEntity( - in EntityID INT UNSIGNED, + in EntityID VARCHAR(255), in Version VARBINARY(255)) retrieveEntityBody: BEGIN DECLARE FilePath VARCHAR(255) DEFAULT NULL; DECLARE FileSize VARCHAR(255) DEFAULT NULL; DECLARE FileHash VARCHAR(255) DEFAULT NULL; - DECLARE DatatypeID INT UNSIGNED DEFAULT NULL; + DECLARE DatatypeID VARCHAR(255) DEFAULT NULL; + DECLARE InternalDatatypeID INT UNSIGNED DEFAULT NULL; DECLARE CollectionName VARCHAR(255) DEFAULT NULL; DECLARE IsHead BOOLEAN DEFAULT TRUE; DECLARE IVersion INT UNSIGNED DEFAULT NULL; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; + IF InternalEntityID IS NULL THEN + -- RETURN EARLY - Entity does not exist. + SELECT 0 FROM entities WHERE 0 = 1; + LEAVE retrieveEntityBody; + END IF; IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN -- Find out head-ness and version @@ -73,7 +80,7 @@ retrieveEntityBody: BEGIN END IF; IF IsHead IS FALSE THEN - SET IVersion=get_iversion(EntityID, Version); + SET IVersion=get_iversion(InternalEntityID, Version); IF IVersion IS NULL THEN -- RETURN EARLY - Version does not exist. @@ -84,16 +91,16 @@ retrieveEntityBody: BEGIN SELECT path, size, HEX(hash) INTO FilePath, FileSize, FileHash FROM archive_files - WHERE file_id = EntityID + WHERE file_id = InternalEntityID AND _iversion = IVersion LIMIT 1; SELECT datatype - INTO DatatypeID + INTO InternalDatatypeID FROM archive_data_type WHERE domain_id = 0 AND entity_id = 0 - AND property_id = EntityID + AND property_id = InternalEntityID AND _iversion = IVersion LIMIT 1; @@ -102,7 +109,7 @@ retrieveEntityBody: BEGIN FROM archive_collection_type WHERE domain_id = 0 AND entity_id = 0 - AND property_id = EntityID + AND property_id = InternalEntityID AND _iversion = IVersion LIMIT 1; @@ -111,18 +118,17 @@ retrieveEntityBody: BEGIN ( SELECT value FROM ( SELECT value FROM name_data WHERE domain_id = 0 - AND entity_ID = DatatypeID + AND entity_id = InternalDatatypeID AND property_id = 20 - UNION SELECT DatatypeID AS value - ) AS tmp LIMIT 1 ) AS Datatype, + ) AS tmp LIMIT 1 ) AS DatatypeName, + ( SELECT id FROM entity_ids WHERE internal_id=InternalDatatypeID ) AS DatatypeID, CollectionName AS Collection, EntityID AS EntityID, ( SELECT value FROM archive_name_data WHERE domain_id = 0 - AND entity_ID = EntityID + AND entity_ID = InternalEntityID AND property_id = 20 AND _iversion = IVersion - -- LIMIT 1 -- TODO Remove this line if all tests pass. ) AS EntityName, e.description AS EntityDesc, e.role AS EntityRole, @@ -132,7 +138,7 @@ retrieveEntityBody: BEGIN (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL, Version AS Version FROM archive_entities AS e - WHERE e.id = EntityID + WHERE e.id = InternalEntityID AND e._iversion = IVersion LIMIT 1; @@ -145,33 +151,34 @@ retrieveEntityBody: BEGIN SELECT path, size, hex(hash) INTO FilePath, FileSize, FileHash FROM files - WHERE file_id = EntityID + WHERE file_id = InternalEntityID LIMIT 1; - SELECT datatype INTO DatatypeID - FROM data_type - WHERE domain_id=0 - AND entity_id=0 - AND property_id=EntityID + SELECT dt.datatype INTO InternalDatatypeID + FROM data_type as dt + WHERE dt.domain_id=0 + AND dt.entity_id=0 + AND dt.property_id=InternalEntityID LIMIT 1; SELECT collection INTO CollectionName FROM collection_type WHERE domain_id=0 AND entity_id=0 - AND property_id=EntityID + AND property_id=InternalEntityID LIMIT 1; SELECT ( SELECT value FROM name_data WHERE domain_id = 0 - AND entity_ID = DatatypeID - AND property_id = 20 LIMIT 1 ) AS Datatype, + AND entity_id = InternalDatatypeID + AND property_id = 20 LIMIT 1 ) AS DatatypeName, + ( SELECT id FROM entity_ids WHERE internal_id=InternalDatatypeID ) AS DatatypeID, CollectionName AS Collection, EntityID AS EntityID, ( SELECT value FROM name_data WHERE domain_id = 0 - AND entity_ID = EntityID + AND entity_ID = InternalEntityID AND property_id = 20 LIMIT 1) AS EntityName, e.description AS EntityDesc, e.role AS EntityRole, @@ -180,7 +187,7 @@ retrieveEntityBody: BEGIN FileHash AS FileHash, (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL, Version AS Version - FROM entities e WHERE id = EntityID LIMIT 1; + FROM entities e WHERE id = InternalEntityID LIMIT 1; END; // diff --git a/procedures/retrieveEntityOverrides.sql b/procedures/retrieveEntityOverrides.sql index ab3d1c11f34977fcea63f6d0b572c235366c19a7..d66e60a6bd8dbe509ff989522cc4e84b38b6f8cc 100644 --- a/procedures/retrieveEntityOverrides.sql +++ b/procedures/retrieveEntityOverrides.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 Indiscale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 Indiscale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,25 +18,61 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.retrieveOverrides; delimiter // +/* + * Retrieve the overridden (overriding the Abstract Property's) name, description, and datatype. + * + * Parameters + * ---------- + * + * DomainID : VARCHAR(255) + * The domain id (0 or the entity'id for level-2-data) + * EntityID : VARCHAR(255) + * The entity id (or the property'id for level-2-data) + * Version : VARBINARY(255) + * The version of the entity. Optional + * + * ResultSet + * --------- + * collection_override, # e.g. LIST + * name_override, # the name + * desc_override, # the description + * type_name_override, # the datatype, e.g. DOUBLE + * type_id_override, # data type id. + * entity_id, # same as input EntityID + * InternalPropertyID, # internal property id, to be used when property_id + * # is NULL because a replacement is used. + * property_id, # the property id + */ CREATE PROCEDURE db_5_0.retrieveOverrides( - in DomainID INT UNSIGNED, - in EntityID INT UNSIGNED, + in DomainID VARCHAR(255), + in EntityID VARCHAR(255), in Version VARBINARY(255)) retrieveOverridesBody: BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; DECLARE IsHead BOOLEAN DEFAULT TRUE; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + DECLARE InternalDomainID INT UNSIGNED DEFAULT 0; + + -- When DomainID != 0 the EntityID could possibly be a 'replacement id' + -- which are internal ids by definition (and do not have external + -- equivalents). + IF LOCATE("$", EntityID) = 1 THEN + SET InternalEntityID=SUBSTRING(EntityID, 2); + ELSE + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + END IF; + -- DomainID != 0 are always normal (i.e. external) Entity ids. + SELECT internal_id INTO InternalDomainID from entity_ids WHERE id = DomainID; IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN IF Version IS NOT NULL THEN - IF DomainID = 0 THEN + IF InternalDomainID = 0 THEN SELECT get_head_version(EntityID) = Version INTO IsHead; ELSE SELECT get_head_version(DomainID) = Version INTO IsHead; @@ -47,8 +82,8 @@ retrieveOverridesBody: BEGIN IF IsHead IS FALSE THEN SELECT e._iversion INTO IVersion FROM entity_version as e - WHERE ((e.entity_id = EntityID AND DomainID = 0) - OR (e.entity_id = DomainID)) + WHERE ((e.entity_id = InternalEntityID AND InternalDomainID = 0) + OR (e.entity_id = InternalDomainID)) AND e.version = Version; IF IVersion IS NULL THEN @@ -61,12 +96,14 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, name AS name_override, NULL AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM archive_name_overrides - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL @@ -76,12 +113,14 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, NULL AS name_override, description AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM archive_desc_overrides - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL @@ -91,16 +130,18 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, NULL AS name_override, NULL AS desc_override, - IFNULL((SELECT value FROM name_data + (SELECT value FROM name_data WHERE domain_id = 0 AND entity_id = datatype AND property_id = 20 - LIMIT 1), datatype) AS type_override, - entity_id, - property_id + LIMIT 1) AS type_name_override, + (SELECT id FROM entity_ids WHERE internal_id = datatype) AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM archive_data_type - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL @@ -110,12 +151,14 @@ retrieveOverridesBody: BEGIN collection AS collection_override, NULL AS name_override, NULL AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM archive_collection_type - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion; LEAVE retrieveOverridesBody; @@ -126,12 +169,14 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, name AS name_override, NULL AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM name_overrides - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL @@ -139,12 +184,14 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, NULL AS name_override, description AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM desc_overrides - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL @@ -152,15 +199,17 @@ retrieveOverridesBody: BEGIN NULL AS collection_override, NULL AS name_override, NULL AS desc_override, - IFNULL((SELECT value FROM name_data + (SELECT value FROM name_data WHERE domain_id = 0 AND entity_ID = datatype - AND property_id = 20 LIMIT 1), datatype) AS type_override, - entity_id, - property_id + AND property_id = 20 LIMIT 1) AS type_name_override, + (SELECT id FROM entity_ids WHERE internal_id = datatype) AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM data_type - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL @@ -168,12 +217,14 @@ retrieveOverridesBody: BEGIN collection AS collection_override, NULL AS name_override, NULL AS desc_override, - NULL AS type_override, - entity_id, - property_id + NULL AS type_name_override, + NULL AS type_id_override, + EntityID AS entity_id, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS property_id FROM collection_type - WHERE domain_id = DomainID - AND entity_id = EntityID; + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID; END; diff --git a/procedures/retrieveEntityParents.sql b/procedures/retrieveEntityParents.sql index c1378197b12b833b54f8fb22d41cb2d8ee2aa21e..5895a233a63bf51ac597b2e3c80a722e821a2f6c 100644 --- a/procedures/retrieveEntityParents.sql +++ b/procedures/retrieveEntityParents.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ @@ -28,37 +25,35 @@ DROP PROCEDURE IF EXISTS db_5_0.retrieveEntityParents; DELIMITER // /* Retrieve the parents of an Entity. - -Parameters -========== - -EntityID : UNSIGNED -Child entity for which all parental relations should be deleted. - -Returns -======= -ParentID : INT UNSIGNED - Each parent's ID - -ParentName : - The parent's name. - -ParentDescription : - The parent's description. - -ParentRole : - The parent's Role. - -ACL : - Access control list something + * + * Parameters + * ---------- + * EntityID : VARCHAR(255) + * Child entity for which all parental relations should be deleted. + * + * ResultSet + * --------- + * ParentID : VARCHAR(255) + * Each parent's ID + * ParentName : VARCHAR(255) + * The parent's name. + * ParentDescription : TEXT + * The parent's description. + * ParentRole : VARCHAR(255) + * The parent's Role. + * ACL : VARBINARY(65525) + * Access control list. */ CREATE PROCEDURE db_5_0.retrieveEntityParents( - in EntityID INT UNSIGNED, + in EntityID VARCHAR(255), in Version VARBINARY(255)) retrieveEntityParentsBody: BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; DECLARE IsHead BOOLEAN DEFAULT TRUE; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN IF Version IS NOT NULL THEN @@ -68,7 +63,7 @@ retrieveEntityParentsBody: BEGIN IF IsHead IS FALSE THEN SELECT e._iversion INTO IVersion FROM entity_version as e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e.version = Version; IF IVersion IS NULL THEN @@ -77,10 +72,10 @@ retrieveEntityParentsBody: BEGIN END IF; SELECT - i.parent AS ParentID, + ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID, ( SELECT value FROM name_data WHERE domain_id = 0 - AND entity_id = ParentID + AND entity_id = i.parent AND property_id = 20 ) AS ParentName, -- This is not necessarily the name of the parent at the time of -- IVersion but it is a good guess. Future implementations of the @@ -92,7 +87,7 @@ retrieveEntityParentsBody: BEGIN (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL FROM archive_isa AS i JOIN entities AS e ON (i.parent = e.id) - WHERE i.child = EntityID + WHERE i.child = InternalEntityID AND i.child_iversion = IVersion AND i.direct IS TRUE ; @@ -102,18 +97,18 @@ retrieveEntityParentsBody: BEGIN END IF; SELECT - i.parent AS ParentID, + ( SELECT id FROM entity_ids WHERE internal_id = i.parent) AS ParentID, ( SELECT value FROM name_data WHERE domain_id = 0 - AND entity_id = ParentID + AND entity_id = i.parent AND property_id = 20 ) AS ParentName, e.description AS ParentDescription, e.role AS ParentRole, (SELECT acl FROM entity_acl AS a WHERE a.id = e.acl) AS ACL FROM isa_cache AS i JOIN entities AS e ON (i.parent = e.id) - WHERE i.child = EntityID - AND i.rpath = EntityID; + WHERE i.child = InternalEntityID + AND i.rpath = InternalEntityID; END // diff --git a/procedures/retrieveEntityProperties.sql b/procedures/retrieveEntityProperties.sql index 5eee63c6c8eb1353135bf269fe86bc10a7baa89c..7918f0eb3669b11ddcb1c1fd0e651fe3fd69b276 100644 --- a/procedures/retrieveEntityProperties.sql +++ b/procedures/retrieveEntityProperties.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020-2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ @@ -28,30 +25,70 @@ delimiter // drop procedure if exists db_5_0.retrieveEntityProperties // +/* + * Retrieve the properties of an entity (level 1 and 2). + * + * Parameters + * ---------- + * + * DomainID : VARCHAR(255) + * The domain id (0 or the entity's id for level-2-data) + * EntityID : VARCHAR(255) + * The entity id (or the property's id for level-2-data) + * Version : VARBINARY(255) + * The version of the entity. Optional + * + * ResultSet + * --------- + * InternalPropertyID + * Internal property id, to be used when PropertyID + * is NULL because a replacement is used. + * PropertyID + * The property id + * PropertyValue + * The property value + * PropertyStatus + * E.g. OBLIGATORY, FIX, ... + * PropertyIndex + * The index of the property (for ordering). + * ) + */ create procedure db_5_0.retrieveEntityProperties( - in DomainID INT UNSIGNED, - in EntityID INT UNSIGNED, + in DomainID VARCHAR(255), + in EntityID VARCHAR(255), in Version VARBINARY(255)) retrieveEntityPropertiesBody: BEGIN DECLARE IVersion INT UNSIGNED DEFAULT NULL; DECLARE IsHead BOOLEAN DEFAULT TRUE; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + DECLARE InternalDomainID INT UNSIGNED DEFAULT 0; + + -- When DomainID != 0 the EntityID could possibly be a 'replacement id' + -- which are internal ids by definition (and do not have external + -- equivalents). + IF LOCATE("$", EntityID) = 1 THEN + SET InternalEntityID=SUBSTRING(EntityID, 2); + ELSE + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + END IF; + -- DomainID != 0 are always normal (i.e. external) Entity ids. + SELECT internal_id INTO InternalDomainID from entity_ids WHERE id = DomainID; IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN IF Version IS NOT NULL THEN - IF DomainID = 0 THEN + IF InternalDomainID = 0 THEN SELECT get_head_version(EntityID) = Version INTO IsHead; ELSE SELECT get_head_version(DomainID) = Version INTO IsHead; END IF; - END IF; IF IsHead IS FALSE THEN SELECT e._iversion INTO IVersion FROM entity_version as e - WHERE ((e.entity_id = EntityID AND DomainID = 0) - OR (e.entity_id = DomainID)) + WHERE ((e.entity_id = InternalEntityID AND InternalDomainID = 0) + OR (e.entity_id = InternalDomainID)) AND e.version = Version; IF IVersion IS NULL THEN @@ -61,121 +98,135 @@ retrieveEntityPropertiesBody: BEGIN #-- double properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_double_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- integer properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_integer_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- date properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, CONCAT(value, '.NULL.NULL') AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_date_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- datetime properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, CONCAT(value, 'UTC', IF(value_ns IS NULL, '', value_ns)) AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_datetime_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- text properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_text_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- enum properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_enum_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- reference properties SELECT - property_id AS PropertyID, - IF(value_iversion IS NULL, value, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, + IF(value_iversion IS NULL, + IF(status = "REPLACEMENT", + CONCAT("$", value), + ( SELECT id FROM entity_ids WHERE internal_id = value )), -- make it "value@version" if necessary - CONCAT(value, "@", _get_version(value, value_iversion))) + CONCAT( + ( SELECT id FROM entity_ids WHERE internal_id = value ), + "@", _get_version(value, value_iversion))) AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_reference_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- null properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, NULL AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_null_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND _iversion = IVersion UNION ALL #-- name properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM archive_name_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND property_id != 20 AND _iversion = IVersion; @@ -185,115 +236,129 @@ retrieveEntityPropertiesBody: BEGIN #-- double properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM double_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- integer properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM integer_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- date properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, CONCAT(value, '.NULL.NULL') AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM date_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- datetime properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, CONCAT(value, 'UTC', IF(value_ns IS NULL, '', value_ns)) AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM datetime_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- text properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM text_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- enum properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM enum_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- reference properties SELECT - property_id AS PropertyID, - IF(value_iversion IS NULL, value, - CONCAT(value, "@", _get_version(value, value_iversion))) + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, + IF(value_iversion IS NULL, + IF(status = "REPLACEMENT", + CONCAT("$", value), + ( SELECT id FROM entity_ids WHERE internal_id = value )), + -- make it "value@version" if necessary + CONCAT( + ( SELECT id FROM entity_ids WHERE internal_id = value ), + "@", _get_version(value, value_iversion))) AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM reference_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- null properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, NULL AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM null_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID UNION ALL #-- name properties SELECT - property_id AS PropertyID, + CONCAT("$", property_id) AS InternalPropertyID, + ( SELECT id FROM entity_ids WHERE internal_id = property_id ) AS PropertyID, value AS PropertyValue, status AS PropertyStatus, pidx AS PropertyIndex FROM name_data - WHERE domain_id = DomainID - AND entity_id = EntityID + WHERE domain_id = InternalDomainID + AND entity_id = InternalEntityID AND property_id != 20; - END; // diff --git a/procedures/retrieveGroup.sql b/procedures/retrieveGroup.sql deleted file mode 100644 index 38504b093f40da27b01d82e51d2d4e1c308745c8..0000000000000000000000000000000000000000 --- a/procedures/retrieveGroup.sql +++ /dev/null @@ -1,24 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - -Drop Procedure if exists db_5_0.retrieveGroup; diff --git a/procedures/retrieveSubentity.sql b/procedures/retrieveSubentity.sql deleted file mode 100644 index a7f2fb6b3bea081786cd65eec9ae253cbaa4b901..0000000000000000000000000000000000000000 --- a/procedures/retrieveSubentity.sql +++ /dev/null @@ -1,47 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ -DELIMITER // -DROP PROCEDURE IF EXISTS db_5_0.retrieveSubEntity // -/** -CREATE PROCEDURE db_5_0.retrieveSubEntity(in EntityID INT UNSIGNED, in DomainID INT UNSIGNED) -BEGIN - DECLARE FilePath VARCHAR(255) DEFAULT NULL; - DECLARE FileSize VARCHAR(255) DEFAULT NULL; - DECLARE FileHash VARCHAR(255) DEFAULT NULL; - - Select path, size, hex(hash) into FilePath, FileSize, FileHash from files where file_id = EntityID LIMIT 1; - Select DomainID as DomainID, - EntityID as EntityID, - e.name as EntityName, - e.description as EntityDesc, - e.role as EntityRole, - FileSize as FileSize, - FilePath as FilePath, - FileHash as FileHash - from entities e where id = EntityID LIMIT 1; - -END; -// - -**/ -DELIMITER ; diff --git a/procedures/setFileProperties.sql b/procedures/setFileProperties.sql new file mode 100644 index 0000000000000000000000000000000000000000..e1efa3f4c200f37a4d1c1769ca6db1d31d27f62a --- /dev/null +++ b/procedures/setFileProperties.sql @@ -0,0 +1,73 @@ +/* + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +DROP PROCEDURE IF EXISTS setFileProperties; +DELIMITER // +/** + * Update file properties. + * + * If ENTITY_VERSIONING is enabled the old file properties are moved to + * `archive_files`. + * + * Parameters + * ---------- + * EntityID : VARCHAR(255) + * The file's id. + * FilePath : TEXT + * Path of the file in the internal file system. If NULL, an existing file + * entity is simply deleted. + * FileSize : BIGINT UNSIGNED + * Size of the file in bytes. + * FileHash : VARCHAR(255) + * A Sha512 Hash of the file. + */ +CREATE PROCEDURE setFileProperties ( + in EntityID VARCHAR(255), + in FilePath TEXT, + in FileSize BIGINT UNSIGNED, + in FileHash VARCHAR(255) +) +BEGIN + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + DECLARE IVersion INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID FROM entity_ids WHERE id = EntityID; + + IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN + SELECT max(e._iversion) INTO IVersion + FROM entity_version AS e + WHERE e.entity_id = InternalEntityID; + + INSERT INTO archive_files (file_id, path, size, hash, + _iversion) + SELECT file_id, path, size, hash, IVersion AS _iversion + FROM files + WHERE file_id = InternalEntityID; + END IF; + + DELETE FROM files WHERE file_id = InternalEntityID; + + IF FilePath IS NOT NULL THEN + INSERT INTO files (file_id, path, size, hash) + VALUES (InternalEntityID, FilePath, FileSize, unhex(FileHash)); + END IF; + +END // +DELIMITER ; diff --git a/procedures/setPassword.sql b/procedures/setPassword.sql deleted file mode 100644 index 0302dd69c6eae34fe38a0dfcc8ed56a8046ec809..0000000000000000000000000000000000000000 --- a/procedures/setPassword.sql +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ** header v3.0 - * This file is a part of the LinkAhead Project. - * - * Copyright (C) 2018 Research Group Biomedical Physics, - * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header - */ - - -DROP PROCEDURE IF EXISTS db_5_0.setPassword; -delimiter // - -CREATE PROCEDURE db_5_0.setPassword(in EntityID INT UNSIGNED, in NewPassword VARCHAR(255)) -BEGIN - - - DELETE FROM passwords where entity_id=EntityID; - INSERT INTO passwords (entity_id, password) VALUES (EntityID, NewPassword); - -END; -// -delimiter ; diff --git a/procedures/updateEntity.sql b/procedures/updateEntity.sql index 96a140b2354a3ba17e8c7c6a5783729c4dbee21a..bdfe05b92cccb7c424e1a5b70759a15c7d9612dc 100644 --- a/procedures/updateEntity.sql +++ b/procedures/updateEntity.sql @@ -1,11 +1,10 @@ /* - * ** header v3.0 * This file is a part of the LinkAhead Project. * * Copyright (C) 2018 Research Group Biomedical Physics, * Max-Planck-Institute for Dynamics and Self-Organization Göttingen - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -19,8 +18,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ DROP PROCEDURE IF EXISTS db_5_0.updateEntity; @@ -34,11 +31,11 @@ delimiter // * Selects the new version identifier for the entity. */ CREATE PROCEDURE db_5_0.updateEntity( - in EntityID INT UNSIGNED, + in EntityID VARCHAR(255), in EntityName VARCHAR(255), in EntityDescription TEXT, in EntityRole VARCHAR(255), - in Datatype VARCHAR(255), + in DatatypeID VARCHAR(255), in Collection VARCHAR(255), in ACL VARBINARY(65525)) BEGIN @@ -48,20 +45,23 @@ BEGIN DECLARE ParentVersion VARBINARY(255) DEFAULT NULL; DECLARE Transaction VARBINARY(255) DEFAULT NULL; DECLARE OldIVersion INT UNSIGNED DEFAULT NULL; + DECLARE InternalEntityID INT UNSIGNED DEFAULT NULL; + + SELECT internal_id INTO InternalEntityID from entity_ids WHERE id = EntityID; call entityACL(ACLID, ACL); IF is_feature_config("ENTITY_VERSIONING", "ENABLED") THEN SELECT max(_iversion) INTO OldIVersion FROM entity_version - WHERE entity_id = EntityID; + WHERE entity_id = InternalEntityID; -- move old data to archives INSERT INTO archive_entities (id, description, role, acl, _iversion) SELECT e.id, e.description, e.role, e.acl, OldIVersion FROM entities AS e - WHERE e.id = EntityID; + WHERE e.id = InternalEntityID; INSERT INTO archive_data_type (domain_id, entity_id, property_id, datatype, _iversion) @@ -70,7 +70,7 @@ BEGIN FROM data_type AS e WHERE e.domain_id = 0 AND e.entity_id = 0 - AND e.property_id = EntityID; + AND e.property_id = InternalEntityID; INSERT INTO archive_collection_type (domain_id, entity_id, property_id, collection, _iversion) @@ -79,16 +79,16 @@ BEGIN FROM collection_type as e WHERE e.domain_id = 0 AND e.entity_id = 0 - AND e.property_id = EntityID; + AND e.property_id = InternalEntityID; SET Transaction = @SRID; SELECT e.version INTO ParentVersion FROM entity_version as e - WHERE e.entity_id = EntityID + WHERE e.entity_id = InternalEntityID AND e._iversion = OldIVersion; CALL insert_single_child_version( - EntityID, Hash, Version, + InternalEntityID, Hash, Version, ParentVersion, Transaction); END IF; @@ -96,34 +96,33 @@ BEGIN SET e.description = EntityDescription, e.role=EntityRole, e.acl = ACLID - WHERE e.id = EntityID; + WHERE e.id = InternalEntityID; -- clean up primary name, because updateEntity might be called without a -- prior call to deleteEntityProperties. DELETE FROM name_data - WHERE domain_id = 0 AND entity_id = EntityID AND property_id = 20; + WHERE domain_id = 0 AND entity_id = InternalEntityID AND property_id = 20; IF EntityName IS NOT NULL THEN INSERT INTO name_data (domain_id, entity_id, property_id, value, status, pidx) - VALUES (0, EntityID, 20, EntityName, "FIX", 0); + VALUES (0, InternalEntityID, 20, EntityName, "FIX", 0); END IF; DELETE FROM data_type - WHERE domain_id=0 AND entity_id=0 AND property_id=EntityID; + WHERE domain_id=0 AND entity_id=0 AND property_id=InternalEntityID; DELETE FROM collection_type - WHERE domain_id=0 AND entity_id=0 AND property_id=EntityID; + WHERE domain_id=0 AND entity_id=0 AND property_id=InternalEntityID; - IF Datatype IS NOT NULL THEN + IF DatatypeID IS NOT NULL THEN INSERT INTO data_type (domain_id, entity_id, property_id, datatype) - SELECT 0, 0, EntityID, - ( SELECT entity_id FROM name_data WHERE domain_id = 0 - AND property_id = 20 AND value = Datatype LIMIT 1 ); + SELECT 0, 0, InternalEntityID, + ( SELECT internal_id FROM entity_ids WHERE id = DatatypeID ); IF Collection IS NOT NULL THEN INSERT INTO collection_type (domain_id, entity_id, property_id, collection) - SELECT 0, 0, EntityID, Collection; + SELECT 0, 0, InternalEntityID, Collection; END IF; END IF; diff --git a/tests/example.dump.sql b/tests/example.dump.sql index 014e480e7a5423093b2a9f74b14cec4a7e54ad70..1fdb96dbf1e3fc35aba9b7d9ac7ad5e2fb45ad40 100644 --- a/tests/example.dump.sql +++ b/tests/example.dump.sql @@ -563,31 +563,6 @@ INSERT INTO `passwd` VALUES ('guest','3fe82ca86837d4f9ff765d2d4265ded96843314936 /*!40000 ALTER TABLE `passwd` ENABLE KEYS */; UNLOCK TABLES; --- --- Table structure for table `passwords` --- - -DROP TABLE IF EXISTS `passwords`; -/*!40101 SET @saved_cs_client = @@character_set_client */; -/*!40101 SET character_set_client = utf8 */; -CREATE TABLE `passwords` ( - `entity_id` int(10) unsigned NOT NULL COMMENT 'User ID.', - `password` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT 'Password.', - PRIMARY KEY (`entity_id`), - CONSTRAINT `use_entity_id_entity` FOREIGN KEY (`entity_id`) REFERENCES `entities` (`id`) -) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -/*!40101 SET character_set_client = @saved_cs_client */; - --- --- Dumping data for table `passwords` --- - -LOCK TABLES `passwords` WRITE; -/*!40000 ALTER TABLE `passwords` DISABLE KEYS */; -INSERT INTO `passwords` VALUES (98,'37d7bd8a833261b4e4653644ee0a065f522b92b3738ca9ae2cb43a83844bf352c4a59c386a44965997a508c61988c9484c093775027425091d6d3d435c3c0e0c'),(99,'37d7bd8a833261b4e4653644ee0a065f522b92b3738ca9ae2cb43a83844bf352c4a59c386a44965997a508c61988c9484c093775027425091d6d3d435c3c0e0c'); -/*!40000 ALTER TABLE `passwords` ENABLE KEYS */; -UNLOCK TABLES; - -- -- Table structure for table `permissions` -- @@ -668,7 +643,7 @@ CREATE TABLE `reference_data` ( LOCK TABLES `reference_data` WRITE; /*!40000 ALTER TABLE `reference_data` DISABLE KEYS */; -INSERT INTO `reference_data` VALUES (0,243,233,119,'REPLACEMENT',6),(0,243,119,240,'FIX',0),(0,243,232,120,'REPLACEMENT',7),(0,243,120,241,'FIX',0),(0,243,234,121,'REPLACEMENT',8),(0,243,121,242,'FIX',0),(0,265,255,230,'FIX',3),(0,265,256,243,'FIX',4),(0,265,257,119,'REPLACEMENT',6),(0,265,119,262,'FIX',0),(0,265,260,120,'REPLACEMENT',7),(0,265,120,263,'FIX',0),(0,265,259,121,'REPLACEMENT',8),(0,265,121,264,'FIX',0),(0,270,257,119,'REPLACEMENT',1),(0,270,260,120,'REPLACEMENT',2),(0,271,257,119,'REPLACEMENT',1),(0,271,119,268,'FIX',0),(0,271,260,120,'REPLACEMENT',2),(0,271,120,269,'FIX',0),(0,271,267,266,'FIX',3),(0,273,222,271,'FIX',1),(0,277,222,230,'FIX',1),(0,279,222,243,'FIX',1),(0,278,222,265,'FIX',1),(0,276,222,99,'FIX',1),(0,230,221,119,'REPLACEMENT',3),(0,230,119,226,'FIX',0),(0,230,220,120,'REPLACEMENT',4),(0,230,120,227,'FIX',0),(0,230,218,121,'REPLACEMENT',5),(0,230,121,228,'FIX',0),(0,230,219,122,'REPLACEMENT',6),(0,230,122,229,'FIX',0); +INSERT INTO `reference_data` VALUES (0,243,233,119,'REPLACEMENT',6),(0,243,119,240,'FIX',0),(0,243,232,120,'REPLACEMENT',7),(0,243,120,241,'FIX',0),(0,243,234,121,'REPLACEMENT',8),(0,243,121,242,'FIX',0),(0,265,255,230,'FIX',3),(0,265,256,243,'FIX',4),(0,265,257,119,'REPLACEMENT',6),(0,265,119,262,'FIX',0),(0,265,260,120,'REPLACEMENT',7),(0,265,120,263,'FIX',0),(0,265,259,121,'REPLACEMENT',8),(0,265,121,264,'FIX',0),(0,270,257,119,'REPLACEMENT',1),(0,270,260,120,'REPLACEMENT',2),(0,271,257,119,'REPLACEMENT',1),(0,271,119,268,'FIX',0),(0,271,260,120,'REPLACEMENT',2),(0,271,120,269,'FIX',0),(0,271,267,266,'FIX',3),(0,273,222,271,'FIX',1),(0,277,222,230,'FIX',1),(0,279,222,243,'FIX',1),(0,278,222,265,'FIX',1),(0,230,221,119,'REPLACEMENT',3),(0,230,119,226,'FIX',0),(0,230,220,120,'REPLACEMENT',4),(0,230,120,227,'FIX',0),(0,230,218,121,'REPLACEMENT',5),(0,230,121,228,'FIX',0),(0,230,219,122,'REPLACEMENT',6),(0,230,122,229,'FIX',0); /*!40000 ALTER TABLE `reference_data` ENABLE KEYS */; UNLOCK TABLES; @@ -2783,34 +2758,6 @@ BEGIN INSERT IGNORE INTO units_lin_con (signature_from, signature_to, a, b_dividend, b_divisor, c) VALUES (signature_from, signature_to, a, b_dividend, b_divisor, c); -END ;; -DELIMITER ; -/*!50003 SET sql_mode = @saved_sql_mode */ ; -/*!50003 SET character_set_client = @saved_cs_client */ ; -/*!50003 SET character_set_results = @saved_cs_results */ ; -/*!50003 SET collation_connection = @saved_col_connection */ ; -/*!50003 DROP PROCEDURE IF EXISTS `insertUser` */; -/*!50003 SET @saved_cs_client = @@character_set_client */ ; -/*!50003 SET @saved_cs_results = @@character_set_results */ ; -/*!50003 SET @saved_col_connection = @@collation_connection */ ; -/*!50003 SET character_set_client = utf8mb4 */ ; -/*!50003 SET character_set_results = utf8mb4 */ ; -/*!50003 SET collation_connection = utf8mb4_general_ci */ ; -/*!50003 SET @saved_sql_mode = @@sql_mode */ ; -/*!50003 SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ; -DELIMITER ;; -CREATE DEFINER=`caosdb`@`%` PROCEDURE `insertUser`(in Name VARCHAR(255), in Password VARCHAR(255)) -BEGIN - - -INSERT INTO entities (name, role, acl) VALUES (Name, 'USER', 0); - -SET @LAST_UserID = LAST_INSERT_ID(); - -INSERT INTO passwords VALUES (@LAST_UserID, Password); - -Select @LAST_UserID as UserID; - END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; @@ -3168,29 +3115,6 @@ BEGIN SELECT collection as collection_override, NULL as name_override, NULL as desc_override, NULL as type_override, entity_id, property_id from collection_type where domain_id=DomainID and entity_id=EntityID; -END ;; -DELIMITER ; -/*!50003 SET sql_mode = @saved_sql_mode */ ; -/*!50003 SET character_set_client = @saved_cs_client */ ; -/*!50003 SET character_set_results = @saved_cs_results */ ; -/*!50003 SET collation_connection = @saved_col_connection */ ; -/*!50003 DROP PROCEDURE IF EXISTS `setPassword` */; -/*!50003 SET @saved_cs_client = @@character_set_client */ ; -/*!50003 SET @saved_cs_results = @@character_set_results */ ; -/*!50003 SET @saved_col_connection = @@collation_connection */ ; -/*!50003 SET character_set_client = utf8mb4 */ ; -/*!50003 SET character_set_results = utf8mb4 */ ; -/*!50003 SET collation_connection = utf8mb4_general_ci */ ; -/*!50003 SET @saved_sql_mode = @@sql_mode */ ; -/*!50003 SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ; -DELIMITER ;; -CREATE DEFINER=`caosdb`@`%` PROCEDURE `setPassword`(in EntityID INT UNSIGNED, in NewPassword VARCHAR(255)) -BEGIN - - - DELETE FROM passwords where entity_id=EntityID; - INSERT INTO passwords (entity_id, password) VALUES (EntityID, NewPassword); - END ;; DELIMITER ; /*!50003 SET sql_mode = @saved_sql_mode */ ; diff --git a/tests/test_autotap.sql b/tests/test_autotap.sql index ebec7304fd753261775a40a8ccfd8e765136ec0e..6d62a0ced953fddc7afe1ccc06d45ef339e8f47e 100644 --- a/tests/test_autotap.sql +++ b/tests/test_autotap.sql @@ -38,7 +38,11 @@ SELECT tap.has_schema('_caosdb_schema_unit_tests',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','archive_isa',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','archive_isa','utf8_unicode_ci',''); +-- ******* +-- Collation testing of tables fails for uca1400 collations, see upstream issue: +-- https://github.com/hepabolu/mytap/issues/58 +-- ******* +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','archive_isa','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','archive_isa','InnoDB',''); -- COLUMNS @@ -116,7 +120,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','archive_isa','archive_isa_i -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','collection_type',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','collection_type','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','collection_type','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','collection_type','InnoDB',''); -- COLUMNS @@ -155,8 +159,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','collection_type','collection' SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','collection_type','collection','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','collection_type','collection','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','collection_type','collection',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','collection_type','collection','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','collection_type','collection','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','collection_type','collection','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','collection_type','collection','utf8mb4_uca1400_as_ci',''); -- INDEXES SELECT tap.indexes_are('_caosdb_schema_unit_tests','collection_type','`domain_id`,`entity_id`,`property_id`',''); @@ -208,7 +212,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','collection_type','collectio -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','data_type',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','data_type','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','data_type','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','data_type','InnoDB',''); -- COLUMNS @@ -300,7 +304,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','data_type','datatype_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','date_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','date_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','date_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','date_data','InnoDB',''); -- COLUMNS @@ -348,8 +352,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','date_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','date_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','date_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','date_data','status','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','date_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','date_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','date_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','date_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN date_data.pidx @@ -398,7 +402,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','date_data','date_ov_forkey_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','datetime_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','datetime_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','datetime_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','datetime_data','InnoDB',''); -- COLUMNS @@ -437,8 +441,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','datetime_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','datetime_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','datetime_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','datetime_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','datetime_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','datetime_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','datetime_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','datetime_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN datetime_data.pidx @@ -505,7 +509,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','datetime_data','dat_propert -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','desc_overrides',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','desc_overrides','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','desc_overrides','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','desc_overrides','InnoDB',''); -- COLUMNS @@ -544,8 +548,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','desc_overrides','description' SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','desc_overrides','description','text',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','desc_overrides','description','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','desc_overrides','description','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','desc_overrides','description','utf8mb4_uca1400_as_ci',''); -- INDEXES SELECT tap.indexes_are('_caosdb_schema_unit_tests','desc_overrides','`desc_ov_dom_ent_idx`',''); @@ -590,7 +594,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','desc_overrides','desc -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','double_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','double_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','double_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','double_data','InnoDB',''); -- COLUMNS @@ -638,8 +642,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','double_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','double_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','double_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','double_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','double_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','double_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','double_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','double_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN double_data.pidx @@ -697,7 +701,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','double_data','dou_property_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','entities',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entities','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entities','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entities','InnoDB',''); -- COLUMNS @@ -718,17 +722,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','entities','description',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','description','text',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','entities','description','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','entities','description','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','description','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','description','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','description','utf8mb4_uca1400_as_ci',''); -- COLUMN entities.role SELECT tap.has_column('_caosdb_schema_unit_tests','entities','role',''); -SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'DOMAIN\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\')',''); +SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','entities','role','enum(\'RECORDTYPE\',\'RECORD\',\'FILE\',\'_REPLACEMENT\',\'PROPERTY\',\'DATATYPE\',\'ROLE\',\'QUERYTEMPLATE\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','entities','role','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','entities','role',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','role','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','role','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','entities','role','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','entities','role','utf8mb4_uca1400_as_ci',''); -- COLUMN entities.acl @@ -760,7 +764,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','entities','`id`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','entity_acl',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_acl','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_acl','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entity_acl','InnoDB',''); -- COLUMNS @@ -807,7 +811,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','entity_acl','`id`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','enum_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','enum_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','enum_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','enum_data','InnoDB',''); -- COLUMNS @@ -855,8 +859,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','enum_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','enum_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','enum_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','enum_data','status','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','enum_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','enum_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','enum_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','enum_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN enum_data.pidx @@ -905,7 +909,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','enum_data','enum_ov_forkey_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','files',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','files','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','files','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','files','InnoDB',''); -- COLUMNS @@ -926,8 +930,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','files','path',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','files','path','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','files','path','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','files','path',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','path','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','path','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','files','path','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','files','path','utf8mb4_uca1400_as_ci',''); -- COLUMN files.size @@ -977,7 +981,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','files','`file_id`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','integer_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','integer_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','integer_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','integer_data','InnoDB',''); -- COLUMNS @@ -1025,8 +1029,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','integer_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','integer_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','integer_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','integer_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','integer_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','integer_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','integer_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','integer_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN integer_data.pidx @@ -1084,7 +1088,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','integer_data','int_property -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','isa_cache',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','isa_cache','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','isa_cache','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','isa_cache','InnoDB',''); -- COLUMNS @@ -1114,8 +1118,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','isa_cache','rpath',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','isa_cache','rpath','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','isa_cache','rpath','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','isa_cache','rpath',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','isa_cache','rpath','utf8mb4_uca1400_as_ci',''); -- CONSTRAINTS SELECT tap.constraints_are('_caosdb_schema_unit_tests','isa_cache','`PRIMARY`,`isa_cache_child_entity`,`isa_cache_parent_entity`',''); @@ -1145,7 +1149,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','isa_cache','`child`,`parent`,` -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','name_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','name_data','InnoDB',''); -- COLUMNS @@ -1184,8 +1188,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_data','value',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_data','value','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_data','value','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_data','value',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','value','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','value','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','value','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','value','utf8mb4_uca1400_as_ci',''); -- COLUMN name_data.status @@ -1193,8 +1197,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN name_data.pidx @@ -1266,7 +1270,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','name_data','name_data_prope -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','name_overrides',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_overrides','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','name_overrides','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','name_overrides','InnoDB',''); -- COLUMNS @@ -1305,8 +1309,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','name_overrides','name',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','name_overrides','name','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','name_overrides','name','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','name_overrides','name','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_overrides','name','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_overrides','name','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','name_overrides','name','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','name_overrides','name','utf8mb4_uca1400_as_ci',''); -- INDEXES SELECT tap.indexes_are('_caosdb_schema_unit_tests','name_overrides','`name_ov_dom_ent_idx`',''); @@ -1351,7 +1355,7 @@ SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','name_overrides','name -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','null_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','null_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','null_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','null_data','InnoDB',''); -- COLUMNS @@ -1390,8 +1394,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','null_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','null_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','null_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','null_data','status','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','null_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','null_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','null_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','null_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN null_data.pidx @@ -1440,7 +1444,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','null_data','null_forkey_pro -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','passwd',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','passwd','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','passwd','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','passwd','InnoDB',''); -- COLUMNS @@ -1470,8 +1474,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','passwd','alg',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','passwd','alg','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','passwd','alg','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','passwd','alg','\'SHA-512\'',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','passwd','alg','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','passwd','alg','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','passwd','alg','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','passwd','alg','utf8mb4_uca1400_as_ci',''); -- COLUMN passwd.it @@ -1505,7 +1509,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','passwd','`principal`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','permissions',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','permissions','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','permissions','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','permissions','InnoDB',''); -- COLUMNS @@ -1526,8 +1530,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','permissions','permissions','' SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','permissions','permissions','mediumtext',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','permissions','permissions','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','permissions','permissions',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','permissions','permissions','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','permissions','permissions','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','permissions','permissions','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','permissions','permissions','utf8mb4_uca1400_as_ci',''); -- CONSTRAINTS SELECT tap.constraints_are('_caosdb_schema_unit_tests','permissions','`PRIMARY`,`perm_name_roles`',''); @@ -1550,7 +1554,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','permissions','`role`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','query_template_def',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','query_template_def','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','query_template_def','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','query_template_def','InnoDB',''); -- COLUMNS @@ -1571,8 +1575,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','query_template_def','definiti SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','query_template_def','definition','mediumtext',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','query_template_def','definition','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','query_template_def','definition',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','query_template_def','definition','utf8mb4_uca1400_as_ci',''); -- CONSTRAINTS SELECT tap.constraints_are('_caosdb_schema_unit_tests','query_template_def','`PRIMARY`,`query_template_def_ibfk_1`',''); @@ -1595,7 +1599,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','query_template_def','query_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','reference_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','reference_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','reference_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','reference_data','InnoDB',''); -- COLUMNS @@ -1643,8 +1647,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','reference_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','reference_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','reference_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','reference_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','reference_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','reference_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','reference_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','reference_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN reference_data.pidx @@ -1722,7 +1726,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','reference_data','reference_ -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','roles',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','roles','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','roles','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','roles','InnoDB',''); -- COLUMNS @@ -1743,8 +1747,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','roles','description',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','roles','description','mediumtext',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','roles','description','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','roles','description','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','roles','description','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','roles','description','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','roles','description','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','roles','description','utf8mb4_uca1400_as_ci',''); -- CONSTRAINTS SELECT tap.constraints_are('_caosdb_schema_unit_tests','roles','`PRIMARY`',''); @@ -1760,7 +1764,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','roles','`name`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','stats',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','stats','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','stats','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','stats','InnoDB',''); -- COLUMNS @@ -1772,8 +1776,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','stats','name',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','stats','name','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','stats','name','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','stats','name',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','stats','name','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','stats','name','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','stats','name','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','stats','name','utf8mb4_uca1400_as_ci',''); -- COLUMN stats.value @@ -1798,7 +1802,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','stats','`name`',''); -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','text_data',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','text_data','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','text_data','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','text_data','InnoDB',''); -- COLUMNS @@ -1837,8 +1841,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','text_data','value',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','text_data','value','text',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','text_data','value','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','text_data','value',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','value','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','value','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','value','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','value','utf8mb4_uca1400_as_ci',''); -- COLUMN text_data.status @@ -1846,8 +1850,8 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','text_data','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','text_data','status','enum(\'OBLIGATORY\',\'RECOMMENDED\',\'SUGGESTED\',\'FIX\',\'REPLACEMENT\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','text_data','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','text_data','status',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','text_data','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','text_data','status','utf8mb4_uca1400_as_ci',''); -- COLUMN text_data.pidx @@ -1896,7 +1900,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','text_data','str_property_id -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','transaction_log',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','transaction_log','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','transaction_log','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','transaction_log','InnoDB',''); -- COLUMNS @@ -1908,17 +1912,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','transaction_log','transaction SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','transaction','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','transaction_log','transaction','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','transaction_log','transaction',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','transaction','utf8mb4_uca1400_as_ci',''); -- COLUMN transaction_log.entity_id SELECT tap.has_column('_caosdb_schema_unit_tests','transaction_log','entity_id',''); -SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','int(10) unsigned',''); +SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','transaction_log','entity_id','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','transaction_log','entity_id','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id',NULL,''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','transaction_log','entity_id','utf8mb4_bin',''); -- COLUMN transaction_log.username @@ -1970,7 +1974,7 @@ SELECT tap.is_indexed('_caosdb_schema_unit_tests','transaction_log','`entity_id` -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','units_lin_con',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','units_lin_con','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','units_lin_con','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','units_lin_con','InnoDB',''); -- COLUMNS @@ -2044,7 +2048,7 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','units_lin_con','`signature_fro -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','user_info',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_info','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_info','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','user_info','InnoDB',''); -- COLUMNS @@ -2083,17 +2087,17 @@ SELECT tap.has_column('_caosdb_schema_unit_tests','user_info','status',''); SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','status','enum(\'ACTIVE\',\'INACTIVE\')',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','user_info','status','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','user_info','status','\'INACTIVE\'',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','status','utf8',''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','utf8_unicode_ci',''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','status','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','status','utf8mb4_uca1400_as_ci',''); -- COLUMN user_info.entity SELECT tap.has_column('_caosdb_schema_unit_tests','user_info','entity',''); -SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','int(10) unsigned',''); +SELECT tap.col_column_type_is('_caosdb_schema_unit_tests','user_info','entity','varchar(255)',''); SELECT tap.col_extra_is('_caosdb_schema_unit_tests','user_info','entity','',''); SELECT tap.col_default_is('_caosdb_schema_unit_tests','user_info','entity','NULL',''); -SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity',NULL,''); -SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity',NULL,''); +SELECT tap.col_charset_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4',''); +SELECT tap.col_collation_is('_caosdb_schema_unit_tests','user_info','entity','utf8mb4_bin',''); -- INDEXES SELECT tap.indexes_are('_caosdb_schema_unit_tests','user_info','`subject_entity`',''); @@ -2105,7 +2109,7 @@ SELECT tap.index_is_type('_caosdb_schema_unit_tests','user_info','subject_entity SELECT tap.is_indexed('_caosdb_schema_unit_tests','user_info','`entity`',''); -- CONSTRAINTS -SELECT tap.constraints_are('_caosdb_schema_unit_tests','user_info','`PRIMARY`,`subjects_ibfk_1`',''); +SELECT tap.constraints_are('_caosdb_schema_unit_tests','user_info','`PRIMARY`,`subjects_ibfk_2`',''); -- CONSTRAINT user_info.PRIMARY @@ -2115,17 +2119,17 @@ SELECT tap.col_is_pk('_caosdb_schema_unit_tests','user_info','`realm`,`name`','' -- CONSTRAINT user_info.subjects_ibfk_1 -SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1',''); -SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','FOREIGN KEY',''); -SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT',''); -SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_1','RESTRICT',''); +SELECT tap.has_constraint('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2',''); +SELECT tap.constraint_type_is('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','FOREIGN KEY',''); +SELECT tap.fk_on_delete('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT',''); +SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_info','subjects_ibfk_2','RESTRICT',''); -- *************************************************************** -- TABLE _caosdb_schema_unit_tests.user_roles -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','user_roles',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_roles','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','user_roles','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','user_roles','InnoDB',''); -- COLUMNS @@ -2179,7 +2183,7 @@ SELECT tap.fk_on_update('_caosdb_schema_unit_tests','user_roles','user_roles_ibf -- *************************************************************** SELECT tap.has_table('_caosdb_schema_unit_tests','entity_version',''); -SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_version','utf8_unicode_ci',''); +-- SELECT tap.table_collation_is('_caosdb_schema_unit_tests','entity_version','utf8mb4_uca1400_as_ci',''); SELECT tap.table_engine_is('_caosdb_schema_unit_tests','entity_version','InnoDB',''); -- COLUMNS @@ -2509,20 +2513,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getFileIdByPa SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','getFileIdByPath','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','getFileIdByPath','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.getRole - -SELECT tap.has_procedure('_caosdb_schema_unit_tests','getRole',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','getRole','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','getRole','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','getRole','CONTAINS SQL',''); - --- PROCEDURES _caosdb_schema_unit_tests.initAutoIncrement - -SELECT tap.has_procedure('_caosdb_schema_unit_tests','initAutoIncrement',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','initAutoIncrement','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','initAutoIncrement','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','initAutoIncrement','CONTAINS SQL',''); - -- PROCEDURES _caosdb_schema_unit_tests.initBackReference SELECT tap.has_procedure('_caosdb_schema_unit_tests','initBackReference',''); @@ -2586,13 +2576,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insertLinCon' SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insertLinCon','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insertLinCon','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.insertUser - -SELECT tap.has_procedure('_caosdb_schema_unit_tests','insertUser',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insertUser','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insertUser','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insertUser','CONTAINS SQL',''); - -- PROCEDURES _caosdb_schema_unit_tests.intersectTable SELECT tap.has_procedure('_caosdb_schema_unit_tests','intersectTable',''); @@ -2649,12 +2632,12 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','raiseWarning' SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','raiseWarning','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','raiseWarning','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.registerSubdomain +-- PROCEDURES _caosdb_schema_unit_tests.registerReplacementIds -SELECT tap.has_procedure('_caosdb_schema_unit_tests','registerSubdomain',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerSubdomain','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerSubdomain','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerSubdomain','CONTAINS SQL',''); +SELECT tap.has_procedure('_caosdb_schema_unit_tests','registerReplacementIds',''); +SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerReplacementIds','NO',''); +SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerReplacementIds','DEFINER',''); +SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerReplacementIds','CONTAINS SQL',''); -- PROCEDURES _caosdb_schema_unit_tests.initSubProperty @@ -2677,13 +2660,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','registerTempT SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','registerTempTableName','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','registerTempTableName','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.retrieveDatatype - -SELECT tap.has_procedure('_caosdb_schema_unit_tests','retrieveDatatype',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','retrieveDatatype','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','retrieveDatatype','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','retrieveDatatype','CONTAINS SQL',''); - -- PROCEDURES _caosdb_schema_unit_tests.retrieveEntityParents SELECT tap.has_procedure('_caosdb_schema_unit_tests','retrieveEntityParents',''); @@ -2691,13 +2667,6 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','retrieveEntit SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','retrieveEntityParents','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','retrieveEntityParents','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.setPassword - -SELECT tap.has_procedure('_caosdb_schema_unit_tests','setPassword',''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','setPassword','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','setPassword','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','setPassword','CONTAINS SQL',''); - -- PROCEDURES _caosdb_schema_unit_tests.insertIsa SELECT tap.has_procedure('_caosdb_schema_unit_tests','insertIsa',''); @@ -2754,12 +2723,5 @@ SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','insert_single SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','insert_single_child_version','DEFINER',''); SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','insert_single_child_version','CONTAINS SQL',''); --- PROCEDURES _caosdb_schema_unit_tests.delete_all_entity_versions - -SELECT tap.has_procedure('_caosdb_schema_unit_tests', 'delete_all_entity_versions', ''); -SELECT tap.procedure_is_deterministic('_caosdb_schema_unit_tests','delete_all_entity_versions','NO',''); -SELECT tap.procedure_security_type_is('_caosdb_schema_unit_tests','delete_all_entity_versions','DEFINER',''); -SELECT tap.procedure_sql_data_access_is('_caosdb_schema_unit_tests','delete_all_entity_versions','CONTAINS SQL',''); - CALL tap.finish(); ROLLBACK; diff --git a/tests/test_entity_versioning.sql b/tests/test_entity_versioning.sql index f54e7d0526e47654fd1f06643b71b0b6d1aadc81..eb01deb2ec2a25b9117c3855c129d814f77f552b 100644 --- a/tests/test_entity_versioning.sql +++ b/tests/test_entity_versioning.sql @@ -1,9 +1,8 @@ /** - * ** header v3.0 * This file is a part of the LinkAhead Project. * - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,8 +16,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ USE _caosdb_schema_unit_tests; @@ -34,6 +31,13 @@ CALL tap.no_plan(); -- SETUP +SET @EntityID1 = 10001; +SET @EntityID2 = 10002; +SET @EntityID3 = 10003; +SET @EntityID4 = 10004; +SET @EntityID5 = 10005; +SET @EntityID6 = 10006; + -- Disable versioning because we want to test `insert_single_child_version` -- separately from `insertEntity` but the former is called inside the latter -- when versioning is enabled. @@ -46,22 +50,22 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES ("SRIDblieb", 3456, 4576, "you", "home"); DELETE FROM entities WHERE id > 99; CALL entityACL(@ACLID1, "{acl1}"); -CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); -SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName"; +CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); +SELECT entity_id INTO @InternalEntityID1 FROM name_data WHERE value="EntityName"; -- TEST insert_single_child_version SELECT count(*) INTO @x FROM entity_version; SELECT tap.eq(@x, 0, "no versions there yet"); -CALL insert_single_child_version(@EntityID, "hashbla", "versionbla", NULL, "SRIDbla"); +CALL insert_single_child_version(@InternalEntityID1, "hashbla", "versionbla", NULL, "SRIDbla"); SELECT _ipparent INTO @x from entity_version WHERE version="versionbla"; SELECT tap.eq(@x, NULL, "no parent for the first version"); -- add a second version SELECT count(*) INTO @x FROM entity_version; SELECT tap.eq(@x, 1, "one version there already"); -CALL insert_single_child_version(@EntityID, "hashblub", "versionblub", "versionbla", "SRIDblub"); +CALL insert_single_child_version(@InternalEntityID1, "hashblub", "versionblub", "versionbla", "SRIDblub"); SELECT _ipparent INTO @x from entity_version WHERE version="versionblub"; SELECT tap.eq(@x, 1, "the original entity is the parent"); @@ -72,7 +76,7 @@ SELECT tap.eq(@x, 2, "two versions there already"); CALL tap._assert_throws( concat("CALL insert_single_child_version(", - @EntityID, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'), + @InternalEntityID1, ', "hashblieb", "versionblieb", "non-existing-parent", "SRIDBlieb")'), "non existing parent throws"); SELECT count(*) INTO @x FROM entity_version; @@ -80,21 +84,24 @@ SELECT tap.eq(@x, 2, "still two versions there"); -- TEST get_primary_parent_version -SELECT tap.eq(get_primary_parent_version(@EntityID, "versionblub"), "versionbla", "returns correct parent for versionblub"); -SELECT tap.eq(get_primary_parent_version(@EntityID, "versionbla"), NULL, "versionbla has no parent"); +SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionblub"), "versionbla", "returns correct parent for versionblub"); +SELECT tap.eq(get_primary_parent_version(@EntityID1, "versionbla"), NULL, "versionbla has no parent"); +-- Reactivate when versioning's FORGET is being implemented -- TEST delete_all_entity_versions SELECT count(*) INTO @x FROM entity_version; SELECT tap.ok(@x > 0, "several versions in the table"); -CALL delete_all_entity_versions(@EntityID); +-- CALL delete_all_entity_versions(@EntityID1); +DELETE FROM entity_version WHERE entity_id = @InternalEntityID1; SELECT count(*) INTO @x FROM entity_version; SELECT tap.eq(@x, 0, "no versions there any more"); -- TEARDOWN clean up DELETE FROM name_data WHERE entity_id > 99; +DELETE FROM entity_ids WHERE internal_id > 99; DELETE FROM entities WHERE id > 99; -- ##################################################################### @@ -108,20 +115,20 @@ SELECT tap.eq(@x, 0, "before insertEntity, no versions there"); -- TEST insertEntity - should produce a version w/o parent SET @SRID = "SRIDbla"; -CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); -SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName"; -CALL insertEntity("ParentName", "ParentDesc", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); +SELECT entity_id INTO @InternalEntityID2 FROM name_data WHERE value="EntityName"; +CALL insertEntity(@EntityID3, "ParentName", "ParentDesc", "RECORDTYPE", "{acl1}"); SELECT entity_id INTO @ParentID FROM name_data WHERE value="ParentName"; -CALL insertIsa(@EntityID, @ParentID); -CALL insertEntityProperty(0, @EntityID, 17, "null_data", NULL, NULL, +CALL insertIsa(@EntityID2, @EntityID3); +CALL insertEntityProperty(0, @EntityID2, 17, "null_data", NULL, NULL, "RECOMMENDED", NULL, "DescOverride", NULL, NULL, 0); -SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID; +SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2; SELECT tap.eq(@x, 1, "after insertEntity, a version is there."); -SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent is NULL; +SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent is NULL; SELECT tap.eq(@x, 1, "after insertEntity, the _iversion number is 1."); -SELECT _ipparent INTO @x from entity_version WHERE entity_id = @EntityID; +SELECT _ipparent INTO @x from entity_version WHERE entity_id = @InternalEntityID2; SELECT tap.eq(@x, NULL, "no parent for the freshly inserted entity"); SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update") FROM archive_entities; @@ -129,14 +136,14 @@ SELECT tap.eq(count(*), 0, "no entity in archive_entities before first update") -- TEST updateEntity - should produce a version with a parent SET @SRID = "SRIDblub"; -CALL deleteEntityProperties(@EntityID); -CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}"); -SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID; +CALL deleteEntityProperties(@EntityID2); +CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl1}"); +SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2; SELECT tap.eq(@x, 2, "after updateEntity, a second version is there."); -SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1; +SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1; SELECT tap.eq(@x, 2, "after updateEntity, the _iversion number incremented."); -SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 1; +SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 1; SELECT tap.eq(@x, 1, "after updateEntity, the _pparent points to the first version"); SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities") @@ -144,60 +151,60 @@ SELECT tap.eq(count(*), 1, "after updateEntity, one entity in archive_entities") -- TEST get_version_history -CALL get_version_history(@EntityID); +CALL get_version_history(@EntityID2); -- TEST retrieveEntity SELECT version INTO @x FROM entity_version - WHERE entity_id = @EntityID + WHERE entity_id = @InternalEntityID2 AND _iversion = 2; -CALL retrieveEntity(@EntityID, NULL); -CALL retrieveEntity(@EntityID, "non-existing-version"); -CALL retrieveEntity(@EntityID, get_head_version(@EntityID)); -CALL retrieveEntity(@EntityID, @x); +CALL retrieveEntity(@EntityID2, NULL); +CALL retrieveEntity(@EntityID2, "non-existing-version"); +CALL retrieveEntity(@EntityID2, get_head_version(@EntityID2)); +CALL retrieveEntity(@EntityID2, @x); -- TEST retrieveEntityParents -CALL retrieveEntityParents(@EntityID, NULL); -CALL retrieveEntityParents(@EntityID, "non-existing-version"); -CALL retrieveEntityParents(@EntityID, get_head_version(@EntityID)); -CALL retrieveEntityParents(@EntityID, @x); +CALL retrieveEntityParents(@EntityID2, NULL); +CALL retrieveEntityParents(@EntityID2, "non-existing-version"); +CALL retrieveEntityParents(@EntityID2, get_head_version(@EntityID2)); +CALL retrieveEntityParents(@EntityID2, @x); -- TEST retrieveEntityProperties -CALL retrieveEntityProperties(0, @EntityID, NULL); -CALL retrieveEntityProperties(0, @EntityID, "non-existing-version"); -CALL retrieveEntityProperties(0, @EntityID, get_head_version(@EntityID)); -CALL retrieveEntityProperties(0, @EntityID, @x); +CALL retrieveEntityProperties(0, @EntityID2, NULL); +CALL retrieveEntityProperties(0, @EntityID2, "non-existing-version"); +CALL retrieveEntityProperties(0, @EntityID2, get_head_version(@EntityID2)); +CALL retrieveEntityProperties(0, @EntityID2, @x); -- TEST retrieveOverrides -CALL retrieveOverrides(0, @EntityID, NULL); -CALL retrieveOverrides(0, @EntityID, "non-existing-version"); -CALL retrieveOverrides(0, @EntityID, get_head_version(@EntityID)); -CALL retrieveOverrides(0, @EntityID, @x); +CALL retrieveOverrides(0, @EntityID2, NULL); +CALL retrieveOverrides(0, @EntityID2, "non-existing-version"); +CALL retrieveOverrides(0, @EntityID2, get_head_version(@EntityID2)); +CALL retrieveOverrides(0, @EntityID2, @x); -- and 2nd updateEntity SET @SRID = "SRIDblieb"; -CALL updateEntity(@EntityID, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}"); -SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID; +CALL updateEntity(@EntityID2, "EntityName", "EntityDesc", "RECORDTYPE", NULL, NULL, "{acl1}"); +SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2; SELECT tap.eq(@x, 3, "after 2nd updateEntity, a 3rd version is there."); -SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @EntityID and _ipparent = 2; +SELECT _iversion INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _ipparent = 2; SELECT tap.eq(@x, 3, "after 2nd updateEntity, the _iversion number incremented again."); -SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @EntityID and _iversion = 3; +SELECT _ipparent INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2 and _iversion = 3; SELECT tap.eq(@x, 2, "after 2nd updateEntity, the _pparent points to the 2nd version"); -SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @EntityID AND _ipparent = 2; +SELECT tap.eq("SRIDblieb", srid, "correct transaction was stored") FROM entity_version WHERE entity_id = @InternalEntityID2 AND _ipparent = 2; -- TEST deleteEntity - should remove all versions -CALL deleteIsa(@EntityID); -CALL deleteEntity(@EntityID); -SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @EntityID; +CALL deleteIsa(@EntityID3); +CALL deleteEntity(@EntityID2); +SELECT count(*) INTO @x FROM entity_version WHERE entity_id = @InternalEntityID2; SELECT tap.eq(@x, 0, "no versions there any more"); -CALL deleteEntity(@ParentID); +CALL deleteEntity(@EntityID3); CALL tap.finish(); ROLLBACK; @@ -217,21 +224,21 @@ DELETE FROM transactions; -- insert entity without versioning DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING"; CALL entityACL(@ACLID1, "{acl1}"); -CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID4, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); SELECT count(*) INTO @NumOfEntities FROM entities; -SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName"; +SELECT entity_id INTO @InternalEntityID4 FROM name_data WHERE value="EntityName"; SET @TheUser = "TheUser"; -- used to identify the matching entry in transaction_log -- fill transaction_log: one entity with two updates (and one insert) and another entity with insert and delete. INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds, nanos) -- the first entry is the one which is be found by _fix_unversioned VALUES - ("Update", @EntityID, @TheUser, "CaosDB", 23458, 254), + ("Update", @InternalEntityID4, @TheUser, "CaosDB", 23458, 254), -- the rest is dummy data - ("Update", @EntityID, "OtherUser", "CaosDB", 2345, 633), -- not the latest transaction - ("Insert", @EntityID, "OtherUser", "CaosDB", 245, 633), -- not the latest transaction - ("Insert", @EntityID + 1, @TheUser, "CaosDB", 2325, 653), -- not the right entity, inserted before our target - ("Delete", @EntityID + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target + ("Update", @InternalEntityID4, "OtherUser", "CaosDB", 2345, 633), -- not the latest transaction + ("Insert", @InternalEntityID4, "OtherUser", "CaosDB", 245, 633), -- not the latest transaction + ("Insert", @InternalEntityID4 + 1, @TheUser, "CaosDB", 2325, 653), -- not the right entity, inserted before our target + ("Delete", @InternalEntityID4 + 1, @TheUser, "CaosDB", 232526, 653); -- not the right entity, deleted after our target SELECT tap.eq(COUNT(*), 5, "five entries in transaction_log") FROM transaction_log; @@ -251,11 +258,11 @@ SELECT tap.eq(COUNT(*), 2, "after _fix_unversioned, one entry for our test entity in transactions, one for the standard entities.") FROM transactions; -SELECT tap.eq(entity_id, @EntityID, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99; +SELECT tap.eq(entity_id, @InternalEntityID4, "versioned entity has correct id") FROM entity_version WHERE entity_id > 99; SELECT tap.ok(srid IS NOT NULL, "srid was generated and user/time matches entries from transaction_log") FROM transactions AS t JOIN transaction_log AS l ON (l.seconds = t.seconds AND l.nanos = t.nanos AND l.username = t.username AND l.realm = t.realm) - WHERE l.entity_id = @EntityID AND l.username = @TheUser; + WHERE l.entity_id = @InternalEntityID4444 AND l.username = @TheUser; CALL tap.finish(); ROLLBACK; @@ -275,18 +282,18 @@ DELETE FROM transactions; DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING"; CALL entityACL(@ACLID1, "{acl1}"); -CALL insertEntity("EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}"); -CALL insertEntity("EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID5, "EntityName1", "EntityDesc1", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID6, "EntityName2", "EntityDesc2", "RECORDTYPE", "{acl1}"); SELECT count(*) INTO @NumOfEntities FROM entities; -SELECT entity_id INTO @EntityID1 FROM name_data WHERE value="EntityName1"; -SELECT entity_id INTO @EntityID2 FROM name_data WHERE value="EntityName2"; +SELECT entity_id INTO @InternalEntityID5 FROM name_data WHERE value="EntityName1"; +SELECT entity_id INTO @InternalEntityID6 FROM name_data WHERE value="EntityName2"; INSERT INTO transaction_log (transaction, entity_id, username, realm, seconds, nanos) -- the first entry is the one which will be found by _fix_unversioned - VALUES ("INSERT", @EntityID1, "User", "CaosDB", 10000, 250), - ("INSERT", @EntityID2, "User", "CaosDB", 10000, 250), - ("UPDATE", @EntityID2, "User", "CaosDB", 20000, 250); + VALUES ("INSERT", @InternalEntityID5, "User", "CaosDB", 10000, 250), + ("INSERT", @InternalEntityID6, "User", "CaosDB", 10000, 250), + ("UPDATE", @InternalEntityID6, "User", "CaosDB", 20000, 250); SELECT tap.eq(COUNT(*), 3, "three entries in transaction_log") FROM transaction_log; @@ -309,10 +316,10 @@ SELECT tap.eq(COUNT(*), 3, SELECT tap.eq(seconds, 10000, "version seconds of entity 1 is correct") FROM entity_version AS v JOIN transactions AS t - ON (v.srid = t.srid) WHERE v.entity_id = @EntityID1; + ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID1; SELECT tap.eq(seconds, 20000, "version seconds of entity 2 is correct") FROM entity_version AS v JOIN transactions AS t - ON (v.srid = t.srid) WHERE v.entity_id = @EntityID2; + ON (v.srid = t.srid) WHERE v.entity_id = @InternalEntityID2; CALL tap.finish(); ROLLBACK; diff --git a/tests/test_insert_update_delete.sql b/tests/test_insert_update_delete.sql index a11b05e3d9a72d6038800adebf5b73c699c2a2b8..ff1e4ec3acc6fe0121ff168279fe7659e05a914c 100644 --- a/tests/test_insert_update_delete.sql +++ b/tests/test_insert_update_delete.sql @@ -1,9 +1,31 @@ +/** + * This file is a part of the CaosDB Project. + * + * Copyright (C) 2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ USE _caosdb_schema_unit_tests; BEGIN; CALL tap.no_plan(); -- SETUP +SET @EntityID1 = 10001; +SET @EntityID2 = 10002; + -- Disable versioning and only test the non-versioning behavior DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING"; @@ -16,31 +38,31 @@ SELECT entity_id into @TextDatatypeID FROM name_data WHERE value ="TEXT"; -- TEST insertEntity SELECT tap.eq(COUNT(id), 0, "No entities") FROM entities WHERE id>=100; -CALL insertEntity("EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID1, "EntityName", "EntityDesc", "RECORDTYPE", "{acl1}"); SELECT tap.eq(COUNT(entity_id), 1, "Entity has been inserted") FROM name_data WHERE value="EntityName"; -SELECT entity_id INTO @EntityID FROM name_data WHERE value="EntityName"; -SELECT tap.ok(@EntityID >= 100, "EntityID greater 99"); +SELECT entity_id INTO @InternalEntityID FROM name_data WHERE value="EntityName"; +SELECT tap.ok(@InternalEntityID >= 100, "EntityID greater 99"); SELECT tap.eq(acl, @ACLID1, "correct acl id had been assigned") - FROM entities WHERE id=@EntityID; + FROM entities WHERE id=@InternalEntityID; -- TEST insertEntityProperty -CALL insertEntity("AProperty", "APropDesc", "PROPERTY", "{acl1}"); -SELECT entity_id INTO @PropID FROM name_data WHERE value="AProperty"; -INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @PropID, @TextDatatypeID); +CALL insertEntity(@EntityID2, "AProperty", "APropDesc", "PROPERTY", "{acl1}"); +SELECT entity_id INTO @InternalPropertyID FROM name_data WHERE value="AProperty"; +INSERT INTO data_type (domain_id, entity_id, property_id, datatype) VALUES (0, 0, @InternalPropertyID, @TextDatatypeID); SELECT COUNT(*) INTO @x FROM null_data; SELECT tap.eq(@x, 0, "No data in null_data table"); -CALL insertEntityProperty(0, @EntityID, @PropID, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0); +CALL insertEntityProperty(0, @EntityID1, @EntityID2, "null_data", NULL, NULL, "RECOMMENDED", NULL, NULL, NULL, NULL, 0); SELECT COUNT(*) INTO @x FROM null_data; SELECT tap.eq(@x, 1, "One row in null_data table"); -- TEST updateEntity -CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}"); +CALL updateEntity(@EntityID1, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}"); SELECT tap.eq(COUNT(entity_id), 0, "Old Entity name not present") FROM name_data WHERE value="EntityName"; @@ -48,21 +70,21 @@ SELECT tap.eq(COUNT(entity_id), 1, "Entity name has been updated") FROM name_data WHERE value="NewEntityName"; SELECT tap.eq(acl, @ACLID2, "acl has been updated") - FROM entities WHERE id=@EntityID; + FROM entities WHERE id=@InternalEntityID; -- CALL updateEntity again an update the Name -CALL updateEntity(@EntityID, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}"); -CALL updateEntity(@EntityID, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}"); +CALL updateEntity(@EntityID2, "NewerEntityName", "NewerEntityDesc", "RECORD", NULL, NULL, "{acl2}"); +CALL updateEntity(@EntityID2, "NewEntityName", "NewEntityDesc", "RECORD", NULL, NULL, "{acl2}"); -- TEST deleteEntityProperties -CALL deleteEntityProperties(@EntityID); +CALL deleteEntityProperties(@EntityID1); SELECT COUNT(*) INTO @x FROM null_data; SELECT tap.eq(@x, 0, "data removed from null_data table"); -- TEST deleteEntity -CALL deleteEntity(@EntityID); -CALL deleteEntity(@PropID); +CALL deleteEntity(@EntityID1); +CALL deleteEntity(@EntityID2); SELECT COUNT(id) INTO @x FROM entities WHERE id>100; SELECT tap.eq(@x, 0, "entity deleted"); diff --git a/tests/test_issues.sql b/tests/test_issues.sql index ea82fbdd3369c7c8cb1bdda6eee0242cd3231075..768d090245fc6a6a280377959e2c326a7f60ec59 100644 --- a/tests/test_issues.sql +++ b/tests/test_issues.sql @@ -1,9 +1,9 @@ /** - * ** header v3.0 * This file is a part of the LinkAhead Project. * - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> * Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> + * Copyright (C) 2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,14 +17,16 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ USE _caosdb_schema_unit_tests; BEGIN; CALL tap.no_plan(); +SET @EntityID1 = 10001; +SET @EntityID2 = 10002; +SET @EntityID3 = 10003; +SET @EntityID4 = 10004; -- ######################################################################## -- TEST Issues from https://gitlab.com/linkahead/linkahead-mysqlbackend/-/issues @@ -42,23 +44,18 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES CALL entityACL(@ACLID1, "{acl1}"); -- Insert entities and obtain IDs -CALL insertEntity("A", "Desc A", "RECORDTYPE", "{acl1}"); -CALL insertEntity("B", "Desc B", "RECORDTYPE", "{acl1}"); -CALL insertEntity("C", "Desc C", "RECORDTYPE", "{acl1}"); -CALL insertEntity("rec", "Desc rec", "RECORD", "{acl1}"); - -SELECT entity_id INTO @ID_A FROM name_data WHERE value="A"; -SELECT entity_id INTO @ID_B FROM name_data WHERE value="B"; -SELECT entity_id INTO @ID_C FROM name_data WHERE value="C"; -SELECT entity_id INTO @ID_rec FROM name_data WHERE value="rec"; +CALL insertEntity(@EntityID1, "A", "Desc A", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID2, "B", "Desc B", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID3, "C", "Desc C", "RECORDTYPE", "{acl1}"); +CALL insertEntity(@EntityID4, "rec", "Desc rec", "RECORD", "{acl1}"); -- Insert is-a relationships -CALL insertIsA(@ID_A, @ID_B); -CALL insertIsA(@ID_B, @ID_C); -CALL insertIsA(@ID_rec, @ID_A); +CALL insertIsA(@EntityID1, @EntityID2); +CALL insertIsA(@EntityID2, @EntityID3); +CALL insertIsA(@EntityID4, @EntityID1); -- Try to delete last child -- leads to failure in issue #21 -CALL deleteIsa(@ID_rec); +CALL deleteIsa(@EntityID4); ROLLBACK; diff --git a/tests/test_reference_values.sql b/tests/test_reference_values.sql index 1226229786d511824cd975053151ed78b7b91a61..1b77f7cb984742e40b50ad287789073042ad6daf 100644 --- a/tests/test_reference_values.sql +++ b/tests/test_reference_values.sql @@ -1,9 +1,8 @@ /** - * ** header v3.0 * This file is a part of the LinkAhead Project. * - * Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> - * Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> + * Copyright (C) 2020,2023 IndiScale GmbH <info@indiscale.com> + * Copyright (C) 2020,2023 Timm Fitschen <t.fitschen@indiscale.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -17,8 +16,6 @@ * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - * ** end header */ USE _caosdb_schema_unit_tests; @@ -37,9 +34,14 @@ INSERT INTO transactions (srid,seconds,nanos,username,realm) VALUES ("SRIDbla", 1234, 2345, "me", "home"), ("SRIDblub", 2345, 3465, "me", "home"), ("SRIDblieb", 3456, 4576, "you", "home"); -SET @EntityID=99; +SET @EntityID="99"; SET @PropertyID=11; SET @Value=50; +SET @SRID="SRIDbla"; +call insertEntity(@EntityID, "TheName", "TheDesc", "RecordType", "{}"); +call insertEntity(@Value, "RefValue", "ValueDesc", "Record", "{}"); +SELECT internal_id INTO @InternalEntityID FROM entity_ids WHERE id = @EntityID; +SELECT internal_id INTO @InternalValueID FROM entity_ids WHERE id = @Value; -- switch off versioning DELETE FROM feature_config WHERE _key = "ENTITY_VERSIONING"; @@ -49,16 +51,16 @@ CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value, NULL, "FIX", NULL, NULL, NULL, NULL, 0); -- TODO switch expected/actual -SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data; -SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data; -SELECT tap.eq(11, property_id, "property ok") FROM reference_data; -SELECT tap.eq(50, value, "value ok") FROM reference_data; +SELECT tap.eq("0", domain_id, "domain ok") FROM reference_data; +SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data; +SELECT tap.eq("11", property_id, "property ok") FROM reference_data; +SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data; SELECT tap.eq("FIX", status, "status ok") FROM reference_data; SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data; -SELECT tap.eq(NULL, value_iversion, "value_iversion ok") FROM reference_data; +SELECT tap.eq(NULL, value_iversion, "value_iversion ok 1") FROM reference_data; -- clean up -DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99; +DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalValueID; -- ##################################################################### -- TODO TEST insertEntityProperty with Versioning @@ -69,39 +71,43 @@ INSERT INTO feature_config (_key, _value) VALUES ("ENTITY_VERSIONING", "ENABLED" -- TEST insertEntityProperty with Versioning - REFERENCE HEAD -SET @VALUE="50"; CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value, NULL, "FIX", NULL, NULL, NULL, NULL, 0); -- TODO switch expected/actual SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data; -SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data; +SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data; SELECT tap.eq(11, property_id, "property ok") FROM reference_data; -SELECT tap.eq(50, value, "value ok") FROM reference_data; +SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data; SELECT tap.eq("FIX", status, "status ok") FROM reference_data; SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data; -SELECT tap.eq(value_iversion, NULL, "value_iversion ok") FROM reference_data; +SELECT tap.eq(value_iversion, NULL, "value_iversion ok 2") FROM reference_data; -DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99; +DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalEntityID; -- TEST insertEntityProperty with Versioning - Reference version -CALL insert_single_child_version(50, "hashbla", "versionbla", NULL, "SRIDbla"); -CALL insert_single_child_version(50, "hashblub", "versionblub", "versionbla", "SRIDblub"); - -SET @VALUE="50@versionbla"; +SELECT * FROM entity_ids; +SELECT * FROM entity_version; +SELECT e.version INTO @ParentVersion + FROM entity_version as e + WHERE e.entity_id = @InternalValueID + AND e._iversion = 1; +CALL insert_single_child_version(@InternalValueID, "hashblub", "versionblub", @ParentVersion, "SRIDblub"); + +SET @VALUE=CONCAT("50@", @ParentVersion); CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value, NULL, "FIX", NULL, NULL, NULL, NULL, 0); SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data; -SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data; +SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data; SELECT tap.eq(11, property_id, "property ok") FROM reference_data; -SELECT tap.eq(50, value, "value ok") FROM reference_data; +SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data; SELECT tap.eq("FIX", status, "status ok") FROM reference_data; SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data; -SELECT tap.eq(value_iversion, "1", "value_iversion ok") FROM reference_data; +SELECT tap.eq(value_iversion, "1", "value_iversion ok 3") FROM reference_data; -DELETE FROM reference_data WHERE domain_id=0 AND entity_id=99; +DELETE FROM reference_data WHERE domain_id=0 AND entity_id=@InternalEntityID; SET @VALUE="50@versionblub"; CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value, @@ -109,12 +115,12 @@ CALL insertEntityProperty(0, @EntityID, @PropertyID, "reference_data", @Value, -- TODO switch expected/actual SELECT tap.eq(0, domain_id, "domain ok") FROM reference_data; -SELECT tap.eq(99, entity_id, "entity ok") FROM reference_data; +SELECT tap.eq(@InternalEntityID, entity_id, "entity ok") FROM reference_data; SELECT tap.eq(11, property_id, "property ok") FROM reference_data; -SELECT tap.eq(50, value, "value ok") FROM reference_data; +SELECT tap.eq(@InternalValueID, value, "value ok") FROM reference_data; SELECT tap.eq("FIX", status, "status ok") FROM reference_data; SELECT tap.eq("0", pidx, "pidx ok") FROM reference_data; -SELECT tap.eq(value_iversion, "2", "value_iversion ok") FROM reference_data; +SELECT tap.eq(value_iversion, "2", "value_iversion ok 4") FROM reference_data; -- invalid values throw errors diff --git a/utils/backup.sh b/utils/backup.sh index 6f2872ef49b5f33698b723d0b3d8b2e05f14e588..7b0da2284578be303f852e664702ca033c754356 100755 --- a/utils/backup.sh +++ b/utils/backup.sh @@ -56,7 +56,7 @@ function backup() { fi echo "Dumping database $database to $backupfile ..." - $MYSQLDUMP_CMD $(get_mysql_args_nodb) --opt --default-character-set=utf8 \ + $MYSQLDUMP_CMD $(get_db_args_nodb) --opt --default-character-set=utf8 \ --routines "$database" > "$backupfile" success diff --git a/utils/helpers.sh b/utils/helpers.sh index 1bb13f5bd4f4d8c57b152428acc07869fa4e0274..ff4b189bffeabf467e0725de9a4b62fe72cd6bf3 100644 --- a/utils/helpers.sh +++ b/utils/helpers.sh @@ -2,9 +2,9 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen -# Copyright (C) 2019, 2020 Daniel Hornung (d.hornung@indiscale.com) +# Copyright (C) 2019, 2020, 2024 Daniel Hornung (d.hornung@indiscale.com) # Copyright (C) 2020 Henrik tom Wörden -# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2020, 2024 IndiScale GmbH <info@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -34,7 +34,7 @@ function mysql_execute { #TODO is it meaningful that here always the database user is used??? set -e - $MYSQL_CMD $(get_db_args) -e "$1" + $MYSQL_CMD $(get_db_args) -e "$@" ret=${PIPESTATUS[0]} if [ "$ret" -ne 0 ]; then failure "MYSQL ERROR" @@ -52,47 +52,31 @@ function mysql_execute_file { fi } - -function get_mysql_args { - echo "$(get_mysql_args_nodb) --database=$DATABASE_NAME" -} - +# Return the arguments from `get_db_args_nodb` and additionally the database name as +# `--database=mydatabasename`. function get_db_args { echo "$(get_db_args_nodb) --database=$DATABASE_NAME" } +# Return arguments for user, password, host, port and additional options in MYSQL_OPTS. +# +# For example, the output may be: +# --user=myuser --password=mypassword --host=example.com --port=1234 --other --option function get_db_args_nodb { - if [ "$DATABASE_USER" ]; then - mysql_con_arguments="--user=$DATABASE_USER" + if [ -n "$MYSQL_USER" ]; then + mysql_con_arguments="--user=$MYSQL_USER" fi - if [ "$DATABASE_USER_PW" ]; then - mysql_con_arguments="$mysql_con_arguments --password=$DATABASE_USER_PW" + if [ -n "$MYSQL_USER_PASSWORD" ]; then + mysql_con_arguments="$mysql_con_arguments --password=$MYSQL_USER_PASSWORD" fi - if [[ "$MYSQL_HOST" && ( "$MYSQL_HOST" != "localhost" ) ]]; then + if [ -n "$MYSQL_HOST" ] && [ "$MYSQL_HOST" != "localhost" ]; then mysql_con_arguments="$mysql_con_arguments --host=$MYSQL_HOST" - if [ "$MYSQL_PORT" ]; then - mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT" - fi fi - echo $mysql_con_arguments -} - -function get_mysql_args_nodb { - if [ "$LOGIN_PATH" ]; then - mysql_con_arguments="--login-path=$LOGIN_PATH" - else - if [ "$MYSQL_USER" ]; then - mysql_con_arguments="--user=$MYSQL_USER" - fi - if [ "$MYSQL_USER_PASSWORD" ]; then - mysql_con_arguments="$mysql_con_arguments --password=$MYSQL_USER_PASSWORD" - fi - if [[ "$MYSQL_HOST" && ( "$MYSQL_HOST" != "localhost" ) ]]; then - mysql_con_arguments="$mysql_con_arguments --host=$MYSQL_HOST" - if [ "$MYSQL_PORT" ]; then - mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT" - fi - fi + if [ -n "$MYSQL_PORT" ] && [ "$MYSQL_PORT" != "3306" ]; then + mysql_con_arguments="$mysql_con_arguments --port=$MYSQL_PORT" + fi + if [ -n "$MYSQL_OPTS" ] ; then + mysql_con_arguments="$mysql_con_arguments $MYSQL_OPTS" fi echo $mysql_con_arguments } diff --git a/utils/load_settings.sh b/utils/load_settings.sh index 44d8f2d630270727a3a7cbd08f4b3ee037e6a7d7..8531113afa5f670400988f92692a59a031c91a11 100644 --- a/utils/load_settings.sh +++ b/utils/load_settings.sh @@ -2,9 +2,9 @@ # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen -# Copyright (C) 2019, 2020 Daniel Hornung (d.hornung@indiscale.com) +# Copyright (C) 2019, 2020, 2024 Daniel Hornung <d.hornung@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden -# Copyright (C) 2020 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2020, 2024 IndiScale GmbH <info@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -62,9 +62,12 @@ export MYSQL_CMD export MYSQLDUMP_CMD export MYSQLADMIN_CMD export MYSQL_CONFIG_EDITOR_CMD + export MYSQL_HOST export MYSQL_PORT export MYSQL_USER +export MYSQL_OPTS + export DATABASE_NAME export DATABASE_USER export DATABASE_USER_PW diff --git a/utils/make_db b/utils/make_db index ea301acc6228344feb7f8b4f7e97a55cd1919048..c7f94fd2d57944758cb48f0aedb2ac2672ec16d3 100755 --- a/utils/make_db +++ b/utils/make_db @@ -1,10 +1,9 @@ #!/bin/bash -# ** header v3.0 # This file is a part of the LinkAhead Project. # -# Copyright (C) 2021 Indiscale GmbH <info@indiscale.com> -# Copyright (C) 2019, 2020, 2021 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (C) 2021, 2024 Indiscale GmbH <info@indiscale.com> +# Copyright (C) 2019, 2020, 2021, 2024 Daniel Hornung <d.hornung@indiscale.com> # Copyright (C) 2020 Timm Fitschen <t.fitschen@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> # Copyright (C) 2020 IndiScale <info@indiscale.com> @@ -22,7 +21,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header # Although some sanity checks are performed, this script still allows lots of SQL injection # possibilities. @@ -87,7 +85,7 @@ function _install_unit_test_database () { if _db_exists "$DATABASE_NAME"; then echo "using $DATABASE_NAME" else - sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_mysql_args_nodb) + sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_db_args_nodb) # create test user grant @@ -113,7 +111,7 @@ function _setup_mytap() { pushd libs > /dev/null unzip -u mytap*.zip > /dev/null pushd mytap*/ > /dev/null - $MYSQL_CMD $(get_mysql_args_nodb) < mytap.sql > /dev/null || exit 1 + $MYSQL_CMD $(get_db_args_nodb) < mytap.sql > /dev/null || exit 1 popd > /dev/null rm -r mytap*/ popd > /dev/null @@ -129,13 +127,28 @@ name in your .config file " exit 0 fi - sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_mysql_args_nodb) + sed "s/db_5_0/$DATABASE_NAME/g" "$INSTALL_SQL_FILE" | $MYSQL_CMD $(get_db_args_nodb) +} + +function sanity_check() { + trap "$(shopt -po errexit)" RETURN + set +e + echo -n "running sanity checks ..." + msg="$($MYSQL_CMD $(get_db_args) < "utils/sanity_check.sql" 2>/dev/null)" + code="$?" + if [ "$code" -eq "0" ] ; then + echo " [OK]" + else + echo " [FAILED]" + echo "$msg" + exit 1 + fi } # Inserts the dump (arg 1) into the database function restore_db() { SQL_FILE="$1" - $MYSQL_CMD $(get_mysql_args) < "$SQL_FILE" + $MYSQL_CMD $(get_db_args) < "$SQL_FILE" cat <<EOF If this is not the same SQL server where the SQL dump was originally created from, make sure that a user with sufficient permissions exists. Note that you @@ -144,7 +157,7 @@ EOF } function test-connection() { - $MYSQL_CMD $(get_mysql_args_nodb) -e "select 0;" + $MYSQL_CMD $(get_db_args_nodb) -e "select 0;" } # Creates a user and grants it sufficient rights. @@ -168,7 +181,7 @@ function grant() { if [[ $1 = "--strict" ]] ; then for host in ${DATABASE_USER_HOST_LIST//,/ } ; do CMD="SELECT COUNT(*) FROM mysql.user WHERE user='${DATABASE_USER}' AND host='${host}';" - [[ $($MYSQL_CMD $(get_mysql_args_nodb) -s -N -e "$CMD") = 0 ]] || { + [[ $($MYSQL_CMD $(get_db_args_nodb) -s -N -e "$CMD") = 0 ]] || { echo "The user '${DATABASE_USER}@${host}' is already in the database." echo "Please use another user or delete it, e.g. with" echo "'mysql -u ${MYSQL_USER} -p -e \"DROP USER ${DATABASE_USER}@${host};\"'" @@ -182,7 +195,7 @@ function grant() { # FIXME Are all these permissions necessary? See # https://gitlab.indiscale.com/caosdb/src/caosdb-mysqlbackend/-/issues/28 "Default # installation target does not work for existing databases" - $MYSQL_CMD $(get_mysql_args_nodb) <<EOF + $MYSQL_CMD $(get_db_args_nodb) <<EOF CREATE USER IF NOT EXISTS '$DATABASE_USER'@'$host' identified by '$DATABASE_USER_PW'; GRANT USAGE ON *.* TO '$DATABASE_USER'@'$host'; @@ -197,16 +210,16 @@ EOF function drop() { DROPDB="$1" for host in ${DATABASE_USER_HOST_LIST//,/ } ; do - $MYSQL_CMD $(get_mysql_args_nodb) -e "DROP USER '${DATABASE_USER}'@'${host}';" || true + $MYSQL_CMD $(get_db_args_nodb) -e "DROP USER '${DATABASE_USER}'@'${host}';" || true done - "$MYSQLADMIN_CMD" $(get_mysql_args_nodb) -f drop "$DROPDB" + "$MYSQLADMIN_CMD" $(get_db_args_nodb) -f drop "$DROPDB" } # Returns 0 or non-zero, depending on whether the database exists already. # Optional parameter: [DATABASE_NAME], else $DATABASE_NAME is used. function _db_exists() { - $MYSQL_CMD $(get_mysql_args_nodb) -D "${1-${DATABASE_NAME}}" -e "show tables;" > /dev/null 2>&1 \ + $MYSQL_CMD $(get_db_args_nodb) -D "${1-${DATABASE_NAME}}" -e "show tables;" > /dev/null 2>&1 \ && return 0 || return 1 } @@ -235,7 +248,7 @@ function grant-permission() { fi cmd="SELECT COUNT(1) from roles where name='${role}';" - count=$($MYSQL_CMD $(get_mysql_args) -AN -e "$cmd") + count=$($MYSQL_CMD $(get_db_args) -AN -e "$cmd") if [[ $count == "0" ]]; then echo "Role not found!" exit 1 @@ -244,7 +257,7 @@ function grant-permission() { cmd="INSERT INTO permissions (role, permissions) VALUE ('${role}', '${permissions}')" cmd+="ON DUPLICATE KEY UPDATE role='${role}', permissions='${permissions}'" cmd+=";" - $MYSQL_CMD $(get_mysql_args) -e "$cmd" + $MYSQL_CMD $(get_db_args) -e "$cmd" } @@ -256,5 +269,6 @@ case $1 in "test-connection") test-connection ;; "install_db") install_db ;; "restore_db") restore_db $2 ;; + "sanity_check") sanity_check ;; *) echo "Unknown action: $1"; exit 32 esac diff --git a/utils/patch_header.sh b/utils/patch_header.sh index 76896b067960f67a101bfa3954bbdecb4f41b31d..c7d25ae3f21ccbba30658182572177847d5610a7 100644 --- a/utils/patch_header.sh +++ b/utils/patch_header.sh @@ -1,12 +1,10 @@ -# -# ** header v3.0 # This file is a part of the LinkAhead Project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen -# Copyright (C) 2019, 2020 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (C) 2019, 2020, 2025 Daniel Hornung <d.hornung@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> -# Copyright (C) 2020 IndiScale <info@indiscale.com> +# Copyright (C) 2020, 2025 IndiScale <info@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,12 +19,20 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header -# ############################################################################### # header for patch scripts # ############################################################################### +# +# This file defines the following functions (see below for more detailed descriptions): +# +# - check_version_or_exit: Check if the stored version is as expected. +# - update_version: Set the stored version. +# - dump_table: Store table content into a file. +# - redo_table: Apply the table content stored by dump_table. +# +# This file also sets the `errexit` option (`set -e`). +# set -e @@ -63,7 +69,7 @@ configuration make file. Notable examples are: - DATABASE_USER_PW EOF - ) + ) function _print_help() { echo -e "$USAGE" @@ -115,21 +121,51 @@ done if [ -n "$PATCH" ]; then echo -ne "applying patch $PATCH to $DATABASE_NAME ... " fi -# @param $1: db version string, e.g. v2.0.0 -# @return: 0 on success, 1 on failure -function check_version { + +# usage: check_version_or_exit version +# +# Check if the version string is as expected. Otherwise, `exit 0`. +# +# Arguments +# --------- +# +# version: str +# The expected database version string, e.g. 'v2.0.0' +# +# Returns +# ------- +# +# 0 on success +function check_version_or_exit { local version=$($MYSQL_CMD $(get_db_args) -B -e "Select CaosDBVersion();") - if [[ "$(echo $version | sed 's/^CaosDBVersion()\s//')" = "$1" ]]; then + local version="$(echo $version | sed 's/^CaosDBVersion()\s//')" + if [[ "$version" = "$1" ]]; then return 0 fi uptodate } -# @param $1: new version string +# Deprecated name, call "check_version_or_exit" directly instead. +function check_version { + check_version_or_exit "$1" +} + +# usage: update_version version +# +# Set the version string. +# +# Arguments +# --------- +# +# version: str +# The new database version string, e.g. 'v2.0.0' function update_version { mysql_execute "DROP FUNCTION IF EXISTS CaosDBVersion; CREATE FUNCTION CaosDBVersion() RETURNS VARCHAR(255) DETERMINISTIC RETURN '$1';" } +# usage: dump_table table +# +# Dump the table given in the argument into file "caosdb.<table>.<OLD_VERSION>.dump.sql" function dump_table { if [[ -z $MYSQLDUMP_CMD ]]; then echo "Cannot find mysqldump program!" >&2 @@ -139,6 +175,9 @@ function dump_table { > ${DATABASE_NAME}.${1}.${OLD_VERSION}.dump.sql } +# usage: redo_table table +# +# Apply the dump from `dump_table` to the database. Takes the same argument. function redo_table { $MYSQL_CMD $(get_db_args) < ${DATABASE_NAME}.${1}.${OLD_VERSION}.dump.sql } diff --git a/utils/sanity_check.sql b/utils/sanity_check.sql new file mode 100644 index 0000000000000000000000000000000000000000..5e3d580cc386feb44b5e97269ac384c050d6cf84 --- /dev/null +++ b/utils/sanity_check.sql @@ -0,0 +1,121 @@ + + +DROP PROCEDURE IF EXISTS sanity_check; +delimiter // +CREATE PROCEDURE sanity_check() +sanityCheckBody: BEGIN + CREATE TEMPORARY TABLE expected_tables (table_name VARCHAR(255)); + INSERT INTO expected_tables (table_name) VALUES +("archive_collection_type"), +("archive_data_type"), +("archive_date_data"), +("archive_datetime_data"), +("archive_desc_overrides"), +("archive_double_data"), +("archive_entities"), +("archive_enum_data"), +("archive_files"), +("archive_integer_data"), +("archive_isa"), +("archive_name_data"), +("archive_name_overrides"), +("archive_null_data"), +("archive_query_template_def"), +("archive_reference_data"), +("archive_text_data"), +("collection_type"), +("data_type"), +("date_data"), +("datetime_data"), +("desc_overrides"), +("double_data"), +("entities"), +("entity_ids"), +("entity_acl"), +("entity_version"), +("enum_data"), +("feature_config"), +("files"), +("integer_data"), +("isa_cache"), +("name_data"), +("name_overrides"), +("null_data"), +("passwd"), +("permissions"), +("query_template_def"), +("reference_data"), +("roles"), +("stats"), +("text_data"), +("transaction_log"), +("transactions"), +("units_lin_con"), +("user_info"), +("user_roles") +; + +SELECT COUNT(WRONG) INTO @count_wrong FROM ( + SELECT l.table_name AS MATCHED, + r.table_name AS WRONG + FROM + expected_tables AS l + RIGHT OUTER JOIN + information_schema.tables AS r + ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) + WHERE r.table_schema = database() AND r.table_type != 'TEMPORARY' + ) + AS temp WHERE temp.MATCHED IS NULL; + +SELECT COUNT(MISSING) INTO @count_missing FROM ( + SELECT l.table_name AS MISSING, + r.table_name AS MATCHED + FROM + expected_tables AS l + LEFT OUTER JOIN + information_schema.tables AS r + ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) + WHERE r.table_schema = database() OR r.table_schema IS NULL + ) + AS temp WHERE temp.MATCHED IS NULL; + +IF @count_missing = 0 AND @count_wrong = 0 THEN + LEAVE sanityCheckBody; +END IF; + +SELECT "--------------"; +SELECT @count_missing AS "Number of missing tables"; + +SELECT MISSING AS "Missing tables" FROM ( + SELECT l.table_name AS MISSING, r.table_name AS MATCHED FROM + expected_tables AS l + LEFT OUTER JOIN + information_schema.tables AS r + ON (r.table_name COLLATE utf8_unicode_ci = l.table_name) + WHERE r.table_schema = database() OR r.table_schema IS NULL + ) + AS temp WHERE temp.MATCHED IS NULL; + +SELECT "--------------"; +SELECT @count_wrong AS "Number of tables which should not exist"; + +SELECT WRONG AS "Tables which should not exist" FROM ( + SELECT expec.table_name AS MATCHED, info.table_name AS WRONG FROM + expected_tables AS expec + RIGHT OUTER JOIN + information_schema.tables AS info + ON (info.table_name COLLATE utf8_unicode_ci = expec.table_name) + WHERE info.table_schema = database() and info.table_type != 'TEMPORARY' + ) + AS temp WHERE temp.MATCHED IS NULL; + +SELECT "--------------"; +SELECT "ERROR" from sanity_check_failed; + +END; +// +delimiter ; + +CALL sanity_check(); + +DROP PROCEDURE sanity_check; diff --git a/utils/update_sql_procedures.sh b/utils/update_sql_procedures.sh index bbbbc15b299cf24bcfa4c72da6a4e49534655e67..2fe1febfc7d5bbe45a8bc68c630e13d1cef6707f 100755 --- a/utils/update_sql_procedures.sh +++ b/utils/update_sql_procedures.sh @@ -1,13 +1,12 @@ #!/bin/bash # -# ** header v3.0 # This file is a part of the LinkAhead Project. # # Copyright (C) 2018 Research Group Biomedical Physics, # Max-Planck-Institute for Dynamics and Self-Organization Göttingen -# Copyright (C) 2020 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (C) 2020, 2024 Daniel Hornung <d.hornung@indiscale.com> # Copyright (C) 2020 Henrik tom Wörden <h.tomwoerden@indiscale.com> -# Copyright (C) 2020 IndiScale <info@indiscale.com> +# Copyright (C) 2020, 2024 IndiScale <info@indiscale.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -22,8 +21,6 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # -# ** end header -# # Updates all SQL procedures @@ -37,7 +34,7 @@ fi source $UTILSPATH/load_settings.sh source $UTILSPATH/helpers.sh -echo -n "updating procedures ... " +echo "Updating procedures ... " temp_proc_sql=$(mktemp --suffix=.sql) sed -e "s/db_5_0/$DATABASE_NAME/g" procedures/*.sql procedures/query/*.sql \ > "$temp_proc_sql"