diff --git a/.jupyter/test.ipynb b/.jupyter/test.ipynb index 9f8f1f23c6fc913491ce07ee3421b9dc84b9f1c6..7c276b67efa8dde9fe2e055e7b7b669244e8a5f8 100644 --- a/.jupyter/test.ipynb +++ b/.jupyter/test.ipynb @@ -13,7 +13,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 113, "metadata": { "pycharm": { "name": "#%%\n" @@ -64,7 +64,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 114, "metadata": { "pycharm": { "name": "#%%\n" @@ -116,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 115, "outputs": [], "source": [ "response = authentication.authenticate_user1({\n", @@ -155,13 +155,13 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 116, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'created': datetime.datetime(2022, 7, 26, 7, 57, 28, 27000, tzinfo=tzutc()),\n", + "{'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -174,7 +174,7 @@ " 'titles_after': None,\n", " 'titles_before': None,\n", " 'username': 'user'},\n", - " 'hash': '0ba17c47b0eec5cd73dd6a9164bed510b159191076dda38165906733a821cd16',\n", + " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", " 'id': 1,\n", " 'internal_name': 'fda-userdb-airquality',\n", " 'is_public': None,\n", @@ -212,13 +212,13 @@ }, { "cell_type": "code", - "execution_count": 42, + "execution_count": 117, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'created': datetime.datetime(2022, 7, 26, 7, 57, 28, 27000, tzinfo=tzutc()),\n", + "{'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -231,7 +231,7 @@ " 'titles_after': None,\n", " 'titles_before': None,\n", " 'username': 'user'},\n", - " 'hash': '0ba17c47b0eec5cd73dd6a9164bed510b159191076dda38165906733a821cd16',\n", + " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", " 'id': 1,\n", " 'internal_name': 'fda-userdb-airquality',\n", " 'is_public': None,\n", @@ -267,13 +267,13 @@ }, { "cell_type": "code", - "execution_count": 43, + "execution_count": 118, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'container': {'created': datetime.datetime(2022, 7, 26, 7, 57, 28, 27000, tzinfo=tzutc()),\n", + "{'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -286,12 +286,12 @@ " 'titles_after': None,\n", " 'titles_before': None,\n", " 'username': 'user'},\n", - " 'hash': '0ba17c47b0eec5cd73dd6a9164bed510b159191076dda38165906733a821cd16',\n", + " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", " 'id': 1,\n", " 'internal_name': 'fda-userdb-airquality',\n", " 'is_public': None,\n", " 'name': 'Airquality'},\n", - " 'created': datetime.datetime(2022, 7, 26, 7, 57, 34, 419000, tzinfo=tzutc()),\n", + " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -342,25 +342,25 @@ }, { "cell_type": "code", - "execution_count": 44, + "execution_count": 119, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'contact': None,\n", - " 'container': {'created': datetime.datetime(2022, 7, 26, 7, 57, 28, 27000, tzinfo=tzutc()),\n", + " 'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", " 'databases': None,\n", - " 'hash': '0ba17c47b0eec5cd73dd6a9164bed510b159191076dda38165906733a821cd16',\n", + " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", " 'id': 1,\n", " 'image': {'id': 1, 'repository': 'mariadb', 'tag': '10.5'},\n", " 'internal_name': 'fda-userdb-airquality',\n", " 'ip_address': None,\n", " 'is_public': None,\n", " 'name': 'Airquality',\n", - " 'port': 46090,\n", + " 'port': 35358,\n", " 'state': None},\n", - " 'created': datetime.datetime(2022, 7, 26, 7, 57, 34, 419000, tzinfo=tzutc()),\n", + " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'containers': None,\n", @@ -381,49 +381,49 @@ " 'exchange': 'airquality',\n", " 'id': 1,\n", " 'image': {'compiled': None,\n", - " 'date_formats': [{'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 320000, tzinfo=tzutc()),\n", + " 'date_formats': [{'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 747000, tzinfo=tzutc()),\n", " 'database_format': '%Y-%c-%d',\n", " 'example': '2022-01-30',\n", " 'has_time': False,\n", " 'id': 1,\n", " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 328000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 753000, tzinfo=tzutc()),\n", " 'database_format': '%d.%c.%Y',\n", " 'example': '30.01.2022',\n", " 'has_time': False,\n", " 'id': 2,\n", " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 332000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 756000, tzinfo=tzutc()),\n", " 'database_format': '%d.%c.%y',\n", " 'example': '30.01.22',\n", " 'has_time': False,\n", " 'id': 3,\n", " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 335000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 759000, tzinfo=tzutc()),\n", " 'database_format': '%c/%d/%Y',\n", " 'example': '01/30/2022',\n", " 'has_time': False,\n", " 'id': 4,\n", " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 338000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 762000, tzinfo=tzutc()),\n", " 'database_format': '%c/%d/%y',\n", " 'example': '01/30/22',\n", " 'has_time': False,\n", " 'id': 5,\n", " 'unix_format': 'yyyy-MM-dd'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 342000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 765000, tzinfo=tzutc()),\n", " 'database_format': '%Y-%c-%d %H:%i:%S.%f',\n", " 'example': '2022-01-30 13:44:25.0',\n", " 'has_time': True,\n", " 'id': 6,\n", " 'unix_format': 'yyyy-MM-dd HH:mm:ss.SSSSSS'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 344000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 767000, tzinfo=tzutc()),\n", " 'database_format': '%Y-%c-%d %H:%i:%S',\n", " 'example': '2022-01-30 13:44:25',\n", " 'has_time': True,\n", " 'id': 7,\n", " 'unix_format': 'yyyy-MM-dd HH:mm:ss'},\n", - " {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 347000, tzinfo=tzutc()),\n", + " {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 770000, tzinfo=tzutc()),\n", " 'database_format': '%d.%c.%Y %H:%i:%S',\n", " 'example': '30.01.2022 13:44:25',\n", " 'has_time': True,\n", @@ -492,13 +492,13 @@ }, { "cell_type": "code", - "execution_count": 45, + "execution_count": 120, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "{'container': {'created': datetime.datetime(2022, 7, 26, 7, 57, 28, 27000, tzinfo=tzutc()),\n", + "{'container': {'created': datetime.datetime(2022, 7, 26, 13, 5, 36, 339000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -511,12 +511,12 @@ " 'titles_after': None,\n", " 'titles_before': None,\n", " 'username': 'user'},\n", - " 'hash': '0ba17c47b0eec5cd73dd6a9164bed510b159191076dda38165906733a821cd16',\n", + " 'hash': '5dc114629602472d0bb93f4aedd6a38f161dd59ed129247511c83767fcba0a19',\n", " 'id': 1,\n", " 'internal_name': 'fda-userdb-airquality',\n", " 'is_public': None,\n", " 'name': 'Airquality'},\n", - " 'created': datetime.datetime(2022, 7, 26, 7, 57, 34, 419000, tzinfo=tzutc()),\n", + " 'created': datetime.datetime(2022, 7, 26, 13, 5, 42, 453000, tzinfo=tzutc()),\n", " 'creator': {'affiliation': None,\n", " 'authorities': None,\n", " 'email': 'someone@example.com',\n", @@ -581,7 +581,7 @@ }, { "cell_type": "code", - "execution_count": 46, + "execution_count": 121, "outputs": [ { "name": "stdout", @@ -600,8 +600,8 @@ " 'titles_before': None,\n", " 'username': 'user'},\n", " 'id': 1,\n", - " 'internal_name': 'airquality_9bf3d186-0cb8-11ed-9462-8c8caada74c3',\n", - " 'name': 'Airquality 9bf3d186-0cb8-11ed-9462-8c8caada74c3'}\n" + " 'internal_name': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", + " 'name': 'Airquality a7a429a6-0ce3-11ed-9462-8c8caada74c3'}\n" ] } ], @@ -678,7 +678,7 @@ }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 122, "outputs": [ { "name": "stdout", @@ -704,7 +704,7 @@ " 'check_expression': None,\n", " 'column_concept': None,\n", " 'column_type': 'date',\n", - " 'date_format': {'created_at': datetime.datetime(2022, 7, 26, 7, 56, 9, 320000, tzinfo=tzutc()),\n", + " 'date_format': {'created_at': datetime.datetime(2022, 7, 26, 13, 1, 15, 747000, tzinfo=tzutc()),\n", " 'database_format': '%Y-%c-%d',\n", " 'example': '2022-01-30',\n", " 'has_time': False,\n", @@ -817,12 +817,12 @@ " 'name': 'Status',\n", " 'references': None,\n", " 'unique': False}],\n", - " 'created': datetime.datetime(2022, 7, 26, 7, 57, 35, 791000, tzinfo=tzutc()),\n", + " 'created': datetime.datetime(2022, 7, 26, 13, 5, 43, 660000, tzinfo=tzutc()),\n", " 'description': 'Airquality in Zürich, Switzerland',\n", " 'id': 1,\n", - " 'internal_name': 'airquality_9bf3d186-0cb8-11ed-9462-8c8caada74c3',\n", - " 'name': 'Airquality 9bf3d186-0cb8-11ed-9462-8c8caada74c3',\n", - " 'topic': 'airquality_9bf3d186-0cb8-11ed-9462-8c8caada74c3'}\n" + " 'internal_name': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", + " 'name': 'Airquality a7a429a6-0ce3-11ed-9462-8c8caada74c3',\n", + " 'topic': 'airquality_a7a429a6-0ce3-11ed-9462-8c8caada74c3'}\n" ] } ], @@ -853,7 +853,7 @@ }, { "cell_type": "code", - "execution_count": 48, + "execution_count": 123, "outputs": [ { "name": "stdout", @@ -894,7 +894,7 @@ }, { "cell_type": "code", - "execution_count": 49, + "execution_count": 124, "outputs": [ { "name": "stdout", @@ -954,16 +954,16 @@ }, { "cell_type": "code", - "execution_count": 50, + "execution_count": 125, "outputs": [ { "ename": "ApiException", - "evalue": "(400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 07:57:39 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n", + "evalue": "(400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 13:05:46 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n", "output_type": "error", "traceback": [ "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[0;31mApiException\u001B[0m Traceback (most recent call last)", - "Input \u001B[0;32mIn [50]\u001B[0m, in \u001B[0;36m<cell line: 1>\u001B[0;34m()\u001B[0m\n\u001B[0;32m----> 1\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mquery\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstatement\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mselect `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[43mtable_internal_name\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m` where `foo` = \u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mbar\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 3\u001B[0m \u001B[43m}\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontainer_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpage\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msize\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m3\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28mprint\u001B[39m(response)\n", + "Input \u001B[0;32mIn [125]\u001B[0m, in \u001B[0;36m<cell line: 1>\u001B[0;34m()\u001B[0m\n\u001B[0;32m----> 1\u001B[0m response \u001B[38;5;241m=\u001B[39m \u001B[43mquery\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute\u001B[49m\u001B[43m(\u001B[49m\u001B[43m{\u001B[49m\n\u001B[1;32m 2\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mstatement\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m:\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mselect `date`, `location`, `parameter`, `interval`, `unit`, `value`, `status` from `\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[43mtable_internal_name\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m+\u001B[39;49m\u001B[43m \u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43m` where `foo` = \u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mbar\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\n\u001B[1;32m 3\u001B[0m \u001B[43m}\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcontainer_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpage\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m0\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43msize\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;241;43m3\u001B[39;49m\u001B[43m)\u001B[49m\n\u001B[1;32m 4\u001B[0m \u001B[38;5;28mprint\u001B[39m(response)\n", "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:57\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 55\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mexecute_with_http_info(body, \u001B[38;5;28mid\u001B[39m, database_id, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs) \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 56\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[0;32m---> 57\u001B[0m (data) \u001B[38;5;241m=\u001B[39m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mexecute_with_http_info\u001B[49m\u001B[43m(\u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43mid\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mdatabase_id\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[38;5;241;43m*\u001B[39;49m\u001B[43mkwargs\u001B[49m\u001B[43m)\u001B[49m \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[1;32m 58\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m data\n", "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api/query_endpoint_api.py:140\u001B[0m, in \u001B[0;36mQueryEndpointApi.execute_with_http_info\u001B[0;34m(self, body, id, database_id, **kwargs)\u001B[0m\n\u001B[1;32m 137\u001B[0m \u001B[38;5;66;03m# Authentication setting\u001B[39;00m\n\u001B[1;32m 138\u001B[0m auth_settings \u001B[38;5;241m=\u001B[39m [\u001B[38;5;124m'\u001B[39m\u001B[38;5;124mbearerAuth\u001B[39m\u001B[38;5;124m'\u001B[39m] \u001B[38;5;66;03m# noqa: E501\u001B[39;00m\n\u001B[0;32m--> 140\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mapi_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mcall_api\u001B[49m\u001B[43m(\u001B[49m\n\u001B[1;32m 141\u001B[0m \u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m/api/container/\u001B[39;49m\u001B[38;5;132;43;01m{id}\u001B[39;49;00m\u001B[38;5;124;43m/database/\u001B[39;49m\u001B[38;5;132;43;01m{databaseId}\u001B[39;49;00m\u001B[38;5;124;43m/query\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\n\u001B[1;32m 142\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 143\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 144\u001B[0m \u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 145\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 146\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mform_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 147\u001B[0m \u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mlocal_var_files\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 148\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43mQueryResultDto\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;66;43;03m# noqa: E501\u001B[39;49;00m\n\u001B[1;32m 149\u001B[0m \u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 150\u001B[0m \u001B[43m \u001B[49m\u001B[43masync_req\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43masync_req\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 151\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_return_http_data_only\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 152\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_preload_content\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[38;5;28;43;01mTrue\u001B[39;49;00m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 153\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mparams\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mget\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[38;5;124;43m_request_timeout\u001B[39;49m\u001B[38;5;124;43m'\u001B[39;49m\u001B[43m)\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 154\u001B[0m \u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mcollection_formats\u001B[49m\u001B[43m)\u001B[49m\n", "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:316\u001B[0m, in \u001B[0;36mApiClient.call_api\u001B[0;34m(self, resource_path, method, path_params, query_params, header_params, body, post_params, files, response_type, auth_settings, async_req, _return_http_data_only, collection_formats, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 279\u001B[0m \u001B[38;5;124;03m\"\"\"Makes the HTTP request (synchronous) and returns deserialized data.\u001B[39;00m\n\u001B[1;32m 280\u001B[0m \n\u001B[1;32m 281\u001B[0m \u001B[38;5;124;03mTo make an async request, set the async_req parameter.\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 313\u001B[0m \u001B[38;5;124;03m then the method will return the response directly.\u001B[39;00m\n\u001B[1;32m 314\u001B[0m \u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 315\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m async_req:\n\u001B[0;32m--> 316\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43m__call_api\u001B[49m\u001B[43m(\u001B[49m\u001B[43mresource_path\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mmethod\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 317\u001B[0m \u001B[43m \u001B[49m\u001B[43mpath_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mheader_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 318\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mfiles\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 319\u001B[0m \u001B[43m \u001B[49m\u001B[43mresponse_type\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mauth_settings\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 320\u001B[0m \u001B[43m \u001B[49m\u001B[43m_return_http_data_only\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43mcollection_formats\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 321\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 322\u001B[0m \u001B[38;5;28;01melse\u001B[39;00m:\n\u001B[1;32m 323\u001B[0m thread \u001B[38;5;241m=\u001B[39m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mpool\u001B[38;5;241m.\u001B[39mapply_async(\u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m__call_api, (resource_path,\n\u001B[1;32m 324\u001B[0m method, path_params, query_params,\n\u001B[1;32m 325\u001B[0m header_params, body,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 329\u001B[0m collection_formats,\n\u001B[1;32m 330\u001B[0m _preload_content, _request_timeout))\n", @@ -971,7 +971,7 @@ "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/api_client.py:366\u001B[0m, in \u001B[0;36mApiClient.request\u001B[0;34m(self, method, url, query_params, headers, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 358\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPOST(url,\n\u001B[1;32m 359\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 360\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 363\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 364\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n\u001B[1;32m 365\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPUT\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[0;32m--> 366\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrest_client\u001B[49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mPUT\u001B[49m\u001B[43m(\u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 367\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 368\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 369\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 370\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 371\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 372\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n\u001B[1;32m 373\u001B[0m \u001B[38;5;28;01melif\u001B[39;00m method \u001B[38;5;241m==\u001B[39m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mPATCH\u001B[39m\u001B[38;5;124m\"\u001B[39m:\n\u001B[1;32m 374\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mrest_client\u001B[38;5;241m.\u001B[39mPATCH(url,\n\u001B[1;32m 375\u001B[0m query_params\u001B[38;5;241m=\u001B[39mquery_params,\n\u001B[1;32m 376\u001B[0m headers\u001B[38;5;241m=\u001B[39mheaders,\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 379\u001B[0m _request_timeout\u001B[38;5;241m=\u001B[39m_request_timeout,\n\u001B[1;32m 380\u001B[0m body\u001B[38;5;241m=\u001B[39mbody)\n", "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:273\u001B[0m, in \u001B[0;36mRESTClientObject.PUT\u001B[0;34m(self, url, headers, query_params, post_params, body, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 271\u001B[0m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21mPUT\u001B[39m(\u001B[38;5;28mself\u001B[39m, url, headers\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, query_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, post_params\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m,\n\u001B[1;32m 272\u001B[0m body\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m, _preload_content\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m, _request_timeout\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mNone\u001B[39;00m):\n\u001B[0;32m--> 273\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28;43mself\u001B[39;49m\u001B[38;5;241;43m.\u001B[39;49m\u001B[43mrequest\u001B[49m\u001B[43m(\u001B[49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[38;5;124;43mPUT\u001B[39;49m\u001B[38;5;124;43m\"\u001B[39;49m\u001B[43m,\u001B[49m\u001B[43m \u001B[49m\u001B[43murl\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 274\u001B[0m \u001B[43m \u001B[49m\u001B[43mheaders\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mheaders\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 275\u001B[0m \u001B[43m \u001B[49m\u001B[43mquery_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mquery_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 276\u001B[0m \u001B[43m \u001B[49m\u001B[43mpost_params\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mpost_params\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 277\u001B[0m \u001B[43m \u001B[49m\u001B[43m_preload_content\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_preload_content\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 278\u001B[0m \u001B[43m \u001B[49m\u001B[43m_request_timeout\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43m_request_timeout\u001B[49m\u001B[43m,\u001B[49m\n\u001B[1;32m 279\u001B[0m \u001B[43m \u001B[49m\u001B[43mbody\u001B[49m\u001B[38;5;241;43m=\u001B[39;49m\u001B[43mbody\u001B[49m\u001B[43m)\u001B[49m\n", "File \u001B[0;32m~/Projects/fda-services/.jupyter/api_query/rest.py:222\u001B[0m, in \u001B[0;36mRESTClientObject.request\u001B[0;34m(self, method, url, query_params, headers, body, post_params, _preload_content, _request_timeout)\u001B[0m\n\u001B[1;32m 219\u001B[0m logger\u001B[38;5;241m.\u001B[39mdebug(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mresponse body: \u001B[39m\u001B[38;5;132;01m%s\u001B[39;00m\u001B[38;5;124m\"\u001B[39m, r\u001B[38;5;241m.\u001B[39mdata)\n\u001B[1;32m 221\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;241m200\u001B[39m \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m r\u001B[38;5;241m.\u001B[39mstatus \u001B[38;5;241m<\u001B[39m\u001B[38;5;241m=\u001B[39m \u001B[38;5;241m299\u001B[39m:\n\u001B[0;32m--> 222\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m ApiException(http_resp\u001B[38;5;241m=\u001B[39mr)\n\u001B[1;32m 224\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m r\n", - "\u001B[0;31mApiException\u001B[0m: (400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 07:57:39 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n" + "\u001B[0;31mApiException\u001B[0m: (400)\nReason: Bad Request\nHTTP response headers: HTTPHeaderDict({'transfer-encoding': 'chunked', 'Vary': 'Origin, Access-Control-Request-Method, Access-Control-Request-Headers', 'X-Content-Type-Options': 'nosniff', 'X-XSS-Protection': '1; mode=block', 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'X-Frame-Options': 'DENY', 'Content-Type': 'application/json', 'Date': 'Tue, 26 Jul 2022 13:05:46 GMT'})\nHTTP response body: b'{\"status\":\"BAD_REQUEST\",\"message\":\"Failed to execute and map time-versioned query\",\"code\":\"error.table.malformed\"}'\n" ] } ], @@ -987,30 +987,6 @@ "name": "#%%\n" } } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } - }, - { - "cell_type": "code", - "execution_count": null, - "outputs": [], - "source": [], - "metadata": { - "collapsed": false, - "pycharm": { - "name": "#%%\n" - } - } } ], "metadata": { diff --git a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java index 2c57b444bb742964a40cbde0f1a7db93f5cb8e51..cc325e77af9f2ba5cb0e8c2ac9e06141e5c05d10 100644 --- a/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java +++ b/fda-database-service/rest-service/src/main/java/at/tuwien/endpoints/ContainerDatabaseEndpoint.java @@ -79,7 +79,7 @@ public class ContainerDatabaseEndpoint { Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, - DatabaseNotFoundException, DatabaseNameExistsException, DatabaseConnectionException { + DatabaseNotFoundException, DatabaseNameExistsException, DatabaseConnectionException, QueryMalformedException { final Database database = databaseService.create(containerId, createDto, principal); messageQueueService.createExchange(database, principal); queryStoreService.create(containerId, database.getId()); @@ -128,7 +128,7 @@ public class ContainerDatabaseEndpoint { @NotBlank @PathVariable Long databaseId, Principal principal) throws DatabaseNotFoundException, ImageNotSupportedException, DatabaseMalformedException, AmqpException, ContainerConnectionException, - ContainerNotFoundException, DatabaseConnectionException { + ContainerNotFoundException, DatabaseConnectionException, QueryMalformedException { final Database database = databaseService.findById(containerId, databaseId); messageQueueService.deleteExchange(database); databaseService.delete(containerId, databaseId, principal); diff --git a/fda-database-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java b/fda-database-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..6d3d2bc052a734dd49bf58e309b063c11f55292a --- /dev/null +++ b/fda-database-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryMalformedException extends Exception { + + public QueryMalformedException(String msg) { + super(msg); + } + + public QueryMalformedException(String msg, Throwable thr) { + super(msg, thr); + } + + public QueryMalformedException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java index 3537f5a9ae30f90647f005f32180a90e047bda0f..be6bc90490978e615039348bea02389becf02fa1 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java +++ b/fda-database-service/services/src/main/java/at/tuwien/mapper/DatabaseMapper.java @@ -7,6 +7,7 @@ import at.tuwien.api.database.LanguageTypeDto; import at.tuwien.api.user.UserDetailsDto; import at.tuwien.entities.database.Database; import at.tuwien.entities.database.LanguageType; +import at.tuwien.exception.QueryMalformedException; import at.tuwien.querystore.Query; import org.apache.http.auth.BasicUserPrincipal; import org.mapstruct.Mapper; @@ -15,6 +16,9 @@ import org.mapstruct.Mappings; import org.mapstruct.Named; import java.security.Principal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.text.Normalizer; import java.util.Locale; import java.util.regex.Pattern; @@ -58,22 +62,43 @@ public interface DatabaseMapper { }) DatabaseDto databaseToDatabaseDto(Database data); - default String databaseToRawCreateDatabaseQuery(Database database) { - final String statement = "CREATE DATABASE `" + database.getInternalName() + "`;"; - log.trace("raw create statement [{}]", statement); - return statement; + default PreparedStatement databaseToRawCreateDatabaseQuery(Connection connection, Database database) throws QueryMalformedException { + final StringBuilder statement = new StringBuilder("CREATE DATABASE `") + .append(database.getInternalName()) + .append("`;"); + log.trace("raw create statement [{}]", statement);try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } - default String imageToRawGrantReadonlyAccessQuery() { - final String statement = "GRANT SELECT ON *.* TO `mariadb`@`%`;"; + default PreparedStatement imageToRawGrantReadonlyAccessQuery(Connection connection) throws QueryMalformedException { + final StringBuilder statement = new StringBuilder("GRANT SELECT ON *.* TO `mariadb`@`%`;"); log.trace("raw grant readonly statement [{}]", statement); - return statement; + try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } - default String databaseToRawDeleteDatabaseQuery(Database database) { - final String statement = "DROP DATABASE `" + database.getInternalName() + "`;"; + default PreparedStatement databaseToRawDeleteDatabaseQuery(Connection connection, Database database) throws QueryMalformedException { + final StringBuilder statement = new StringBuilder("DROP DATABASE `") + .append(database.getInternalName()) + .append("`;"); log.trace("raw grant readonly statement [{}]", statement); - return statement; + try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } default Principal userDetailsDtoToPrincipal(UserDetailsDto data) { diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java b/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java index 97986772568893c061e2822ce58faf31519beb37..c1ab507ad6ba97c113216f291c556d8db4270884 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/DatabaseService.java @@ -63,7 +63,7 @@ public interface DatabaseService { */ void delete(Long id, Long databaseId, Principal principal) throws DatabaseNotFoundException, ImageNotSupportedException, - DatabaseMalformedException, AmqpException, ContainerConnectionException, ContainerNotFoundException, DatabaseConnectionException; + DatabaseMalformedException, AmqpException, ContainerConnectionException, ContainerNotFoundException, DatabaseConnectionException, QueryMalformedException; /** * Creates a new database with minimal metadata in the metadata database and creates a new database on the container. @@ -80,7 +80,7 @@ public interface DatabaseService { */ Database create(Long id, DatabaseCreateDto createDto, Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, - DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, DatabaseNameExistsException, DatabaseConnectionException; + DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, DatabaseNameExistsException, DatabaseConnectionException, QueryMalformedException; /** * Updates the database metadata. diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java b/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java index 52196b30a91be60135c8ca0e02af4f25ca531505..52929f254ceee8eec3047ed1b1d2cdba15a9382a 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/QueryStoreService.java @@ -1,9 +1,10 @@ package at.tuwien.service; import at.tuwien.exception.DatabaseConnectionException; +import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.exception.DatabaseNotFoundException; public interface QueryStoreService { - void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, DatabaseConnectionException; + void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, DatabaseConnectionException, DatabaseMalformedException; } diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java index 749b9c7adc1eb78f935db03877e127b60affe02b..a2f2abfe0e931706d24313708a4fbe1432b6f105 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java @@ -8,27 +8,21 @@ import at.tuwien.entities.database.Database; import at.tuwien.exception.DatabaseConnectionException; import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; -import org.hibernate.Session; -import org.hibernate.query.NativeQuery; import org.springframework.stereotype.Service; -import javax.persistence.PersistenceException; import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; -import java.util.List; import java.util.stream.Collectors; @Log4j2 @Service public abstract class HibernateConnector { - protected static Connection getConnection(ContainerImage image, Container container) throws DatabaseConnectionException { - return getConnection(image, container, null); + protected static ComboPooledDataSource getDataSource(ContainerImage image, Container container) { + return getDataSource(image, container, null); } - protected static Connection getConnection(ContainerImage image, Container container, Database database) throws DatabaseConnectionException { + protected static ComboPooledDataSource getDataSource(ContainerImage image, Container container, Database database) { final ComboPooledDataSource dataSource = new ComboPooledDataSource(); final String url = "jdbc:" + image.getJdbcMethod() + "://" + container.getInternalName() + "/" + (database != null ? database.getInternalName() : ""); dataSource.setJdbcUrl(url); @@ -51,41 +45,7 @@ public abstract class HibernateConnector { dataSource.setAcquireIncrement(5); dataSource.setMaxPoolSize(20); dataSource.setMaxStatements(100); - final Connection connection; - try { - connection = dataSource.getConnection(); - } catch (SQLException e) { - log.error("Failed to connect to the database"); - log.debug("failed to connect to the database {}", database); - throw new DatabaseConnectionException("Failed to connect to the database"); - } - return connection; - } - - protected static Long activeConnection(Connection connection) throws DatabaseConnectionException { - final ResultSet resultSet = execute(connection, "SHOW STATUS LIKE 'threads_connected'"); - try { - if (resultSet.next()) { - return resultSet.getLong(2); - } - } catch (SQLException e) { - log.error("Failed to determine active connections"); - throw new DatabaseConnectionException("Failed to determine active connections", e); - } - log.error("Failed to determine active connections"); - throw new DatabaseConnectionException("Failed to determine active connections"); - } - - protected static ResultSet execute(Connection connection, String statement) throws DatabaseConnectionException { - final PreparedStatement preparedStatement; - try { - preparedStatement = connection.prepareStatement(statement); - return preparedStatement.executeQuery(); - } catch (SQLException e) { - log.error("Failed to execute statement"); - log.debug("failed to execute statement [{}] reason: {}", statement, e.getMessage()); - throw new DatabaseConnectionException("Failed to execute statement", e); - } + return dataSource; } } diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java index 2160174133acd4ccb05cd604f0bb4b2681722f78..d0a8ffabbc84c3ff9bc2807cace12da272f3f84d 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/impl/MariaDbServiceImpl.java @@ -15,6 +15,7 @@ import at.tuwien.service.ContainerService; import at.tuwien.service.DatabaseService; import at.tuwien.service.LicenseService; import at.tuwien.service.UserService; +import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.hibernate.Session; import org.hibernate.Transaction; @@ -30,6 +31,7 @@ import java.security.Principal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.time.Instant; import java.util.List; import java.util.Optional; @@ -103,17 +105,26 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe @Override @Transactional public void delete(Long containerId, Long databaseId, Principal principal) throws DatabaseNotFoundException, - ImageNotSupportedException, DatabaseMalformedException, ContainerConnectionException, AmqpException, - ContainerNotFoundException, DatabaseConnectionException { + ImageNotSupportedException, DatabaseMalformedException, ContainerNotFoundException, + DatabaseConnectionException, QueryMalformedException { final Container container = containerService.find(containerId); final Database database = findPublicOrMineById(containerId, databaseId, principal); if (!database.getContainer().getImage().getRepository().equals("mariadb")) { throw new ImageNotSupportedException("Currently only MariaDB is supported"); } /* run query */ - final Connection connection = getConnection(container.getImage(), container, database); - execute(connection, databaseMapper.databaseToRawDeleteDatabaseQuery(database)); - activeConnection(connection); + final ComboPooledDataSource dataSource = getDataSource(container.getImage(), container, database); + try { + final Connection connection = dataSource.getConnection(); + final PreparedStatement preparedStatement = databaseMapper.databaseToRawDeleteDatabaseQuery(connection, database); + preparedStatement.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to delete database with id {}", databaseId); + log.debug("failed to delete database {}, reason: {}", database, e.getMessage()); + throw new DatabaseMalformedException("Failed to execute and map time-versioned query", e); + } finally { + dataSource.close(); + } database.setDeleted(Instant.now()) /* method has void, only for debug logs */; /* save in metadata database */ databaseRepository.deleteById(databaseId); @@ -126,7 +137,7 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe public Database create(Long containerId, DatabaseCreateDto createDto, Principal principal) throws ImageNotSupportedException, ContainerNotFoundException, DatabaseMalformedException, AmqpException, ContainerConnectionException, UserNotFoundException, - DatabaseNameExistsException, DatabaseConnectionException { + DatabaseNameExistsException, DatabaseConnectionException, QueryMalformedException { final Container container = containerService.find(containerId); if (container.getDatabases().size() != 0) { log.error("Currently we only support one database per container."); @@ -137,13 +148,22 @@ public class MariaDbServiceImpl extends HibernateConnector implements DatabaseSe database.setName(createDto.getName()); database.setInternalName(databaseMapper.nameToInternalName(database.getName())); database.setContainer(container); - /* create database */ - final Connection connection = getConnection(container.getImage(), container); - execute(connection, databaseMapper.databaseToRawCreateDatabaseQuery(database)); - log.debug("active database connections {}", activeConnection(connection)); - /* grant read-only access */ - execute(connection, databaseMapper.imageToRawGrantReadonlyAccessQuery()); - log.debug("active database connections {}", activeConnection(connection)); + final ComboPooledDataSource dataSource = getDataSource(container.getImage(), container); + try { + /* create database */ + final Connection connection = dataSource.getConnection(); + final PreparedStatement preparedStatement = databaseMapper.databaseToRawCreateDatabaseQuery(connection, database); + preparedStatement.executeUpdate(); + /* grant read-only access */ + final PreparedStatement preparedStatement1 = databaseMapper.imageToRawGrantReadonlyAccessQuery(connection); + preparedStatement1.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to delete database"); + log.debug("failed to delete database {}, reason: {}", database, e.getMessage()); + throw new DatabaseMalformedException("Failed to execute and map time-versioned query", e); + } finally { + dataSource.close(); + } /* save in metadata database */ database.setExchange(amqpMapper.exchangeName(database)); database.setDescription(createDto.getDescription()); diff --git a/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java b/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java index 43b61c073efc3e529019b4995f19f24f6b228e52..aabf3856bc328d6b8d43060e25a4d13f0d0934a7 100644 --- a/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java +++ b/fda-database-service/services/src/main/java/at/tuwien/service/impl/QueryStoreServiceImpl.java @@ -2,14 +2,18 @@ package at.tuwien.service.impl; import at.tuwien.entities.database.Database; import at.tuwien.exception.DatabaseConnectionException; +import at.tuwien.exception.DatabaseMalformedException; import at.tuwien.exception.DatabaseNotFoundException; import at.tuwien.service.DatabaseService; import at.tuwien.service.QueryStoreService; +import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; @Log4j2 @Service @@ -23,16 +27,31 @@ public class QueryStoreServiceImpl extends HibernateConnector implements QuerySt } @Override - public void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, DatabaseConnectionException { + public void create(Long containerId, Long databaseId) throws DatabaseNotFoundException, DatabaseConnectionException, DatabaseMalformedException { final Database database = databaseService.findById(containerId, databaseId); /* create */ - final Connection connection = getConnection(database.getContainer().getImage(), database.getContainer(), database); - execute(connection, "CREATE SEQUENCE IF NOT EXISTS `qs_queries_seq`"); - execute(connection, "CREATE SEQUENCE IF NOT EXISTS `qs_tables_seq`"); - execute(connection, "CREATE SEQUENCE IF NOT EXISTS `qs_columns_seq`"); - execute(connection, "CREATE TABLE `qs_queries` (`id` bigint not null primary key default nextval(`qs_queries_seq`), `cid` bigint not null, `created` datetime not null default now(), `created_by` bigint not null, `dbid` bigint not null, `execution` datetime not null, `last_modified` datetime, `query` text not null, `query_normalized` text not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint)"); - execute(connection, "CREATE TABLE `qs_tables` (`id` bigint not null primary key default nextval(`qs_tables_seq`), `created` datetime not null, `dbid` bigint not null, `last_modified` datetime)"); - execute(connection, "CREATE TABLE `qs_columns` (`id` bigint not null primary key default nextval(`qs_columns_seq`), `created` datetime not null, `dbid` bigint not null, `tid` bigint not null, `last_modified` datetime)"); + final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database); + try { + final Connection connection = dataSource.getConnection(); + final PreparedStatement preparedStatement10 = connection.prepareStatement("CREATE SEQUENCE IF NOT EXISTS `qs_queries_seq`"); + preparedStatement10.executeUpdate(); + final PreparedStatement preparedStatement11 = connection.prepareStatement("CREATE SEQUENCE IF NOT EXISTS `qs_tables_seq`"); + preparedStatement11.executeUpdate(); + final PreparedStatement preparedStatement12 = connection.prepareStatement("CREATE SEQUENCE IF NOT EXISTS `qs_columns_seq`"); + preparedStatement12.executeUpdate(); + final PreparedStatement preparedStatement20 = connection.prepareStatement("CREATE TABLE `qs_queries` (`id` bigint not null primary key default nextval(`qs_queries_seq`), `cid` bigint not null, `created` datetime not null default now(), `created_by` bigint not null, `dbid` bigint not null, `execution` datetime not null, `last_modified` datetime, `query` text not null, `query_normalized` text not null, `query_hash` varchar(255) not null, `result_hash` varchar(255), `result_number` bigint)"); + preparedStatement20.executeUpdate(); + final PreparedStatement preparedStatement21 = connection.prepareStatement("CREATE TABLE `qs_tables` (`id` bigint not null primary key default nextval(`qs_tables_seq`), `created` datetime not null, `dbid` bigint not null, `last_modified` datetime)"); + preparedStatement21.executeUpdate(); + final PreparedStatement preparedStatement22 = connection.prepareStatement("CREATE TABLE `qs_columns` (`id` bigint not null primary key default nextval(`qs_columns_seq`), `created` datetime not null, `dbid` bigint not null, `tid` bigint not null, `last_modified` datetime)"); + preparedStatement22.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to delete database with id {}", databaseId); + log.debug("failed to delete database {}, reason: {}", database, e.getMessage()); + throw new DatabaseMalformedException("Failed to execute and map time-versioned query", e); + } finally { + dataSource.close(); + } log.info("Created query store in database with id {}", databaseId); log.debug("created query store in database {}", database); } diff --git a/fda-table-service/api/src/main/java/at/tuwien/CreateTableRawQuery.java b/fda-table-service/api/src/main/java/at/tuwien/CreateTableRawQuery.java index 674dbbf6ff8c995b60d79f37d34063c9972142cf..2b9c7a12769f1bc95c50a135d6b984a9f073a80f 100644 --- a/fda-table-service/api/src/main/java/at/tuwien/CreateTableRawQuery.java +++ b/fda-table-service/api/src/main/java/at/tuwien/CreateTableRawQuery.java @@ -2,6 +2,8 @@ package at.tuwien; import lombok.*; +import java.sql.PreparedStatement; + @Getter @Setter @ToString @@ -10,7 +12,7 @@ import lombok.*; @NoArgsConstructor public class CreateTableRawQuery { - private String query; + private PreparedStatement preparedStatement; /** * True if the "id" column was autogenerated by the service (e.g. not present before) diff --git a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java index b024d9fd57669b3d2c290c4cff564332a887078e..101c2d82e41f013a5c5940e2fb5ae93d73f0bd20 100644 --- a/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java +++ b/fda-table-service/rest-service/src/main/java/at/tuwien/endpoints/TableEndpoint.java @@ -68,7 +68,7 @@ public class TableEndpoint extends AbstractEndpoint { @NotNull @Valid @RequestBody TableCreateDto createDto, Principal principal) throws ImageNotSupportedException, DatabaseNotFoundException, TableMalformedException, AmqpException, - TableNameExistsException, ContainerNotFoundException, UserNotFoundException, DatabaseConnectionException { + TableNameExistsException, ContainerNotFoundException, UserNotFoundException, QueryMalformedException { if (!hasDatabasePermission(containerId, databaseId, "TABLE_CREATE", principal)) { log.error("Missing table create permission"); throw new NotAllowedException("Missing table create permission"); @@ -122,7 +122,7 @@ public class TableEndpoint extends AbstractEndpoint { @NotNull @PathVariable("tableId") Long tableId, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, - DataProcessingException, ContainerNotFoundException, TableMalformedException, DatabaseConnectionException { + DataProcessingException, ContainerNotFoundException, TableMalformedException, QueryMalformedException { if (!hasTablePermission(containerId, databaseId, tableId, "TABLE_DELETE", principal)) { log.error("Missing table delete permission"); throw new NotAllowedException("Missing table delete permission"); diff --git a/fda-table-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java b/fda-table-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java new file mode 100644 index 0000000000000000000000000000000000000000..6d3d2bc052a734dd49bf58e309b063c11f55292a --- /dev/null +++ b/fda-table-service/services/src/main/java/at/tuwien/exception/QueryMalformedException.java @@ -0,0 +1,21 @@ +package at.tuwien.exception; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.ResponseStatus; + +@ResponseStatus(code = HttpStatus.BAD_REQUEST) +public class QueryMalformedException extends Exception { + + public QueryMalformedException(String msg) { + super(msg); + } + + public QueryMalformedException(String msg, Throwable thr) { + super(msg, thr); + } + + public QueryMalformedException(Throwable thr) { + super(thr); + } + +} diff --git a/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java b/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java index 3176a148f0061a715ac45a2fd18335e6bf6f3849..cbb946cfc04cbff4edf24d390ce3d48cabf3cb9c 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java +++ b/fda-table-service/services/src/main/java/at/tuwien/mapper/TableMapper.java @@ -13,12 +13,16 @@ import at.tuwien.entities.database.table.Table; import at.tuwien.entities.database.table.columns.TableColumn; import at.tuwien.entities.database.table.columns.TableColumnType; import at.tuwien.exception.ImageNotSupportedException; +import at.tuwien.exception.QueryMalformedException; import at.tuwien.exception.TableMalformedException; import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.Mappings; import org.mapstruct.Named; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; import java.text.Normalizer; import java.util.*; import java.util.regex.Pattern; @@ -144,11 +148,21 @@ public interface TableMapper { * @param data The table * @return The drop table query */ - default String tableToDropTableRawQuery(Table data) throws ImageNotSupportedException { + default PreparedStatement tableToDropTableRawQuery(Connection connection, Table data) throws ImageNotSupportedException, QueryMalformedException { if (!data.getDatabase().getContainer().getImage().getRepository().equals("mariadb")) { throw new ImageNotSupportedException("Currently only MariaDB is supported"); } - return "DROP TABLE `" + data.getInternalName() + "`;"; + final StringBuilder statement = new StringBuilder("DROP TABLE `") + .append(data.getInternalName()) + .append("`;"); + log.trace("mapped raw drop table query [{}]", statement); + try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } /** @@ -159,9 +173,9 @@ public interface TableMapper { * @param data The table * @return The create table query */ - default CreateTableRawQuery tableToCreateTableRawQuery(Database database, TableCreateDto data) + default CreateTableRawQuery tableToCreateTableRawQuery(Connection connection, Database database, TableCreateDto data) throws ImageNotSupportedException, - TableMalformedException { + TableMalformedException, QueryMalformedException { if (!database.getContainer().getImage().getRepository().equals("mariadb")) { throw new ImageNotSupportedException("Currently only MariaDB is supported"); } @@ -196,21 +210,23 @@ public interface TableMapper { data.setColumns(columns); } final int[] idx = {0}; - Arrays.stream(data.getColumns()) - .forEach(c -> query.append(idx[0]++ > 0 ? ", " : "") - .append("`") - .append(nameToInternalName(c.getName())) - .append("` ") - /* data type */ - .append(columnTypeDtoToDataType(c)) - /* null expressions */ - .append(c.getNullAllowed() ? " NULL" : " NOT NULL") - /* default expressions */ - .append(!primaryColumnExists && c.getName().equals( - "id") ? " DEFAULT NEXTVAL(`" + tableCreateDtoToSequenceName(data) + "`)" : "") - /* check expressions */ - .append(c.getCheckExpression() != null && - !c.getCheckExpression().isEmpty() ? " CHECK (" + c.getCheckExpression() + ")" : "")); + for (int i = 0; i < data.getColumns().length; i++) { + final ColumnCreateDto c = data.getColumns()[i]; + query.append(idx[0]++ > 0 ? ", " : "") + .append("`") + .append(nameToInternalName(c.getName())) + .append("` ") + /* data type */ + .append(columnTypeDtoToDataType(c)) + /* null expressions */ + .append(c.getNullAllowed() ? " NULL" : " NOT NULL") + /* default expressions */ + .append(!primaryColumnExists && c.getName().equals( + "id") ? " DEFAULT NEXTVAL(`" + tableCreateDtoToSequenceName(data) + "`)" : "") + /* check expressions */ + .append(c.getCheckExpression() != null && + !c.getCheckExpression().isEmpty() ? " CHECK (" + c.getCheckExpression() + ")" : ""); + } /* create primary key index */ query.append(", PRIMARY KEY (") .append(String.join(",", Arrays.stream(data.getColumns()) @@ -243,41 +259,62 @@ public interface TableMapper { query.append(") WITH SYSTEM VERSIONING;"); log.debug("create table query built with {} columns and system versioning", data.getColumns().length); log.debug("raw create table query: [{}]", query); - return CreateTableRawQuery.builder() - .query(query.toString()) - .generated(!primaryColumnExists) - .build(); + try { + return CreateTableRawQuery.builder() + .preparedStatement(connection.prepareStatement(query.toString())) + .generated(!primaryColumnExists) + .build(); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", query, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } default String tableCreateDtoToSequenceName(TableCreateDto data) { return "seq_" + nameToInternalName(data.getName()) + "_id"; } - default String tableToCreateSequenceRawQuery(Database database, TableCreateDto data) - throws ImageNotSupportedException { + default PreparedStatement tableToCreateSequenceRawQuery(Connection connection, Database database, TableCreateDto data) + throws ImageNotSupportedException, QueryMalformedException { if (!database.getContainer().getImage().getRepository().equals("mariadb")) { throw new ImageNotSupportedException("Currently only MariaDB is supported"); } - return "CREATE SEQUENCE `" + tableCreateDtoToSequenceName(data) + "` START WITH 1 INCREMENT BY 1;"; + final StringBuilder statement = new StringBuilder("CREATE SEQUENCE `") + .append(tableCreateDtoToSequenceName(data)) + .append("` START WITH 1 INCREMENT BY 1;"); + try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } - default String tableToCreateHistoryViewRawQuery(Table data) { - final StringBuilder builder = new StringBuilder("CREATE VIEW `hs_") + default PreparedStatement tableToCreateHistoryViewRawQuery(Connection connection, Table data) throws QueryMalformedException { + final StringBuilder statement = new StringBuilder("CREATE VIEW `hs_") .append(data.getInternalName()) .append("` AS SELECT "); final int[] idx = new int[]{0}; data.getColumns() .stream() .filter(TableColumn::getIsPrimaryKey) - .forEach(c -> builder.append(idx[0]++ > 0 ? "," : "") + .forEach(c -> statement.append(idx[0]++ > 0 ? "," : "") .append("`") .append(c.getInternalName()) .append("`")); - builder.append(", ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at FROM `") + statement.append(", ROW_START AS inserted_at, IF(ROW_END > NOW(), NULL, ROW_END) AS deleted_at FROM `") .append(data.getInternalName()) .append("` FOR SYSTEM_TIME ALL ORDER BY deleted_at ASC"); - log.trace("created history view query [{}]", builder); - return builder.toString(); + log.trace("created history view query [{}]", statement); + try { + return connection.prepareStatement(statement.toString()); + } catch (SQLException e) { + log.error("Failed to prepare statement"); + log.debug("failed to prepare statement {} reason: {}", statement, e.getMessage()); + throw new QueryMalformedException("Failed to prepare statement", e); + } } } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/TableService.java b/fda-table-service/services/src/main/java/at/tuwien/service/TableService.java index 511467cdd009cde8fb5697d10685f614ddf11716..5b948baf83b0ae489b87b442dfcc064593aae9e2 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/TableService.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/TableService.java @@ -33,7 +33,8 @@ public interface TableService { */ void deleteTable(Long containerId, Long databaseId, Long tableId, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, - ImageNotSupportedException, DataProcessingException, ContainerNotFoundException, TableMalformedException, DatabaseConnectionException; + ImageNotSupportedException, DataProcessingException, ContainerNotFoundException, TableMalformedException, + QueryMalformedException; /** * Find a table by database-table id pair @@ -66,5 +67,5 @@ public interface TableService { */ Table createTable(Long containerId, Long databaseId, TableCreateDto createDto, Principal principal) throws ImageNotSupportedException, DatabaseNotFoundException, TableMalformedException, - TableNameExistsException, ContainerNotFoundException, UserNotFoundException, DatabaseConnectionException; + TableNameExistsException, ContainerNotFoundException, UserNotFoundException, QueryMalformedException; } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java index 9cb24ee589fd979c0537c4d35be52c7feea437b8..a2f2abfe0e931706d24313708a4fbe1432b6f105 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/HibernateConnector.java @@ -11,8 +11,6 @@ import lombok.extern.log4j.Log4j2; import org.springframework.stereotype.Service; import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.stream.Collectors; @@ -20,7 +18,11 @@ import java.util.stream.Collectors; @Service public abstract class HibernateConnector { - protected static Connection getConnection(ContainerImage image, Container container, Database database) throws DatabaseConnectionException { + protected static ComboPooledDataSource getDataSource(ContainerImage image, Container container) { + return getDataSource(image, container, null); + } + + protected static ComboPooledDataSource getDataSource(ContainerImage image, Container container, Database database) { final ComboPooledDataSource dataSource = new ComboPooledDataSource(); final String url = "jdbc:" + image.getJdbcMethod() + "://" + container.getInternalName() + "/" + (database != null ? database.getInternalName() : ""); dataSource.setJdbcUrl(url); @@ -43,41 +45,7 @@ public abstract class HibernateConnector { dataSource.setAcquireIncrement(5); dataSource.setMaxPoolSize(20); dataSource.setMaxStatements(100); - final Connection connection; - try { - connection = dataSource.getConnection(); - } catch (SQLException e) { - log.error("Failed to connect to the database"); - log.debug("failed to connect to the database {}", database); - throw new DatabaseConnectionException("Failed to connect to the database"); - } - return connection; - } - - protected static Long activeConnection(Connection connection) throws DatabaseConnectionException { - final ResultSet resultSet = execute(connection, "SHOW STATUS LIKE 'threads_connected'"); - try { - if (resultSet.next()) { - return resultSet.getLong(2); - } - } catch (SQLException e) { - log.error("Failed to determine active connections"); - throw new DatabaseConnectionException("Failed to determine active connections", e); - } - log.error("Failed to determine active connections"); - throw new DatabaseConnectionException("Failed to determine active connections"); - } - - protected static ResultSet execute(Connection connection, String statement) throws DatabaseConnectionException { - final PreparedStatement preparedStatement; - try { - preparedStatement = connection.prepareStatement(statement); - return preparedStatement.executeQuery(); - } catch (SQLException e) { - log.error("Failed to execute statement"); - log.debug("failed to execute statement {}", statement); - throw new DatabaseConnectionException("Failed to execute statement", e); - } + return dataSource; } } diff --git a/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java b/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java index c8e4b0f52072982de1cc44ba930505058487979c..beee9782ec2feb547948f79738a6b9244ecd2700 100644 --- a/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java +++ b/fda-table-service/services/src/main/java/at/tuwien/service/impl/TableServiceImpl.java @@ -13,6 +13,7 @@ import at.tuwien.service.ContainerService; import at.tuwien.service.DatabaseService; import at.tuwien.service.TableService; import at.tuwien.service.UserService; +import com.mchange.v2.c3p0.ComboPooledDataSource; import lombok.extern.log4j.Log4j2; import org.hibernate.Session; import org.hibernate.Transaction; @@ -25,6 +26,7 @@ import javax.persistence.PersistenceException; import javax.persistence.PersistenceUnit; import java.security.Principal; import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.*; import java.util.stream.Collectors; @@ -59,13 +61,23 @@ public class TableServiceImpl extends HibernateConnector implements TableService @Transactional public void deleteTable(Long containerId, Long databaseId, Long tableId, Principal principal) throws TableNotFoundException, DatabaseNotFoundException, ImageNotSupportedException, - TableMalformedException, DatabaseConnectionException { + TableMalformedException, QueryMalformedException { /* find */ final Database database = databaseService.findPublicOrMineById(containerId, databaseId, principal); final Table table = findById(containerId, databaseId, tableId, principal); /* run query */ - final Connection connection = getConnection(database.getContainer().getImage(), database.getContainer(), database); - execute(connection, tableMapper.tableToDropTableRawQuery(table)); + final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database); + try { + final Connection connection = dataSource.getConnection(); + final PreparedStatement preparedStatement = tableMapper.tableToDropTableRawQuery(connection, table); + preparedStatement.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to delete table with id {}", tableId); + log.debug("failed to delete table {}, reason: {}", table, e.getMessage()); + throw new TableMalformedException("Failed to delete table", e); + } finally { + dataSource.close(); + } log.info("Deleted table with id {}", table.getId()); log.debug("deleted table {}", table); } @@ -87,7 +99,7 @@ public class TableServiceImpl extends HibernateConnector implements TableService @Transactional public Table createTable(Long containerId, Long databaseId, TableCreateDto createDto, Principal principal) throws ImageNotSupportedException, DatabaseNotFoundException, TableMalformedException, - TableNameExistsException, UserNotFoundException, DatabaseConnectionException { + TableNameExistsException, UserNotFoundException, QueryMalformedException { /* find */ final Database database = databaseService.findPublicOrMineById(containerId, databaseId, principal); final Optional<Table> optional = tableRepository.findByDatabaseAndInternalName(database, @@ -98,14 +110,26 @@ public class TableServiceImpl extends HibernateConnector implements TableService throw new TableNameExistsException("Table name exists"); } /* run query */ - final Connection connection = getConnection(database.getContainer().getImage(), database.getContainer(), database); - final CreateTableRawQuery query = tableMapper.tableToCreateTableRawQuery(database, createDto); - if (query.getGenerated()) { - /* in case the id column needs to be generated, we need to generate the sequence too */ - execute(connection, tableMapper.tableToCreateSequenceRawQuery(database, createDto)); - log.debug("created id sequence"); + final ComboPooledDataSource dataSource = getDataSource(database.getContainer().getImage(), database.getContainer(), database); + final CreateTableRawQuery query; + try { + final Connection connection = dataSource.getConnection(); + query = tableMapper.tableToCreateTableRawQuery(connection, database, createDto); + if (query.getGenerated()) { + /* in case the id column needs to be generated, we need to generate the sequence too */ + final PreparedStatement preparedStatement10 = tableMapper.tableToCreateSequenceRawQuery(connection, database, createDto); + preparedStatement10.executeUpdate(); + log.debug("created id sequence"); + } + final PreparedStatement preparedStatement11 = query.getPreparedStatement(); + preparedStatement11.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to create table"); + log.debug("failed to create table, reason: {}", e.getMessage()); + throw new TableMalformedException("Failed to create table", e); + } finally { + dataSource.close(); } - execute(connection, query.getQuery()); int[] idx = {0}; /* map table */ final Table tmp = tableMapper.tableCreateDtoToTable(createDto); @@ -129,7 +153,18 @@ public class TableServiceImpl extends HibernateConnector implements TableService column.setOrdinalPosition(idx[0]++); }); /* create history view */ - execute(connection, tableMapper.tableToCreateHistoryViewRawQuery(entity)); + final ComboPooledDataSource dataSource1 = getDataSource(database.getContainer().getImage(), database.getContainer(), database); + try { + final Connection connection = dataSource1.getConnection(); + final PreparedStatement preparedStatement = tableMapper.tableToCreateHistoryViewRawQuery(connection, entity); + preparedStatement.executeUpdate(); + } catch (SQLException e) { + log.error("Failed to create history view"); + log.debug("failed to create history view, reason: {}", e.getMessage()); + throw new TableMalformedException("Failed to create history view", e); + } finally { + dataSource1.close(); + } /* save */ final Table table = tableRepository.save(entity); log.info("Created table with id {}", table.getId());