├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENCE.txt ├── README.md ├── app ├── .gitignore ├── pom.xml └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── skuehnel │ │ │ └── dbvisualizer │ │ │ ├── DBVisualizer.java │ │ │ ├── OutputWriter.java │ │ │ ├── domain │ │ │ ├── Column.java │ │ │ ├── Model.java │ │ │ └── Table.java │ │ │ ├── report │ │ │ ├── AbstractReportGenerator.java │ │ │ ├── HTMLReportGenerator.java │ │ │ ├── MarkdownReportGenerator.java │ │ │ ├── PDFReportGenerator.java │ │ │ ├── ReportGenerator.java │ │ │ └── ReportGeneratorFactory.java │ │ │ ├── retrieve │ │ │ ├── ConnectionException.java │ │ │ ├── ERModelRetriever.java │ │ │ └── JDBCConnection.java │ │ │ ├── util │ │ │ ├── DB_DIALECT.java │ │ │ ├── FORMAT.java │ │ │ ├── InvalidParamException.java │ │ │ ├── MissingMandatoryException.java │ │ │ ├── OPTS.java │ │ │ ├── REPORT_FORMAT.java │ │ │ ├── TEST_OPTS.java │ │ │ ├── TEST_TYPE.java │ │ │ └── TestDBGenerator.java │ │ │ └── visualize │ │ │ ├── DetailedTableVisualizer.java │ │ │ ├── SimpleTableVisualizer.java │ │ │ ├── TableVisualizer.java │ │ │ └── Visualizer.java │ └── resources │ │ └── simplelogger.properties │ └── test │ ├── java │ └── com │ │ └── skuehnel │ │ └── dbvisualizer │ │ ├── ConfigurationTest.java │ │ ├── report │ │ └── ReportGeneratorTest.java │ │ └── visualize │ │ └── VisualizerTest.java │ └── resources │ └── test.properties ├── example ├── README.md ├── dbvisualizer.dot ├── dbvisualizer.pdf ├── dbvisualizer.png ├── dbvisualizer.sql ├── dbvisualizer_preview.png ├── postgresql_test.dot ├── postgresql_test.md ├── postgresql_test.png └── postgresql_test.sql ├── maven-plugin ├── .gitignore ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── skuehnel │ └── dbvisualizer │ └── mavenplugin │ └── DBVisualizerMavenPluginMojo.java ├── plugin-demo ├── README.md ├── pom.xml └── src │ └── main │ └── resources │ ├── init.sql │ └── postgresql_demo.sql └── pom.xml /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven 3 | 4 | # This workflow uses actions that are not certified by GitHub. 5 | # They are provided by a third-party and are governed by 6 | # separate terms of service, privacy policy, and support 7 | # documentation. 8 | 9 | name: Java CI with Maven 10 | 11 | on: 12 | push: 13 | branches: [ "master" ] 14 | pull_request: 15 | branches: [ "master" ] 16 | 17 | jobs: 18 | build: 19 | 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v3 24 | - name: Set up JDK 11 25 | uses: actions/setup-java@v3 26 | with: 27 | java-version: '11' 28 | distribution: 'temurin' 29 | cache: maven 30 | - name: Build with Maven 31 | run: mvn -B package --file pom.xml 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/** 2 | .vscode/** 3 | target/** 4 | **/**.class 5 | **/**.iml -------------------------------------------------------------------------------- /LICENCE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![GitHub](https://img.shields.io/github/license/eska-muc/dbvisualizer.svg) 2 | [![GitHub forks](https://img.shields.io/github/forks/eska-muc/dbvisualizer)](https://github.com/eska-muc/dbvisualizer/network) 3 | [![GitHub Org's stars](https://img.shields.io/github/stars/eska-muc/dbvisualizer)](https://github.com/eska-muc/dbvisualizer/stargazers) 4 | ![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/eska-muc/dbvisualizer/maven.yml) 5 | 6 | # DBVisualizer 7 | 8 | A tool which creates ER-Diagrams as a PNG, PDF, SVG file or as .dot input file for [GraphViz](https://graphviz.org/) 9 | or [PlantUML](https://plantuml.com/) and textual reports (in HTML, MARKDOWN or PDF format) about tables and columns from 10 | a database using JDBC 11 | metadata retrieval. 12 | 13 | ![Example (generated with PlantUML)](https://github.com/eska-muc/dbvisualizer/blob/master/example/postgresql_test.png) 14 | 15 | ### Latest news 16 | 17 | #### 2023-01 18 | 19 | * Configuration can be read from a .properties file (new option -C) 20 | 21 | #### 2022-12 22 | 23 | * Maven Plugin 24 | * Direct integration of PlantUML (as dependency). Diagrams in .png, .pdf and .svg format can be generated directly now 25 | without the necessity to call PlantUML manually 26 | 27 | ### Examples 28 | 29 | [Examples](./example/README.md) 30 | 31 | ## Compilation 32 | 33 | Just do 34 | 35 | mvn clean install 36 | 37 | This creates a "fat" .jar with all dependencies using the maven assembly plugin. 38 | 39 | ## Start 40 | 41 | ### Maven Plugin 42 | 43 | For an example how to use DBVisualizer as a maven plugin, just switch to the directory "plugin-demo", edit the 44 | configuration section 45 | in the pom.xml and run "mvn install". 46 | 47 | [Documentation](./maven-plugin/README.md) 48 | 49 | ### CLI 50 | 51 | For convenience all required options (for the database connection and the output generation) can be configured using a 52 | .properties file, like this: 53 | 54 | database.dialect=PostgreSQL 55 | database.jdbc.url=jdbc:postgresql://[::1]:5432/test 56 | database.jdbc.driver.class=org.postgresql.Driver 57 | database.jdbc.driver.path=c:/Users/_your_name_/.m2/repository/org/postgresql/postgresql/42.3.3/postgresql-42.3.3.jar 58 | output.graphviz.lroption=false 59 | output.diagram.entitiesonly=false 60 | output.diagram.format=PNG 61 | database.user=_replace_with_real_username_ 62 | database.password=_replace_with_real_password_ 63 | database.schema=test 64 | #not required for PostgreSQL 65 | #database.catalog= 66 | #database.filter= 67 | output.report.format=MARKDOWN 68 | output.report.metadata=true 69 | output.diagram.filename=postgres_test_with_properties.png 70 | output.report.filename=postgres_test_with_properties_report.md 71 | 72 | To use such a configuration file, just call 73 | 74 | java -jar app/target/dbvisualizer-1.0.0-SNAPSHOT-jar-with-dependencies.jar -C 75 | 76 | You can also specify some of the options in the configuration file and some at runtime. The options specified via 77 | command line options will have priority over the values from the properties file. 78 | 79 | For example if you specify -a PDF -o test_diagram.pdf when executing DBVisualizer you will get the diagram as .PDF 80 | even if the value in the properties file for property "output.diagram.format" was set to PNG. 81 | 82 | To get a list of all options call DBVisualizer like this: 83 | 84 | java -jar app/target/dbvisualizer-1.0.0-SNAPSHOT-jar-with-dependencies.jar 85 | 86 | All command line options are listed: 87 | 88 | usage: DBVisualizer [-a ] [-C ] [-c ] [-d ] -driver 89 | [-driverpath ] [-e] [-f ] [-F ] [-l] [-m] -o 90 | [-p ] -r [-s ] [-t ] [-u ] -url 91 | 92 | Gets all (matching) tables from given database connection and generates an 93 | outputfile in the specified format (default: .dot) 94 | -a,--format Format: DOT (default), PLANT, PNG, 95 | SVG, PDF 96 | -c,--catalog Name of the catalog to retrieve 97 | tables from. Default: null. 98 | -C,--config Name of a configuration file. 99 | -d,--dialect DB dialect. Possible values are 100 | PostgreSQL, MySQL, Oracle 101 | -driver,--jdbc-driver Class name of the JDBC driver 102 | (mandatory). 103 | -driverpath,--jdbc-driver-path Path to the driver classes. If 104 | this option is not specified, the 105 | driver is searched in CLASSPATH. 106 | -e,--entities-only Show only entities and relations 107 | in output (no attributes/columns). 108 | -f,--filter Regular expression (Java flavor) 109 | which is applied on table names 110 | -F,--report-format Format of the Report file. 111 | Supported formats are: html, pdf 112 | and markdown 113 | -l,--enable-lr Use GraphViz option ranking=LR; 114 | Graph layout from left to right. 115 | -m,--report-metainformation Include some meta information 116 | (e.g. report generation date) in 117 | the generated report. 118 | -o,--output-file Name of the output file 119 | (mandatory). 120 | -p,--password Password for database connection. 121 | -r,--report-file Name of the report file. If 122 | omitted, no report will be 123 | generated. 124 | -s,--schema Name of the schema to retrieve 125 | tables from. Default: all schemas. 126 | -t,--tables TestDBGenerator only: number of 127 | tables. 128 | -u,--user User name for database connection 129 | -url,--jdbc-url JDBC URL (mandatory). 130 | 131 | Example (assuming a PostgreSQL database "test" on localhost, port 5432): 132 | 133 | java -jar target/dbvisualizer-1-SNAPSHOT-jar-with-dependencies.jar -driverpath ./postgresql-42.3.1.jar -driver org.postgresql.Driver -a PNG -o postgresql_test_diagram.png -d PostgreSQL -s test -u test -p "test123" -url jdbc:postgresql://localhost:5432/test 134 | 135 | Tip: For very large schemas it might be useful to apply an filter and generate 136 | several smaller diagrams instead of one large. 137 | 138 | ## Supported Databases 139 | 140 | Tested with PostgreSQL,H2, MySQL and OracleXE 18c. 141 | 142 | ## PlantUML 143 | 144 | [PlantUML](https://plantuml.com/ie-diagram) is used internally when output formats PNG, SVG or PDF for the diagram are 145 | specified. 146 | Since there is a dependency on PlantUML defined in the pom of DBVisualizer, no explicit installation of PlantUML is 147 | required. 148 | If you are interested in the generated input file for PlantUML, the format specification "PLANT" can be used with 149 | (commandline option -a). In this case, a text input file for PlantUML is generated, which can be converted into one of 150 | the target formats of PlantUML like this (name of the .jar file can be different, -tpdf stands for target format PDF): 151 | 152 | java -jar target/plantuml-1.2021.16-SNAPSHOT-jar-with-dependencies.jar -tpdf 153 | 154 | For a full reference of PlantUML Command Line refer to 155 | the [documentation](https://plantuml.com/command-line#458de91d76a8569c) 156 | 157 | ## GraphViz 158 | 159 | By default the output file is in the .dot-format of [GraphViz](http://www.graphviz.org). To generate a .pdf-file just 160 | type 161 | 162 | dot -Tpdf -odiagram.pdf 163 | 164 | You may also try 165 | 166 | neato -Goverlap=false -Gmodel=subset -Tpdf -odiagram.pdf 167 | 168 | ## Reports 169 | 170 | Using the option -r with a filename, a tabular report on the tables and columns will be written in the specified file. 171 | Following formats (option -F) are supported: 172 | * HTML (default) 173 | * MARKDOWN 174 | * PDF 175 | 176 | For PDF the library [easytable](https://github.com/vandeseer/easytable) is used. 177 | 178 | ## TestDBGenerator 179 | 180 | If you do not have access to a complex schema, you can generate one using TestDBGenerator. 181 | It creates either an SQL DDL (DDL - Data Definition Language) file or directly a .dot file. 182 | I've used the DDL primarily for end to end testing of DBVisualizer. The examples have been 183 | generated with TestDBGenerator as well. 184 | 185 | Start TestDBGenerator like this: 186 | 187 | java -cp target/dbvisualizer-1-SNAPSHOT-jar-with-dependencies.jar com.skuehnel.dbvisualizer.util.TestDBGenerator 188 | 189 | Command line options are: 190 | 191 | usage: TestDBGenerator -f -n -t 192 | Creates a DDL .sql file or a .dot file with some randomly generated 193 | tables. 194 | -f,--file Name of the output file. 195 | -n,--num Number of tables to be generated. 196 | -t,--type Type of test file. Either sql or dot. 197 | 198 | ## Native-image build with GraalVM 199 | 200 | If you want to leverage [GraalVM's](https://www.graalvm.org/) capability to build 201 | [native-images](https://www.graalvm.org/latest/reference-manual/native-image/), 202 | you can do so by following the below steps: 203 | 204 | - [Install GraalVM](https://www.graalvm.org/latest/docs/getting-started/#install-graalvm) on your system. 205 | - [Install the native-image](https://www.graalvm.org/latest/docs/getting-started/#native-image) functionality of `GraalVM`. 206 | - Depending on your OS, the linker might require `libfreetype.a` during the native-image build of this project; 207 | in my case (Ubuntu 20.04) I did it via `sudo apt-get install libfreetype6-dev`. 208 | - If not already done, clone this project with `git`. 209 | - Add the driver of the database you want to build this native-image for to the dependency list in `pom.xml`. 210 | E.g. for `PostgreSQL` I added: 211 | ``` 212 | 213 | org.postgresql 214 | postgresql 215 | 42.3.0 216 | 217 | ``` 218 | - From the root folder of the project build the app as usual with `mvn clean install` 219 | - Now, we will execute the application as we usually would, but with an agent attached 220 | that collects configurations for the native-image build and puts into the right folder: 221 | ``` 222 | java -agentlib:native-image-agent=config-output-dir=app/src/main/resources/META-INF/native-image -jar app/target/dbvisualizer-app-1.0.0-SNAPSHOT-jar-with-dependencies.jar -driver org.postgresql.Driver -a PLANT -o app/target/postgresql_test.puml -d PostgreSQL -u -p -url -r app/target/postgresql_test.html 223 | ``` 224 | You will be able to see the files in `app/src/main/resources/META-INF/native-image`. 225 | - We run `mvn clean install` again. The first time we did it was just for being able to 226 | collect the required configurations. Now we build the app including the configurations. 227 | - Switch into the target folder: `cd app/target` 228 | - Next, create the native-image from the jar we just built by executing: 229 | ``` 230 | native-image -jar dbvisualizer-app-1.0.0-SNAPSHOT-jar-with-dependencies.jar 231 | ``` 232 | - To finally run the native-image, execute: 233 | ``` 234 | ./dbvisualizer-app-1.0.0-SNAPSHOT-jar-with-dependencies -driver org.postgresql.Driver -a PLANT -o ../postgresql_test.puml -d PostgreSQL -u -p -url -r ../postgresql_test.html 235 | ``` 236 | 237 | ## Ideas for future enhancements 238 | 239 | List of some features, which might be added in the future: 240 | 241 | * Add more automated tests for different databases 242 | * run as REST service and provide a web UI, probably using a JS framework like [visjs.org](http://visjs.org/) 243 | or [D3js](https://d3js.org/) for visualization 244 | 245 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/** 2 | .vscode/** 3 | target/** 4 | **/**.class -------------------------------------------------------------------------------- /app/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.skuehnel 6 | dbvisualizer 7 | 1.0.0-SNAPSHOT 8 | 9 | com.skuehnel 10 | dbvisualizer-app 11 | 1.0.0-SNAPSHOT 12 | DB Visualizer App 13 | 14 | Creates a dot graph description from a database schema using JDBC 15 | 16 | 17 | org.junit.jupiter 18 | junit-jupiter 19 | 5.8.2 20 | test 21 | 22 | 23 | org.junit.jupiter 24 | junit-jupiter-engine 25 | 5.8.2 26 | test 27 | 28 | 29 | org.apache.commons 30 | commons-lang3 31 | 3.12.0 32 | 33 | 34 | commons-cli 35 | commons-cli 36 | 1.5.0 37 | 38 | 39 | org.apache.commons 40 | commons-text 41 | 1.10.0 42 | 43 | 44 | org.slf4j 45 | slf4j-simple 46 | 2.0.7 47 | 48 | 49 | com.github.vandeseer 50 | easytable 51 | 0.8.5 52 | 53 | 54 | net.sourceforge.plantuml 55 | plantuml 56 | 1.2023.10 57 | 58 | 59 | org.apache.xmlgraphics 60 | batik-rasterizer 61 | 1.17 62 | 63 | 64 | org.apache.xmlgraphics 65 | batik-transcoder 66 | 1.17 67 | 68 | 69 | org.apache.xmlgraphics 70 | fop 71 | 2.8 72 | 73 | 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-surefire-plugin 79 | 3.0.0-M5 80 | 81 | 82 | org.apache.maven.plugins 83 | maven-compiler-plugin 84 | 3.8.1 85 | 86 | 11 87 | 11 88 | 89 | 90 | 91 | org.apache.maven.plugins 92 | maven-assembly-plugin 93 | 3.1.1 94 | 95 | 96 | jar-with-dependencies 97 | 98 | 99 | 100 | com.skuehnel.dbvisualizer.DBVisualizer 101 | 102 | 103 | 104 | 105 | 106 | make-assembly 107 | package 108 | 109 | single 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/DBVisualizer.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer; 2 | 3 | import java.io.*; 4 | import java.sql.SQLException; 5 | import java.util.Arrays; 6 | import java.util.List; 7 | import java.util.Properties; 8 | import java.util.regex.Pattern; 9 | import java.util.regex.PatternSyntaxException; 10 | 11 | import com.skuehnel.dbvisualizer.domain.Model; 12 | import com.skuehnel.dbvisualizer.report.ReportGenerator; 13 | import com.skuehnel.dbvisualizer.report.ReportGeneratorFactory; 14 | import com.skuehnel.dbvisualizer.util.MissingMandatoryException; 15 | import net.sourceforge.plantuml.FileFormat; 16 | import net.sourceforge.plantuml.FileFormatOption; 17 | import net.sourceforge.plantuml.SourceStringReader; 18 | import org.apache.commons.cli.CommandLine; 19 | import org.apache.commons.cli.CommandLineParser; 20 | import org.apache.commons.cli.DefaultParser; 21 | import org.apache.commons.cli.Option; 22 | import org.apache.commons.cli.ParseException; 23 | import org.apache.commons.lang3.StringUtils; 24 | import org.slf4j.Logger; 25 | import org.slf4j.LoggerFactory; 26 | 27 | import com.skuehnel.dbvisualizer.retrieve.ConnectionException; 28 | import com.skuehnel.dbvisualizer.retrieve.JDBCConnection; 29 | import com.skuehnel.dbvisualizer.retrieve.ERModelRetriever; 30 | import com.skuehnel.dbvisualizer.util.DB_DIALECT; 31 | import com.skuehnel.dbvisualizer.util.FORMAT; 32 | import com.skuehnel.dbvisualizer.util.REPORT_FORMAT; 33 | import com.skuehnel.dbvisualizer.util.OPTS; 34 | import com.skuehnel.dbvisualizer.visualize.Visualizer; 35 | 36 | /** 37 | * Project DBVisualizer 38 | *

39 | * Main class with command line interface 40 | * 41 | * @author Stefan Kuehnel 42 | */ 43 | public class DBVisualizer { 44 | 45 | private static final Logger LOGGER = LoggerFactory.getLogger(DBVisualizer.class); 46 | 47 | 48 | public static class DBVisualizerBuilder { 49 | 50 | private static final Logger LOGGER = LoggerFactory.getLogger(DBVisualizerBuilder.class); 51 | 52 | private DBVisualizer instance; 53 | 54 | public DBVisualizerBuilder() { 55 | instance = new DBVisualizer(); 56 | } 57 | 58 | public static DBVisualizerBuilder builder() { 59 | return new DBVisualizerBuilder(); 60 | } 61 | 62 | public DBVisualizerBuilder withOutputFileName(String outputFileName) { 63 | instance.setOutputFileName(outputFileName); 64 | return this; 65 | } 66 | 67 | public DBVisualizerBuilder withJdbcDriver(String jdbcDriver) { 68 | instance.setJdbcDriver(jdbcDriver); 69 | return this; 70 | } 71 | 72 | public DBVisualizerBuilder withJdbcUrl(String jbdcUrl) { 73 | instance.setJdbcUrl(jbdcUrl); 74 | return this; 75 | } 76 | 77 | public DBVisualizerBuilder withCatalog(String catalog) { 78 | instance.setCatalog(catalog); 79 | return this; 80 | } 81 | 82 | public DBVisualizerBuilder withDatabaseUser(String databaseUser) { 83 | instance.setDatabaseUser(databaseUser); 84 | return this; 85 | } 86 | 87 | public DBVisualizerBuilder withDatabasePassword(String databasePassword) { 88 | instance.setDatabasePassword(databasePassword); 89 | return this; 90 | } 91 | 92 | public DBVisualizerBuilder withSchema(String schema) { 93 | instance.setSchema(schema); 94 | return this; 95 | } 96 | 97 | public DBVisualizerBuilder withOutputFormat(String outputFormat) { 98 | if (StringUtils.isNotEmpty(outputFormat)) { 99 | FORMAT format = FORMAT.valueOf(outputFormat.toUpperCase()); 100 | instance.setOutputFormat(format); 101 | } else { 102 | LOGGER.warn("Ignoring empty output format"); 103 | } 104 | return this; 105 | } 106 | 107 | public DBVisualizerBuilder withDBDialect(String dialect) { 108 | if (StringUtils.isNotEmpty(dialect)) { 109 | DB_DIALECT db_dialect = DB_DIALECT.valueOf(dialect.toUpperCase()); 110 | instance.setDbDialect(db_dialect); 111 | } else { 112 | LOGGER.warn("Ignoring empty db dialect"); 113 | } 114 | return this; 115 | } 116 | 117 | public DBVisualizerBuilder withDbDialect(String dbDialect) { 118 | if (StringUtils.isNotEmpty(dbDialect)) { 119 | DB_DIALECT db_dialect = DB_DIALECT.valueOf(dbDialect); 120 | instance.setDbDialect(db_dialect); 121 | } else { 122 | LOGGER.warn("Ignoring empty db dialect"); 123 | } 124 | return this; 125 | } 126 | 127 | public DBVisualizerBuilder withFilter(String filter) { 128 | if (StringUtils.isNotEmpty(filter)) { 129 | Pattern filterPattern = Pattern.compile(filter); 130 | instance.setFilter(filterPattern); 131 | } else { 132 | LOGGER.warn("Ignoring empty filter"); 133 | } 134 | return this; 135 | } 136 | 137 | public DBVisualizerBuilder withReportFile(String reportFile) { 138 | instance.setReportFile(reportFile); 139 | return this; 140 | } 141 | 142 | public DBVisualizerBuilder withReportFormat(String reportFormat) { 143 | if (StringUtils.isNotEmpty(reportFormat)) { 144 | REPORT_FORMAT report_format = REPORT_FORMAT.valueOf(reportFormat); 145 | instance.setReportFormat(report_format); 146 | } else { 147 | LOGGER.warn("Ignoring empty report format"); 148 | } 149 | return this; 150 | } 151 | 152 | public DBVisualizerBuilder withReportMetadata(boolean reportMetadata) { 153 | instance.setReportMeta(reportMetadata); 154 | return this; 155 | } 156 | 157 | public DBVisualizer build() { 158 | return instance; 159 | } 160 | 161 | } 162 | 163 | private String outputFileName; 164 | private String jdbcDriver; 165 | private String jdbcUrl; 166 | private String jdbcDriverPath; 167 | private String databaseUser; 168 | private String databasePassword; 169 | private String catalog = null; 170 | private String configFile = null; 171 | private String schema; 172 | private FORMAT outputFormat = FORMAT.DOT; 173 | private DB_DIALECT dbDialect = DB_DIALECT.MYSQL; 174 | private boolean lROption = false; 175 | private boolean entitiesOnly = false; 176 | private Pattern filter; 177 | private String reportFile; 178 | private REPORT_FORMAT reportFormat = REPORT_FORMAT.HTML; 179 | private boolean reportMeta = false; 180 | 181 | /** 182 | * Getter for attribute outputFileName 183 | * 184 | * @return current value of field outputFileName 185 | */ 186 | public String getOutputFileName() { 187 | return outputFileName; 188 | } 189 | 190 | /** 191 | * Setter for field outputFileName 192 | * 193 | * @param outputFileName new value 194 | */ 195 | public void setOutputFileName(String outputFileName) { 196 | this.outputFileName = outputFileName; 197 | } 198 | 199 | /** 200 | * Getter for attribute jdbcDriver 201 | * 202 | * @return current value of field jdbcDriver 203 | */ 204 | public String getJdbcDriver() { 205 | return jdbcDriver; 206 | } 207 | 208 | /** 209 | * Setter for field jdbcDriver 210 | * 211 | * @param jdbcDriver new value 212 | */ 213 | public void setJdbcDriver(String jdbcDriver) { 214 | this.jdbcDriver = jdbcDriver; 215 | } 216 | 217 | /** 218 | * Getter for attribute jdbcUrl 219 | * 220 | * @return current value of field jdbcUrl 221 | */ 222 | public String getJdbcUrl() { 223 | return jdbcUrl; 224 | } 225 | 226 | /** 227 | * Setter for field jdbcUrl 228 | * 229 | * @param jdbcUrl new value 230 | */ 231 | public void setJdbcUrl(String jdbcUrl) { 232 | this.jdbcUrl = jdbcUrl; 233 | } 234 | 235 | /** 236 | * Getter for attribute jdbcDriverPath 237 | * 238 | * @return current value of field jdbcDriverPath 239 | */ 240 | public String getJdbcDriverPath() { 241 | return jdbcDriverPath; 242 | } 243 | 244 | /** 245 | * Setter for field jdbcDriverPath 246 | * 247 | * @param jdbcDriverPath new value 248 | */ 249 | public void setJdbcDriverPath(String jdbcDriverPath) { 250 | this.jdbcDriverPath = jdbcDriverPath; 251 | } 252 | 253 | /** 254 | * Getter for attribute databaseUser 255 | * 256 | * @return current value of field databaseUser 257 | */ 258 | public String getDatabaseUser() { 259 | return databaseUser; 260 | } 261 | 262 | /** 263 | * Setter for field databaseUser 264 | * 265 | * @param databaseUser new value 266 | */ 267 | public void setDatabaseUser(String databaseUser) { 268 | this.databaseUser = databaseUser; 269 | } 270 | 271 | /** 272 | * Getter for attribute databasePassword 273 | * 274 | * @return current value of field databasePassword 275 | */ 276 | public String getDatabasePassword() { 277 | return databasePassword; 278 | } 279 | 280 | /** 281 | * Setter for field databasePassword 282 | * 283 | * @param databasePassword new value 284 | */ 285 | public void setDatabasePassword(String databasePassword) { 286 | this.databasePassword = databasePassword; 287 | } 288 | 289 | /** 290 | * Getter for attribute catalog 291 | * 292 | * @return current value of field catalog 293 | */ 294 | public String getCatalog() { 295 | return catalog; 296 | } 297 | 298 | /** 299 | * Setter for field catalog 300 | * 301 | * @param catalog new value 302 | */ 303 | public void setCatalog(String catalog) { 304 | this.catalog = catalog; 305 | } 306 | 307 | /** 308 | * Getter for attribute schema 309 | * 310 | * @return current value of field schema 311 | */ 312 | public String getSchema() { 313 | return schema; 314 | } 315 | 316 | /** 317 | * Setter for field schema 318 | * 319 | * @param schema new value 320 | */ 321 | public void setSchema(String schema) { 322 | this.schema = schema; 323 | } 324 | 325 | /** 326 | * Getter for attribute outputFormat 327 | * 328 | * @return current value of field outputFormat 329 | */ 330 | public FORMAT getOutputFormat() { 331 | return outputFormat; 332 | } 333 | 334 | /** 335 | * Setter for field outputFormat 336 | * 337 | * @param outputFormat new value 338 | */ 339 | public void setOutputFormat(FORMAT outputFormat) { 340 | this.outputFormat = outputFormat; 341 | } 342 | 343 | /** 344 | * Getter for attribute dbDialect 345 | * 346 | * @return current value of field dbDialect 347 | */ 348 | public DB_DIALECT getDbDialect() { 349 | return dbDialect; 350 | } 351 | 352 | /** 353 | * Setter for field dbDialect 354 | * 355 | * @param dbDialect new value 356 | */ 357 | public void setDbDialect(DB_DIALECT dbDialect) { 358 | this.dbDialect = dbDialect; 359 | } 360 | 361 | /** 362 | * Getter for attribute lROption 363 | * 364 | * @return current value of field lROption 365 | */ 366 | public boolean islROption() { 367 | return lROption; 368 | } 369 | 370 | /** 371 | * Setter for field lROption 372 | * 373 | * @param lROption new value 374 | */ 375 | public void setlROption(boolean lROption) { 376 | this.lROption = lROption; 377 | } 378 | 379 | /** 380 | * Getter for attribute entitiesOnly 381 | * 382 | * @return current value of field entitiesOnly 383 | */ 384 | public boolean isEntitiesOnly() { 385 | return entitiesOnly; 386 | } 387 | 388 | /** 389 | * Setter for field entitiesOnly 390 | * 391 | * @param entitiesOnly new value 392 | */ 393 | public void setEntitiesOnly(boolean entitiesOnly) { 394 | this.entitiesOnly = entitiesOnly; 395 | } 396 | 397 | /** 398 | * Getter for attribute filter 399 | * 400 | * @return current value of field filter 401 | */ 402 | public Pattern getFilter() { 403 | return filter; 404 | } 405 | 406 | /** 407 | * Setter for field filter 408 | * 409 | * @param filter new value 410 | */ 411 | public void setFilter(Pattern filter) { 412 | this.filter = filter; 413 | } 414 | 415 | /** 416 | * Getter for attribute reportFile 417 | * 418 | * @return current value of field reportFile 419 | */ 420 | public String getReportFile() { 421 | return reportFile; 422 | } 423 | 424 | /** 425 | * Setter for field reportFile 426 | * 427 | * @param reportFile new value 428 | */ 429 | public void setReportFile(String reportFile) { 430 | this.reportFile = reportFile; 431 | } 432 | 433 | /** 434 | * Getter for attribute reportFormat 435 | * 436 | * @return current value of field reportFormat 437 | */ 438 | public REPORT_FORMAT getReportFormat() { 439 | return reportFormat; 440 | } 441 | 442 | /** 443 | * Setter for field reportFormat 444 | * 445 | * @param reportFormat new value 446 | */ 447 | public void setReportFormat(REPORT_FORMAT reportFormat) { 448 | this.reportFormat = reportFormat; 449 | } 450 | 451 | /** 452 | * Getter for attribute reportMeta 453 | * 454 | * @return current value of field reportMeta 455 | */ 456 | public boolean isReportMeta() { 457 | return reportMeta; 458 | } 459 | 460 | /** 461 | * Setter for field reportMeta 462 | * 463 | * @param reportMeta new value 464 | */ 465 | public void setReportMeta(boolean reportMeta) { 466 | this.reportMeta = reportMeta; 467 | } 468 | 469 | /** 470 | * Getter for attribute configFile 471 | * 472 | * @return current value of field configFile 473 | */ 474 | public String getConfigFile() { 475 | return configFile; 476 | } 477 | 478 | /** 479 | * Setter for field configFile 480 | * 481 | * @param configFile new value 482 | */ 483 | public void setConfigFile(String configFile) { 484 | this.configFile = configFile; 485 | } 486 | 487 | /** 488 | * Default constructor 489 | */ 490 | public DBVisualizer() { 491 | } 492 | 493 | /** 494 | * Constructor 495 | * 496 | * @param commandline the commandline 497 | * @throws ConnectionException if the connection to the database could not be established 498 | * @throws SQLException if the execution of an SQL command failed 499 | */ 500 | public DBVisualizer(CommandLine commandline) { 501 | try { 502 | assignCommandLineOptionsAndConfigurationValues(commandline); 503 | } catch (MissingMandatoryException missingMandatoryException) { 504 | LOGGER.error("Mandatory option was not set.", missingMandatoryException); 505 | System.exit(1); 506 | } 507 | } 508 | 509 | public void execute() throws ConnectionException, SQLException, IOException { 510 | LOGGER.debug("Initializing connection to DB with driver '{}', driver path {}, url '{}' and user '{}'.", jdbcDriver, jdbcDriverPath != null ? jdbcDriverPath : "n/a", jdbcUrl, databaseUser); 511 | JDBCConnection jdbcConnection = new JDBCConnection(jdbcDriver, jdbcDriverPath, jdbcUrl, databaseUser, databasePassword); 512 | ERModelRetriever retrievER = new ERModelRetriever(jdbcConnection.getConnection(), dbDialect); 513 | retrievER.setFilter(filter); 514 | Model model = retrievER.getModel(catalog, schema); 515 | model.setJdbcURL(jdbcUrl); 516 | model.setFilterInfo(filter != null ? filter.toString() : null); 517 | Visualizer visualizer = new Visualizer(model.getTableList()); 518 | visualizer.setLrEnabled(lROption); 519 | visualizer.setEntitiesOnly(entitiesOnly); 520 | // Create an additional report 521 | if (reportFile != null) { 522 | ReportGenerator reportGenerator = ReportGeneratorFactory.createReportGeneratorInstance(reportFormat.toString()); 523 | if (reportMeta) { 524 | reportGenerator.initMetaInformation(model); 525 | } 526 | reportGenerator.generateReport(reportFile, model, reportMeta ? ReportGenerator.REPORT_OPT.WITH_META_INFORMATION : null); 527 | } 528 | if (outputFormat.equals(FORMAT.DOT)) { 529 | OutputWriter writer = new OutputWriter(outputFileName, visualizer.getDotRepresentation()); 530 | writer.write(); 531 | } else if (outputFormat.equals(FORMAT.PLANT)) { 532 | OutputWriter writer = new OutputWriter(outputFileName, visualizer.getPlantRepresentation()); 533 | writer.write(); 534 | } else if (outputFormat.equals(FORMAT.PNG) || outputFormat.equals(FORMAT.SVG) || outputFormat.equals(FORMAT.PDF)) { 535 | FileFormatOption fileFormatOption = null; 536 | switch (outputFormat) { 537 | case PDF: 538 | LOGGER.info("Format for diagram: PDF"); 539 | fileFormatOption = new FileFormatOption(FileFormat.PDF); 540 | break; 541 | case PNG: 542 | LOGGER.info("Format for diagram: PNG"); 543 | fileFormatOption = new FileFormatOption(FileFormat.PNG); 544 | break; 545 | case SVG: 546 | LOGGER.info("Format for diagram: SVG"); 547 | fileFormatOption = new FileFormatOption(FileFormat.SVG); 548 | break; 549 | default: 550 | LOGGER.warn("Unsupported format"); 551 | break; 552 | } 553 | if (fileFormatOption != null) { 554 | String plantString = visualizer.getPlantRepresentation(); 555 | SourceStringReader sourceStringReader = new SourceStringReader(plantString); 556 | OutputStream outStream = new FileOutputStream(outputFileName); 557 | String description = sourceStringReader.outputImage(outStream, fileFormatOption).getDescription(); 558 | LOGGER.info("Description of output image: {}", description); 559 | } 560 | } 561 | } 562 | 563 | void assignCommandLineOptionsAndConfigurationValues(CommandLine commandLine) throws MissingMandatoryException { 564 | List

Meta information

"); 68 | stringBuilder.append(" \n"); 69 | for (Map.Entry metaEntry : metainfo.entrySet()) { 70 | String v = StringEscapeUtils.escapeHtml4(metaEntry.getValue()); 71 | stringBuilder.append(" \n"); 72 | stringBuilder.append(String.format(" \n", metaEntry.getKey(), v)); 73 | stringBuilder.append(" \n"); 74 | } 75 | stringBuilder.append("
%s%s
\n"); 76 | return stringBuilder.toString(); 77 | } 78 | 79 | @Override 80 | public void generateReport(String outputFilePath, Model theModel, REPORT_OPT... options) { 81 | LOGGER.debug("Creating HTML report in file {}", outputFilePath); 82 | File outputFile = new File(outputFilePath); 83 | FileWriter outputWriter; 84 | try { 85 | outputWriter = new FileWriter(outputFile); 86 | outputWriter.write(header(Arrays.asList( 87 | String.format("%s\n", getName(theModel)), 88 | "\n", 89 | "\n" 98 | ))); 99 | outputWriter.write(String.format("

Report on \"%s\"

\n", getName(theModel))); 100 | if (checkForOption(options, REPORT_OPT.WITH_META_INFORMATION)) { 101 | outputWriter.write(meta(getMetaInformation())); 102 | } 103 | for (Table t : theModel.getTableList()) { 104 | outputWriter.write(table(t)); 105 | } 106 | outputWriter.write(footer()); 107 | outputWriter.close(); 108 | } catch (IOException e) { 109 | LOGGER.error("Could not open output file.", e); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/report/MarkdownReportGenerator.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.report; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Column; 4 | import com.skuehnel.dbvisualizer.domain.Model; 5 | import com.skuehnel.dbvisualizer.domain.Table; 6 | import org.slf4j.Logger; 7 | import org.slf4j.LoggerFactory; 8 | 9 | import java.io.File; 10 | import java.io.FileWriter; 11 | import java.io.IOException; 12 | import java.util.Map; 13 | 14 | public class MarkdownReportGenerator extends AbstractReportGenerator implements ReportGenerator { 15 | 16 | private static final Logger LOGGER = LoggerFactory.getLogger(MarkdownReportGenerator.class); 17 | 18 | private static final String TABLE_ROW_SEPARATOR = "|----|-----------|----|-------|\n"; 19 | 20 | private String meta(Map metainformation) { 21 | StringBuilder builder = new StringBuilder(); 22 | if (metainformation != null && !metainformation.entrySet().isEmpty()) { 23 | builder.append("## Meta Information\n"); 24 | builder.append("| | Value |\n|---|---|\n"); 25 | for (Map.Entry entry : metainformation.entrySet()) { 26 | builder.append(String.format("| %s | %s |\n", entry.getKey(), nvl(entry.getValue(), ""))); 27 | } 28 | } 29 | return builder.toString(); 30 | } 31 | 32 | @Override 33 | public void generateReport(String outputFilePath, Model model, REPORT_OPT... options) { 34 | LOGGER.debug("Creating Markdown report in file {}", outputFilePath); 35 | File outputFile = new File(outputFilePath); 36 | FileWriter outputWriter; 37 | try { 38 | outputWriter = new FileWriter(outputFile); 39 | outputWriter.write(String.format("# Report on %s\n\n", getName(model))); 40 | if (checkForOption(options, REPORT_OPT.WITH_META_INFORMATION)) { 41 | outputWriter.write(meta(getMetaInformation())); 42 | } 43 | for (Table t : model.getTableList()) { 44 | outputWriter.write(String.format("## Table %s\n", t.getName())); 45 | outputWriter.write(String.format("%s\n", nvl(t.getComment(), ""))); 46 | outputWriter.write("### Columns\n\n"); 47 | outputWriter.write("|Name|Constraints|Type|Comment|\n"); 48 | outputWriter.write(TABLE_ROW_SEPARATOR); 49 | for (Column c : t.getColumns()) { 50 | outputWriter.write(String.format("|%s|%s|%s|%s|\n", c.getName(), nevl(constraints(c), " "), c.getType(), nvl(c.getComment(), " "))); 51 | } 52 | } 53 | outputWriter.close(); 54 | } catch (IOException e) { 55 | LOGGER.error("Caught an I/O exception."); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/report/PDFReportGenerator.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.report; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Column; 4 | import com.skuehnel.dbvisualizer.domain.Model; 5 | import org.apache.pdfbox.pdmodel.PDDocument; 6 | import org.apache.pdfbox.pdmodel.PDPage; 7 | import org.apache.pdfbox.pdmodel.common.PDRectangle; 8 | import org.apache.pdfbox.pdmodel.font.PDType1Font; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.vandeseer.easytable.RepeatedHeaderTableDrawer; 12 | import org.vandeseer.easytable.TableDrawer; 13 | import org.vandeseer.easytable.settings.HorizontalAlignment; 14 | import org.vandeseer.easytable.settings.VerticalAlignment; 15 | import org.vandeseer.easytable.structure.Row; 16 | import org.vandeseer.easytable.structure.Table; 17 | import org.vandeseer.easytable.structure.cell.TextCell; 18 | 19 | import java.io.IOException; 20 | import java.awt.Color; 21 | import java.util.Map; 22 | 23 | public class PDFReportGenerator extends AbstractReportGenerator implements ReportGenerator { 24 | 25 | private static final Logger LOGGER = LoggerFactory.getLogger(PDFReportGenerator.class); 26 | 27 | @Override 28 | public void generateReport(String outputFile, Model model, REPORT_OPT... options) { 29 | try (final PDDocument document = new PDDocument()) { 30 | 31 | if (checkForOption(options, REPORT_OPT.WITH_META_INFORMATION)) { 32 | addMetaPage(document); 33 | } 34 | 35 | for (com.skuehnel.dbvisualizer.domain.Table databaseTable : model.getTableList()) { 36 | 37 | PDPage page = new PDPage(PDRectangle.A4); 38 | float startY = 20; 39 | 40 | TableDrawer drawer = TableDrawer.builder() 41 | .table(createDatabaseTableDescriptionTable(page, databaseTable)) 42 | .startX(50) 43 | .startY(startY) 44 | .endY(200) 45 | .build(); 46 | drawer.draw(() -> document, () -> page, startY); 47 | 48 | RepeatedHeaderTableDrawer.builder() 49 | .table(createPdfTable(page, databaseTable)) 50 | .startX(50) 51 | .startY(drawer.getFinalY() - 50f) 52 | .endY(200) 53 | .numberOfRowsToRepeat(1) 54 | .build().draw(() -> document, () -> new PDPage(PDRectangle.A4), 50f); 55 | } 56 | document.save(outputFile); 57 | } catch (IOException ioException) { 58 | LOGGER.error("I/O Exception caught.", ioException); 59 | } 60 | } 61 | 62 | private void addMetaPage(PDDocument document) throws IOException { 63 | PDPage page = new PDPage(PDRectangle.A4); 64 | float startY = 20; 65 | Table.TableBuilder tableBuilder = Table.builder().addColumnsOfWidth(colWidth(page, 40), colWidth(page, 60)); 66 | Map metaInfo = getMetaInformation(); 67 | for (Map.Entry entry : metaInfo.entrySet()) { 68 | tableBuilder.addRow( 69 | Row.builder().add(createBodyCell(entry.getKey())) 70 | .add(createBodyCell(nvl(entry.getValue(), ""))) 71 | .build() 72 | ); 73 | } 74 | TableDrawer drawer = TableDrawer.builder().table(tableBuilder.build()) 75 | .startX(50) 76 | .startY(startY) 77 | .endY(200) 78 | .build(); 79 | drawer.draw(() -> document, () -> page, startY); 80 | } 81 | 82 | private Table createPdfTable(PDPage page, com.skuehnel.dbvisualizer.domain.Table table) { 83 | 84 | final Table.TableBuilder tableBuilder = Table.builder().addColumnsOfWidth(colWidth(page, 20), colWidth(page, 20), colWidth(page, 20), colWidth(page, 40)); 85 | tableBuilder.addRow(Row.builder() 86 | .add(createHeaderCell("Name")) 87 | .add(createHeaderCell("Constraints")) 88 | .add(createHeaderCell("Type")) 89 | .add(createHeaderCell("Description")) 90 | .build()); 91 | 92 | for (Column column : table.getColumns()) { 93 | tableBuilder.addRow( 94 | Row.builder() 95 | .add(createBodyCell(column.getName())) 96 | .add(createBodyCell(nevl(constraints(column), " "))) 97 | .add(createBodyCell(column.getType())) 98 | .add(createBodyCell(nvl(column.getComment(), " "))) 99 | .build()); 100 | } 101 | 102 | return tableBuilder.build(); 103 | } 104 | 105 | private TextCell createHeaderCell(String text) { 106 | return TextCell.builder() 107 | .font(PDType1Font.HELVETICA_BOLD) 108 | .text(text) 109 | .horizontalAlignment(HorizontalAlignment.CENTER) 110 | .padding(6f) 111 | .borderColor(Color.BLACK) 112 | .borderWidth(1f) 113 | .build(); 114 | } 115 | 116 | private TextCell createBodyCell(String text) { 117 | return TextCell.builder() 118 | .font(PDType1Font.HELVETICA) 119 | .text(text) 120 | .horizontalAlignment(HorizontalAlignment.LEFT) 121 | .verticalAlignment(VerticalAlignment.TOP) 122 | .padding(6f) 123 | .borderColor(Color.BLACK) 124 | .borderWidth(1f) 125 | .build(); 126 | } 127 | 128 | private float colWidth(PDPage page, int percentage) { 129 | float pageWidth = page.getMediaBox().getWidth(); 130 | float usable = pageWidth * 0.8f; 131 | return usable * ((float) percentage / 100f); 132 | } 133 | 134 | private Table createDatabaseTableDescriptionTable(PDPage pdPage, com.skuehnel.dbvisualizer.domain.Table table) throws IOException { 135 | return Table.builder() 136 | .addColumnsOfWidth(colWidth(pdPage, 100)) 137 | .addRow( 138 | Row.builder() 139 | .add(TextCell.builder() 140 | .font(PDType1Font.HELVETICA_BOLD) 141 | .fontSize(20) 142 | .horizontalAlignment(HorizontalAlignment.CENTER) 143 | .text(table.getName()).build()) 144 | .build() 145 | ) 146 | .addRow( 147 | Row.builder() 148 | .add(TextCell.builder() 149 | .font(PDType1Font.HELVETICA) 150 | .fontSize(12) 151 | .horizontalAlignment(HorizontalAlignment.LEFT) 152 | .text(nvl(table.getComment(), "")).build()) 153 | .build() 154 | ).build(); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/report/ReportGenerator.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.report; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Model; 4 | 5 | import java.util.HashMap; 6 | 7 | /** 8 | * Interface of the Report Generator 9 | */ 10 | public interface ReportGenerator { 11 | 12 | enum REPORT_OPT { 13 | WITH_META_INFORMATION 14 | } 15 | 16 | /** 17 | * Generate report from the model 18 | * 19 | * @param outputFile path to the output file 20 | * @param model the model 21 | * @param options list of reporting options 22 | */ 23 | void generateReport(String outputFile, Model model, REPORT_OPT... options); 24 | 25 | HashMap getMetaInformation(); 26 | 27 | void initMetaInformation(Model model); 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/report/ReportGeneratorFactory.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.report; 2 | 3 | /** 4 | * Factory for different implementations of the report generator 5 | */ 6 | public class ReportGeneratorFactory { 7 | public static ReportGenerator createReportGeneratorInstance(String format) { 8 | ReportGenerator reportGenerator; 9 | switch (format) { 10 | case "HTML": 11 | reportGenerator = new HTMLReportGenerator(); 12 | break; 13 | case "PDF": 14 | reportGenerator = new PDFReportGenerator(); 15 | break; 16 | case "MARKDOWN": 17 | reportGenerator = new MarkdownReportGenerator(); 18 | break; 19 | default: 20 | throw new RuntimeException("Unsupported Format"); 21 | } 22 | return reportGenerator; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/retrieve/ConnectionException.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.retrieve; 2 | 3 | /** 4 | * Project DBVisualizer 5 | * 6 | * @author Stefan Kuehnel 7 | * 8 | */ 9 | public class ConnectionException extends Exception { 10 | 11 | /** 12 | * Default Constructor 13 | */ 14 | public ConnectionException() { 15 | super(); 16 | } 17 | 18 | /** 19 | * Constructor 20 | * @param message a message 21 | */ 22 | public ConnectionException(String message) { 23 | super(message); 24 | } 25 | 26 | /** 27 | * Constructor 28 | * @param cause a root cause 29 | */ 30 | public ConnectionException(Throwable cause) { 31 | super(cause); 32 | } 33 | 34 | /** 35 | * Contructor 36 | * @param message a message 37 | * @param cause a cause 38 | */ 39 | public ConnectionException(String message, Throwable cause) { 40 | super(message, cause); 41 | } 42 | 43 | /** 44 | * Constructor 45 | * @param message a message 46 | * @param cause a cause 47 | * @param enableSuppression a boolean flag 48 | * @param writableStackTrace another flag 49 | */ 50 | public ConnectionException(String message, Throwable cause, 51 | boolean enableSuppression, boolean writableStackTrace) { 52 | super(message, cause, enableSuppression, writableStackTrace); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/retrieve/ERModelRetriever.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.retrieve; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DatabaseMetaData; 5 | import java.sql.JDBCType; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.HashSet; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Set; 14 | import java.util.regex.Pattern; 15 | 16 | import com.skuehnel.dbvisualizer.domain.Model; 17 | import org.slf4j.Logger; 18 | import org.slf4j.LoggerFactory; 19 | 20 | import com.skuehnel.dbvisualizer.domain.Column; 21 | import com.skuehnel.dbvisualizer.domain.Table; 22 | import com.skuehnel.dbvisualizer.util.DB_DIALECT; 23 | 24 | /** 25 | * Project DBVisualizer 26 | * 27 | * @author Stefan Kuehnel 28 | */ 29 | public class ERModelRetriever { 30 | 31 | private static final Logger LOGGER = LoggerFactory 32 | .getLogger(ERModelRetriever.class); 33 | 34 | private static final String COLUMN_SIZE = "COLUMN_SIZE"; 35 | private static final String TYPE_NAME = "TYPE_NAME"; 36 | private static final String COLUMN_NAME = "COLUMN_NAME"; 37 | private static final String COLUMN_REMARKS = "REMARKS"; 38 | private static final String DATA_TYPE = "DATA_TYPE"; 39 | private static final String DECIMAL_DIGITS = "DECIMAL_DIGITS"; 40 | private static final String TABLE_CATALOG = "TABLE_CATALOG"; 41 | private static final String TABLE_SCHEM = "TABLE_SCHEM"; 42 | private static final String TABLE_NAME = "TABLE_NAME"; 43 | private static final String TABLE_TYPE = "TABLE_TYPE"; 44 | private static final String TABLE_REMARKS = "REMARKS"; 45 | private static final String FKCOLUMN_NAME = "FKCOLUMN_NAME"; 46 | private static final String PKCOLUMN_NAME = "PKCOLUMN_NAME"; 47 | private static final String PKTABLE_CAT = "PKTABLE_CAT"; 48 | private static final String PKTABLE_SCHEM = "PKTABLE_SCHEM"; 49 | private static final String PKTABLE_NAME = "PKTABLE_NAME"; 50 | private static final String CHAR_OCTET_LENGTH = "CHAR_OCTET_LENGTH"; 51 | 52 | private Connection jdbcConnection; 53 | 54 | private static final String[] TABLE_TYPES = {"TABLE", "VIEW"}; 55 | 56 | private Map knownTables; 57 | 58 | private DB_DIALECT dbDialect; 59 | 60 | private Pattern filter; 61 | 62 | /** 63 | * Constructor 64 | * 65 | * @param jdbcConnection a {@link java.sql.Connection} object 66 | */ 67 | public ERModelRetriever(Connection jdbcConnection, DB_DIALECT dbDialect) { 68 | this.jdbcConnection = jdbcConnection; 69 | this.dbDialect = dbDialect; 70 | knownTables = new HashMap<>(); 71 | } 72 | 73 | /** 74 | * Retrieve a list of {@link com.skuehnel.dbvisualizer.domain.Table} objects 75 | * from the database 76 | * 77 | * @param catalog Catalog in which the schema(s) for which a model should be created are located. May be null 78 | * @param schema Schema for which the model shall be created 79 | * @return list of table objects 80 | * @throws SQLException if an error occurs 81 | */ 82 | public Model getModel(String catalog, String schema) throws SQLException { 83 | Model result = new Model(); 84 | result.setCatalogName(catalog); 85 | result.setSchemaName(schema); 86 | List tables = new ArrayList<>(); 87 | DatabaseMetaData databaseMetaData = jdbcConnection.getMetaData(); 88 | if (databaseMetaData != null) { 89 | 90 | if (schema == null || dbDialect == DB_DIALECT.H2) { 91 | 92 | ResultSet schemaResultSet = databaseMetaData.getSchemas(); 93 | if (schemaResultSet != null) { 94 | while (schemaResultSet.next()) { 95 | 96 | String currentCatalog = null; 97 | try { 98 | currentCatalog = schemaResultSet 99 | .getString(TABLE_CATALOG); 100 | } catch (SQLException e) { 101 | LOGGER.warn("Problem when trying to read Catalog information. Exception: '{}'", e); 102 | } 103 | String currentSchema = schemaResultSet 104 | .getString(TABLE_SCHEM); 105 | LOGGER.debug( 106 | "Going to retrieve tables for catalog '{}' and schema '{}'.", 107 | catalog, currentSchema); 108 | 109 | if (addCurrentSchema(dbDialect, schema, currentSchema)) { 110 | result.setSchemaName(currentSchema); 111 | List
tablesForSchema = getTables( 112 | databaseMetaData, currentCatalog, currentSchema); 113 | tables.addAll(tablesForSchema); 114 | } 115 | } 116 | schemaResultSet.close(); 117 | } 118 | } else { 119 | tables.addAll(getTables(databaseMetaData, catalog, schema)); 120 | } 121 | result.setDatabaseType(databaseMetaData.getDatabaseProductName() + " " + databaseMetaData.getDatabaseProductVersion()); 122 | 123 | } 124 | result.setTableList(tables); 125 | return result; 126 | } 127 | 128 | private boolean addCurrentSchema(DB_DIALECT dialect, String requiredSchema, String currentSchema) { 129 | // in H2 all schemas are returned, the rquired one needs to be filtered out 130 | if (dialect == DB_DIALECT.H2) { 131 | return requiredSchema != null && requiredSchema.equals(currentSchema); 132 | } 133 | return true; 134 | } 135 | 136 | /** 137 | * Setter. Set the filter for table names. 138 | * 139 | * @param filter new value for the table name filter pattern 140 | */ 141 | public void setFilter(Pattern filter) { 142 | this.filter = filter; 143 | } 144 | 145 | /** 146 | * Getter. The current filter pattern for table names 147 | * 148 | * @return the filter pattern for table names 149 | */ 150 | public Pattern getFilter() { 151 | return filter; 152 | } 153 | 154 | private List
getTables(DatabaseMetaData databaseMetaData, 155 | String catalog, String schema) throws SQLException { 156 | List
tablesForSchema = new ArrayList<>(); 157 | LOGGER.debug("Retrieving tables for catalog '{}' and schema '{}'", 158 | catalog, schema); 159 | ResultSet tablesResultSet = databaseMetaData.getTables(catalog, schema, 160 | null, TABLE_TYPES); 161 | if (tablesResultSet != null) { 162 | while (tablesResultSet.next()) { 163 | String tableName = tablesResultSet.getString(TABLE_NAME); 164 | String tableType = tablesResultSet.getString(TABLE_TYPE); 165 | String tableComment = tablesResultSet.getString(TABLE_REMARKS); 166 | if (filter != null && !filter.matcher(tableName).matches()) { 167 | LOGGER.debug("Table name {} does not match filter.", tableName); 168 | continue; 169 | } 170 | LOGGER.debug("Processing table: '{}' Type: '{}'", tableName, tableType); 171 | Set primaryKeyNames = getPrimaryKeysSet(databaseMetaData, catalog, schema, tableName); 172 | Map referencedTables = getReferencedTables(databaseMetaData, catalog, schema, tableName); 173 | List columns = getColumns(databaseMetaData, catalog, schema, tableName, primaryKeyNames, referencedTables); 174 | Table t = getTable(catalog, schema, tableName); 175 | t.setColumns(columns); 176 | t.setComment(tableComment); 177 | tablesForSchema.add(t); 178 | } 179 | tablesResultSet.close(); 180 | } else { 181 | LOGGER.warn("Result Set is empty"); 182 | } 183 | return tablesForSchema; 184 | } 185 | 186 | private List getColumns(DatabaseMetaData databaseMetaData, String catalog, String schema, String tableName, Set primaryKeyNames, Map referencedTables) throws SQLException { 187 | List columns = new ArrayList<>(); 188 | ResultSet columnResultSet = databaseMetaData.getColumns( 189 | catalog, schema, tableName, null); 190 | if (columnResultSet != null) { 191 | while (columnResultSet.next()) { 192 | String columnName = columnResultSet 193 | .getString(COLUMN_NAME); 194 | String columnComment = columnResultSet.getString(COLUMN_REMARKS); 195 | String dataType = getTypeDescription(columnResultSet); 196 | boolean nullable = checkBoolean(columnResultSet, 197 | "IS_NULLABLE", "yes"); 198 | LOGGER.debug("Column: '{}', Type: '{}'", columnName, 199 | dataType); 200 | Column column = new Column(columnName, dataType); 201 | column.setComment(columnComment); 202 | column.setNotNull(!nullable); 203 | if (primaryKeyNames.contains(columnName)) { 204 | LOGGER.debug("Column: '{}' is primary key!", 205 | columnName); 206 | column.setPrimaryKey(true); 207 | } 208 | if (referencedTables.containsKey(columnName)) { 209 | Table referencedTable = referencedTables 210 | .get(columnName); 211 | LOGGER.debug( 212 | "Column: '{}' is foreign key to table '{}'!", 213 | columnName, referencedTable.getName()); 214 | column.setForeignKeyTable(referencedTable); 215 | } 216 | columns.add(column); 217 | } 218 | columnResultSet.close(); 219 | } 220 | return columns; 221 | } 222 | 223 | private Map getReferencedTables(DatabaseMetaData databaseMetaData, String catalog, String schema, String tableName) throws SQLException { 224 | Map referencedTables = new HashMap<>(); 225 | ResultSet importedKeysRS = databaseMetaData.getImportedKeys( 226 | catalog, schema, tableName); 227 | if (importedKeysRS != null) { 228 | while (importedKeysRS.next()) { 229 | String fkColumnName = importedKeysRS 230 | .getString(FKCOLUMN_NAME); 231 | String referencedPkColumnName = importedKeysRS 232 | .getString(PKCOLUMN_NAME); 233 | 234 | if (fkColumnName != null) { 235 | String fkTableCat = null; 236 | if (dbDialect != DB_DIALECT.MYSQL) { 237 | // MySQL returns a cat here, even is no catalog is used overall 238 | fkTableCat = importedKeysRS 239 | .getString(PKTABLE_CAT); 240 | } 241 | String fkTableSchema = importedKeysRS 242 | .getString(PKTABLE_SCHEM); 243 | String fkTableName = importedKeysRS 244 | .getString(PKTABLE_NAME); 245 | LOGGER.debug( 246 | "FKCOLUMN_NAME: '{}' -> '{}' (PK of referenced table: '{}')", 247 | fkColumnName, fkTableName, 248 | referencedPkColumnName); 249 | 250 | // If catalog/schema information is null, use current catalog/schema 251 | if (fkTableSchema == null) { 252 | fkTableSchema = schema; 253 | } 254 | if (fkTableCat == null) { 255 | fkTableCat = catalog; 256 | } 257 | Table fkTable = getTable(fkTableCat, fkTableSchema, 258 | fkTableName); 259 | referencedTables.put(fkColumnName, fkTable); 260 | } 261 | } 262 | importedKeysRS.close(); 263 | } 264 | return referencedTables; 265 | } 266 | 267 | private Set getPrimaryKeysSet(DatabaseMetaData databaseMetaData, String catalog, String schema, String tableName) throws SQLException { 268 | ResultSet primaryKeysRS = databaseMetaData.getPrimaryKeys( 269 | catalog, schema, tableName); 270 | Set primaryKeyNames = new HashSet<>(); 271 | if (primaryKeysRS != null) { 272 | while (primaryKeysRS.next()) { 273 | String pkColumnName = primaryKeysRS 274 | .getString(COLUMN_NAME); 275 | if (pkColumnName != null) { 276 | primaryKeyNames.add(pkColumnName); 277 | } 278 | } 279 | primaryKeysRS.close(); 280 | } 281 | return primaryKeyNames; 282 | } 283 | 284 | /** 285 | * Create a data type description for this column 286 | * 287 | * @param columnResultSet result set of java.sql.DatabaseMetaData#getColumns 288 | * @return String representation of the data type of the column 289 | * @throws SQLException if an error occurs 290 | */ 291 | private String getTypeDescription(ResultSet columnResultSet) 292 | throws SQLException { 293 | StringBuilder buffer = new StringBuilder(); 294 | 295 | // initialize with a proper value, if type cannot be resolved 296 | JDBCType type = JDBCType.OTHER; 297 | int typeValue = columnResultSet.getInt(DATA_TYPE); 298 | 299 | try { 300 | type = JDBCType.valueOf(typeValue); 301 | } catch (IllegalArgumentException exception) { 302 | LOGGER.warn( 303 | "Integer constant '{}' does not seem to represent a known JDBCType.", 304 | typeValue); 305 | } 306 | 307 | int size = columnResultSet.getInt(COLUMN_SIZE); 308 | if (type != null) { 309 | if (columnResultSet.getString(TYPE_NAME) != null) { 310 | buffer.append(columnResultSet.getString(TYPE_NAME)); 311 | } else { 312 | buffer.append(type.name()); 313 | } 314 | if (type.equals(JDBCType.CHAR) || type.equals(JDBCType.VARCHAR) 315 | || type.equals(JDBCType.LONGNVARCHAR) 316 | || type.equals(JDBCType.LONGVARCHAR) 317 | || type.equals(JDBCType.NCHAR) 318 | || type.equals(JDBCType.NVARCHAR)) { 319 | buffer.append("("); 320 | buffer.append(size); 321 | buffer.append(")"); 322 | } else if (type.equals(JDBCType.DECIMAL) 323 | || type.equals(JDBCType.DOUBLE) 324 | || type.equals(JDBCType.FLOAT) 325 | || type.equals(JDBCType.REAL) 326 | || type.equals(JDBCType.NUMERIC)) { 327 | 328 | buffer.append("("); 329 | if (dbDialect == DB_DIALECT.ORACLE) { 330 | if (size == 0) { 331 | if (columnResultSet.getObject(CHAR_OCTET_LENGTH) != null) { 332 | size = columnResultSet.getInt(CHAR_OCTET_LENGTH); 333 | } 334 | } 335 | buffer.append(size); 336 | } else { 337 | buffer.append(size); 338 | } 339 | if (columnResultSet.getObject(DECIMAL_DIGITS) != null) { 340 | int fractionalDigits = columnResultSet.getInt(DECIMAL_DIGITS); 341 | if (fractionalDigits > 0) { 342 | buffer.append(','); 343 | buffer.append(fractionalDigits); 344 | } 345 | } 346 | 347 | buffer.append(")"); 348 | } 349 | } 350 | return buffer.toString(); 351 | } 352 | 353 | /** 354 | * Factory method for tables; each table shall only be created once 355 | * 356 | * @param catalog name of the catalog 357 | * @param schema name of the schema 358 | * @param tableName name of the table 359 | * @return a Table object 360 | */ 361 | private Table getTable(String catalog, String schema, String tableName) { 362 | String key = createKey(catalog, schema, tableName); 363 | Table t = knownTables.get(key); 364 | if (t == null) { 365 | t = new Table(key); 366 | t.setSimpleName(tableName); 367 | knownTables.put(key, t); 368 | } 369 | return t; 370 | } 371 | 372 | private String createKey(String catalog, String schema, String tableName) { 373 | StringBuilder keyBuilder = new StringBuilder(); 374 | if (catalog != null) { 375 | keyBuilder.append(catalog); 376 | keyBuilder.append('.'); 377 | } 378 | if (schema != null) { 379 | keyBuilder.append(schema); 380 | keyBuilder.append('.'); 381 | } 382 | keyBuilder.append(tableName); 383 | return keyBuilder.toString(); 384 | } 385 | 386 | private boolean checkBoolean(ResultSet rs, String columnName, 387 | String comparison) throws SQLException { 388 | boolean result = false; 389 | if (rs != null && columnName != null && comparison != null) { 390 | String stringValue = rs.getString(columnName); 391 | if (stringValue != null) { 392 | result = stringValue.equalsIgnoreCase(comparison); 393 | } 394 | } 395 | return result; 396 | } 397 | 398 | } 399 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/retrieve/JDBCConnection.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.retrieve; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | import org.slf4j.Logger; 5 | import org.slf4j.LoggerFactory; 6 | 7 | import java.io.File; 8 | import java.lang.reflect.InvocationTargetException; 9 | import java.net.MalformedURLException; 10 | import java.net.URL; 11 | import java.net.URLClassLoader; 12 | import java.sql.*; 13 | import java.util.Properties; 14 | 15 | /** 16 | * @author Stefan Kuehnel 17 | */ 18 | public class JDBCConnection { 19 | 20 | private final String driver; 21 | private final String driverPath; 22 | private final String url; 23 | private final String user; 24 | private final String password; 25 | 26 | private Connection connection; 27 | 28 | private static final Logger LOGGER = LoggerFactory.getLogger(JDBCConnection.class); 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @param driver name of the driver class 34 | * @param driverPath path for driver class (or .jar file) 35 | * @param url JDBC url 36 | * @param user name of DB user 37 | * @param password password of DB user 38 | */ 39 | public JDBCConnection(String driver, String driverPath, String url, String user, String password) throws ConnectionException { 40 | this.driver = driver; 41 | this.driverPath = driverPath; 42 | this.url = url; 43 | this.user = user; 44 | this.password = password; 45 | if (driver == null || url == null) { 46 | throw new ConnectionException("At least driver and url must be set."); 47 | } 48 | try { 49 | initialize(); 50 | } catch (Exception e) { 51 | throw new ConnectionException("Could not initialize database connection.", e); 52 | } 53 | } 54 | 55 | /** 56 | * Get the JDBC connection to the database 57 | * 58 | * @return a {@link java.sql.Connection} object 59 | */ 60 | public Connection getConnection() { 61 | return connection; 62 | } 63 | 64 | protected void initialize() throws ClassNotFoundException, MalformedURLException, SQLException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { 65 | if (StringUtils.isNotEmpty(driverPath)) { 66 | LOGGER.debug("Trying to load JBDC driver from path {}", driverPath); 67 | URL urls[] = {new File(driverPath).toURI().toURL()}; 68 | URLClassLoader urlClassLoader = new URLClassLoader(urls); 69 | Class driverClass = Class.forName(driver, false, urlClassLoader); 70 | LOGGER.debug("Instantiate the driver and connect directly."); 71 | Driver d = (Driver) driverClass.getDeclaredConstructor().newInstance(); 72 | Properties connectionProperies = new Properties(); 73 | connectionProperies.setProperty("user", user); 74 | connectionProperies.setProperty("password", password); 75 | connection = d.connect(url, connectionProperies); 76 | 77 | } else { 78 | LOGGER.debug("Load driver from classpath and connect by DriverManager."); 79 | Class.forName(driver); 80 | connection = DriverManager.getConnection(url, user, password); 81 | } 82 | 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/DB_DIALECT.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | /** 4 | * 5 | * @author Stefan Kuehnel 6 | * 7 | */ 8 | public enum DB_DIALECT { 9 | MYSQL("MySQL"), 10 | POSTGRESQL("PostgreSQL"), 11 | H2("H2"), 12 | ORACLE("Oracle"), 13 | SQLITE("SQLite"); 14 | 15 | private String value; 16 | 17 | DB_DIALECT(String value) { 18 | this.value = value; 19 | } 20 | 21 | public String getValue() { 22 | return value; 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/FORMAT.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | public enum FORMAT { 4 | DOT("DOT", ".dot", "The Language of GraphViz; see http://www.graphviz.org", true), 5 | PLANT("PLANT", ".txt", "PlantUML ER Diagrams; see https://plantuml.com/ie-diagram", true), 6 | PNG("PNG", ".png", "Portable Network Graphics; see http://libpng.org/pub/png", true), 7 | SVG("SVG", ".svg", "Scalable Vector Graphics; see https://www.w3.org/TR/2003/REC-SVG11-20030114/", true), 8 | PDF("PDF", ".pdf", "Portable Document Format; see https://en.wikipedia.org/wiki/Portable_Document_Format", true), 9 | VISJS("VISJS", ".html", "JavaScript Visualization Framework; see: https://github.com/almende/vis", false); 10 | 11 | 12 | private String name; 13 | private String extension; 14 | private String description; 15 | private boolean implemented; 16 | 17 | private FORMAT(String name, String extension, String description, boolean implemented) { 18 | this.name = name; 19 | this.extension = extension; 20 | this.description = description; 21 | this.implemented = implemented; 22 | } 23 | 24 | /** 25 | * Get description of format 26 | * 27 | * @return a string 28 | */ 29 | public String getDescription() { 30 | return description; 31 | } 32 | 33 | /** 34 | * Get the name of this format 35 | * @return a string 36 | */ 37 | public String getName() { 38 | return name; 39 | } 40 | 41 | /** 42 | * Get the filename extension for this format 43 | * @return a string 44 | */ 45 | public String getExtension() { 46 | return extension; 47 | } 48 | 49 | /** 50 | * Getter for implemented flag 51 | * @return value of implemented 52 | */ 53 | public boolean hasImplemented() { 54 | return implemented; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/InvalidParamException.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | public class InvalidParamException extends Exception { 4 | 5 | public InvalidParamException(String message) { 6 | super(message); 7 | } 8 | 9 | public InvalidParamException(Throwable cause) { 10 | super(cause); 11 | } 12 | 13 | public InvalidParamException(String message, Throwable cause) { 14 | super(message, cause); 15 | 16 | } 17 | 18 | public InvalidParamException(String message, Throwable cause, 19 | boolean enableSuppression, boolean writableStackTrace) { 20 | super(message, cause, enableSuppression, writableStackTrace); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/MissingMandatoryException.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | public class MissingMandatoryException extends RuntimeException { 4 | public MissingMandatoryException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/OPTS.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | import org.apache.commons.cli.HelpFormatter; 4 | import org.apache.commons.cli.Option; 5 | import org.apache.commons.cli.Options; 6 | 7 | /** 8 | * Options for DBVisualizer and TestDBgenerator 9 | * 10 | * @author Stefan Kuehnel 11 | */ 12 | public enum OPTS { 13 | 14 | OPT_DIALECT("d", "dialect", false, true, 15 | "DB dialect. Possible values are PostgreSQL, MySQL, Oracle", "database.dialect"), 16 | OPT_JDBC_URL( 17 | "url", "jdbc-url", true, true, "JDBC URL (mandatory).", 18 | "database.jdbc.url"), 19 | OPT_JDBC_DRV( 20 | "driver", "jdbc-driver", true, true, 21 | "Class name of the JDBC driver (mandatory).", "database.jdbc.driver.class"), 22 | OPT_JDBC_DRV_PATH( 23 | "driverpath", "jdbc-driver-path", false, true, 24 | "Path to the driver classes. If this option is not specified, the driver is searched in CLASSPATH.", 25 | "database.jdbc.driver.path"), 26 | OPT_ENABLE_LR( 27 | "l", "enable-lr", false, false, 28 | "Use GraphViz option ranking=LR; Graph layout from left to right.", "output.graphviz.lroption"), 29 | OPT_ENTITIES_ONLY( 30 | "e", "entities-only", false, false, 31 | "Show only entities and relations in output (no attributes/columns).", 32 | "output.diagram.entitiesonly"), 33 | OPT_FORMAT("a", "format", false, true, "Format: DOT (default), PLANT, PNG, SVG, PDF", 34 | "output.diagram.format"), 35 | OPT_USER( 36 | "u", "user", false, true, "User name for database connection", 37 | "database.user"), 38 | OPT_PASSWORD( 39 | "p", "password", false, true, "Password for database connection.", 40 | "database.password"), 41 | OPT_NUM_TABLES( 42 | "t", "tables", false, true, 43 | "TestDBGenerator only: number of tables.", "generator.numberoftables"), 44 | OPT_SCHEMA_NAME("s", 45 | "schema", false, true, 46 | "Name of the schema to retrieve tables from. Default: all schemas.", "database.schema"), 47 | OPT_CATALOG_NAME("c", 48 | "catalog", false, true, 49 | "Name of the catalog to retrieve tables from. Default: null.", "database.catalog"), 50 | OPT_CONFIG_FILE("C", 51 | "config", false, true, 52 | "Name of a configuration file.", null), 53 | OPT_FILTER("f", "filter", false, true, 54 | "Regular expression (Java flavor) which is applied on table names", "database.filter"), 55 | OPT_REPORT_FORMAT("F", "report-format", false, true, 56 | "Format of the Report file. Supported formats are: html, pdf and markdown", "output.report.format"), 57 | OPT_REPORT_META("m", "report-metainformation", false, false, 58 | "Include some meta information (e.g. report generation date) in the generated report.", 59 | "output.report.metadata"), 60 | OPT_OUTPUT_FILE( 61 | "o", "output-file", true, true, "Name of the output file (mandatory).", 62 | "output.diagram.filename"), 63 | OPT_REPORT_FILE( 64 | "r", "report-file", true, true, 65 | "Name of the report file. If omitted, no report will be generated.", "output.report.filename"); 66 | 67 | private final String shortOpt; 68 | private final String longOpt; 69 | private final boolean mandatory; 70 | private final boolean hasArg; 71 | private final String description; 72 | private final String property; 73 | 74 | OPTS(String shortOpt, String longOpt, boolean mandatory, 75 | boolean hasArg, String description, String property) { 76 | this.shortOpt = shortOpt; 77 | this.longOpt = longOpt; 78 | this.hasArg = hasArg; 79 | this.mandatory = mandatory; 80 | this.description = description; 81 | this.property = property; 82 | } 83 | 84 | /** 85 | * Get an {@link org.apache.commons.cli.Option} object for an OPTS 86 | * enumeration value. 87 | * 88 | * @return an {@link org.apache.commons.cli.Option} object 89 | */ 90 | public Option getOption() { 91 | Option option = new Option(shortOpt, longOpt, hasArg, description); 92 | return option; 93 | } 94 | 95 | /** 96 | * Get an {@link org.apache.commons.cli.Options} object for all of the 97 | * options defined in this enumeration. 98 | * 99 | * @return an {@link org.apache.commons.cli.Options} object 100 | */ 101 | public static Options getOptions() { 102 | Options options = new Options(); 103 | for (OPTS opt : OPTS.values()) { 104 | options.addOption(opt.getOption()); 105 | } 106 | return options; 107 | } 108 | 109 | /** 110 | * Getter for property key 111 | * 112 | * @return value for property key 113 | */ 114 | public String getPropertyKey() { 115 | return this.property; 116 | } 117 | 118 | /** 119 | * Getter for property "mandatory" 120 | * 121 | * @return true, if this option is mandatory 122 | */ 123 | public boolean isMandatory() { 124 | return this.mandatory; 125 | } 126 | 127 | /** 128 | * Generate a usage message 129 | * 130 | * @param application name of the application 131 | * @param description description of the application 132 | */ 133 | public static void printHelp(String application, String description) { 134 | HelpFormatter helpFormatter = new HelpFormatter(); 135 | helpFormatter.printHelp(application, description, getOptions(), "", 136 | true); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/REPORT_FORMAT.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | public enum REPORT_FORMAT { 4 | HTML, 5 | MARKDOWN, 6 | PDF 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/TEST_OPTS.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | import org.apache.commons.cli.HelpFormatter; 4 | import org.apache.commons.cli.Option; 5 | import org.apache.commons.cli.Options; 6 | 7 | /** 8 | * Options for the TestDBGenerator 9 | */ 10 | public enum TEST_OPTS { 11 | OPT_FILENAME("f","file","Name of the output file."), 12 | OPT_TYPE("t","type","Type of test file. Either sql or dot."), 13 | OPT_NUM("n","num","Number of tables to be generated."); 14 | 15 | String shortName; 16 | String longName; 17 | String description; 18 | 19 | TEST_OPTS(String shortName, String longName, String description) { 20 | this.shortName = shortName; 21 | this.longName = longName; 22 | this.description = description; 23 | } 24 | 25 | Option getOption() { 26 | Option option = new Option(shortName, longName, true, description); 27 | option.setRequired(true); 28 | return option; 29 | } 30 | 31 | /** 32 | * Options for apache commons command line parser 33 | * @return options 34 | */ 35 | public static Options getOptions() { 36 | Options options = new Options(); 37 | for (TEST_OPTS opt : TEST_OPTS.values()) { 38 | options.addOption(opt.getOption()); 39 | } 40 | return options; 41 | } 42 | 43 | public static void printHelp(String application, String description) { 44 | HelpFormatter helpFormatter = new HelpFormatter(); 45 | helpFormatter.printHelp(application, description, getOptions(), "", 46 | true); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/TEST_TYPE.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | /** 4 | * Types for the test file generator 5 | */ 6 | public enum TEST_TYPE { 7 | DOT, 8 | SQL 9 | } 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/util/TestDBGenerator.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.util; 2 | 3 | import java.io.File; 4 | import java.io.FileWriter; 5 | import java.io.IOException; 6 | import java.io.Writer; 7 | import java.util.ArrayList; 8 | import java.util.List; 9 | 10 | import org.apache.commons.cli.CommandLine; 11 | import org.apache.commons.cli.CommandLineParser; 12 | import org.apache.commons.cli.DefaultParser; 13 | import org.apache.commons.cli.Option; 14 | import org.apache.commons.cli.ParseException; 15 | import org.apache.commons.lang3.RandomStringUtils; 16 | import org.apache.commons.lang3.RandomUtils; 17 | 18 | import com.skuehnel.dbvisualizer.domain.Column; 19 | import com.skuehnel.dbvisualizer.domain.Table; 20 | import com.skuehnel.dbvisualizer.visualize.Visualizer; 21 | 22 | public class TestDBGenerator { 23 | 24 | private String[] datatypes; // PostgreSQL 25 | // datatypes 26 | 27 | private int numberOfTables; 28 | private String outputFileName; 29 | private TEST_TYPE testType; 30 | 31 | /** 32 | * Empty constructor 33 | */ 34 | public TestDBGenerator() { 35 | datatypes = new String[]{"int", "date", "varchar(255)", "real"}; 36 | } 37 | 38 | /** 39 | * Constructor 40 | * 41 | * @param commandLine commandline 42 | */ 43 | public TestDBGenerator(CommandLine commandLine) { 44 | assignOptions(commandLine); 45 | datatypes = new String[]{"int", "date", "varchar(255)", "real"}; 46 | } 47 | 48 | private void assignOptions(CommandLine commandLine) { 49 | for (Option option : commandLine.getOptions()) { 50 | if (option.equals(TEST_OPTS.OPT_FILENAME.getOption())) { 51 | outputFileName = option.getValue(); 52 | } 53 | if (option.equals(TEST_OPTS.OPT_NUM.getOption())) { 54 | numberOfTables = Integer.valueOf(option.getValue()); 55 | } 56 | if (option.equals(TEST_OPTS.OPT_TYPE.getOption())) { 57 | testType = TEST_TYPE.valueOf(option.getValue().toUpperCase()); 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * Generate the DDL for the random tables and write it to the configured file 64 | * 65 | * @throws InvalidParamException in case a parameter is not valid 66 | * @throws IOException if something goes wrong with I/O operations 67 | */ 68 | private void generateSQL() throws InvalidParamException, IOException { 69 | List
tables = generateRandomTables(numberOfTables, 10); 70 | File f = new File(outputFileName); 71 | Writer writer = new FileWriter(f); 72 | for (Table t : tables) { 73 | writer.append(generateCreateTable(t)); 74 | writer.append('\n'); 75 | } 76 | for (Table t : tables) { 77 | writer.append(generateAlterTable(t)); 78 | writer.append('\n'); 79 | } 80 | writer.flush(); 81 | writer.close(); 82 | System.out.println("Generated DDL statements for " + numberOfTables + " tables in file " + outputFileName); 83 | } 84 | 85 | private void generateDOT() throws InvalidParamException, IOException { 86 | List
tables = generateRandomTables(numberOfTables, 10); 87 | Visualizer visualizer = new Visualizer(tables); 88 | File f = new File(outputFileName); 89 | Writer writer = new FileWriter(f); 90 | writer.write(visualizer.getDotRepresentation()); 91 | writer.close(); 92 | System.out.println("Wrote .dot file for " + numberOfTables + " tables in file " + outputFileName); 93 | } 94 | 95 | private String generateCreateTable(Table t) { 96 | StringBuilder builder = new StringBuilder(); 97 | builder.append("CREATE TABLE "); 98 | builder.append(t.getName()); 99 | builder.append(" ("); 100 | boolean first = true; 101 | for (Column column : t.getColumns()) { 102 | if (!first) { 103 | builder.append(", "); 104 | } else { 105 | first = false; 106 | } 107 | builder.append(column.getName()); 108 | builder.append(' '); 109 | builder.append(column.getType()); 110 | if (column.isPrimaryKey()) { 111 | builder.append(" PRIMARY KEY "); 112 | } 113 | } 114 | builder.append(");"); 115 | return builder.toString(); 116 | } 117 | 118 | private String generateAlterTable(Table t) { 119 | StringBuilder builder = new StringBuilder(); 120 | List columns = t.getColumns(); 121 | for (Column column : columns) { 122 | Table fkTable = column.getForeignKeyTable(); 123 | if (fkTable != null) { 124 | builder.append("ALTER TABLE "); 125 | builder.append(t.getName()); 126 | builder.append(" ADD FOREIGN KEY ("); 127 | builder.append(column.getName()); 128 | builder.append(") REFERENCES "); 129 | builder.append(fkTable.getName()); 130 | builder.append(" ("); 131 | builder.append(column.getForeignKeyColumn().getName()); 132 | builder.append(");"); 133 | } 134 | } 135 | return builder.toString(); 136 | } 137 | 138 | public static void main(String[] args) throws InvalidParamException, 139 | IOException { 140 | CommandLineParser parser = new DefaultParser(); 141 | CommandLine commandLine = null; 142 | try { 143 | commandLine = parser.parse(TEST_OPTS.getOptions(), args); 144 | } catch (ParseException pex) { 145 | System.err.println("Could not parse commandline. " 146 | + pex.getMessage()); 147 | printHelp(); 148 | System.exit(1); 149 | } 150 | if (commandLine.getOptions().length == 0) { 151 | printHelp(); 152 | } else { 153 | TestDBGenerator testDBGenerator = new TestDBGenerator(commandLine); 154 | if (testDBGenerator.testType.equals(TEST_TYPE.SQL)) { 155 | testDBGenerator.generateSQL(); 156 | } else { 157 | testDBGenerator.generateDOT(); 158 | } 159 | } 160 | } 161 | 162 | private static void printHelp() { 163 | TEST_OPTS.printHelp( 164 | "TestDBGenerator", 165 | "Creates a DDL .sql file or a .dot file with some randomly generated tables."); 166 | } 167 | 168 | /** 169 | * Generate a bunch of random tables. Each table will have a Primary key 170 | * column (name "id") and one foreign key relation to a randomly chosen 171 | * other table. Every table will have a random number of columns (max 10 172 | * 173 | * @param number number of tables (at least 1) 174 | * @param maxColumns maximal number of columns per table (must be at least 2) 175 | * @return list of tables. 176 | * @throws InvalidParamException if an invalid parameter has been used 177 | */ 178 | public List
generateRandomTables(int number, int maxColumns) 179 | throws InvalidParamException { 180 | List
tables = new ArrayList<>(); 181 | if (number < 1 || maxColumns < 2) { 182 | throw new InvalidParamException( 183 | "Number of tables must be at least 1; max number of columns must be at least 2."); 184 | } 185 | for (int i = 0; i < number; i++) { 186 | Table t = new Table(RandomStringUtils.randomAlphabetic(6)); 187 | Column idColumn = new Column("id", "int", true, true, true); 188 | List columns = new ArrayList<>(); 189 | columns.add(idColumn); 190 | // rest of columns 191 | int numColumns = RandomUtils.nextInt(2, maxColumns); 192 | for (int j = 1; j < numColumns; j++) { 193 | Column c = new Column(RandomStringUtils.randomAlphabetic(5), 194 | datatypes[RandomUtils.nextInt(0, datatypes.length)], 195 | false, false, false); 196 | columns.add(c); 197 | } 198 | t.setColumns(columns); 199 | tables.add(t); 200 | } 201 | 202 | 203 | // for each table set a FK relationship to one to five other (randomly selected) 204 | for (Table t : tables) { 205 | connectTableToOthers(t, tables); 206 | } 207 | return tables; 208 | } 209 | 210 | private void connectTableToOthers(Table t, List
others) { 211 | int numFKColumns = RandomUtils.nextInt(1, 3); 212 | for (int i = 0; i < numFKColumns; i++) { 213 | int tableToConnectTo = RandomUtils.nextInt(0, others.size() - 1); 214 | Table other = others.get(tableToConnectTo); 215 | Column pkColumnOfOtherTable = other.getColumns().get(0); 216 | Column fkColumn = new Column(other.getName().concat("_ID"), "int", 217 | false, false, false); 218 | fkColumn.setForeignKeyTable(other); 219 | fkColumn.setForeignKeyColumn(pkColumnOfOtherTable); 220 | t.getColumns().add(fkColumn); 221 | t.updateForeignKeyRelations(); 222 | } 223 | } 224 | 225 | } 226 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/visualize/DetailedTableVisualizer.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.visualize; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Column; 4 | import com.skuehnel.dbvisualizer.domain.Table; 5 | 6 | /** 7 | * Visualizer for a Table 8 | * 9 | * @author Stefan Kuehnel 10 | */ 11 | public class DetailedTableVisualizer implements TableVisualizer { 12 | 13 | private Table table; 14 | 15 | /** 16 | * Constructor 17 | * 18 | * @param table the table object for which a dot reprsentation shall be created 19 | */ 20 | public DetailedTableVisualizer(Table table) { 21 | this.table = table; 22 | } 23 | 24 | /** 25 | * Create a node description for this table 26 | * 27 | * @return the detailed representation of the current table in GraphViz' dot language 28 | */ 29 | @Override 30 | public String getDotRepresentation() { 31 | 32 | String nodeName = Visualizer.makeDotName(table.getName().toLowerCase()); 33 | StringBuilder builder = new StringBuilder(nodeName); 34 | builder.append(" ["); 35 | builder.append("label=<"); 36 | builder.append("
\n"); 37 | builder.append(""); 38 | builder.append(""); 41 | builder.append("\n"); 42 | //builder.append(""); 43 | //builder.append(""); 44 | //builder.append("\n"); 45 | for (Column column : table.getColumns()) { 46 | builder.append(""); 47 | builder.append("\n"); 62 | } 63 | builder.append("
"); 39 | builder.append(table.getName().toUpperCase()); 40 | builder.append("
pknametypeconstr
"); 48 | if (column.isPrimaryKey()) { 49 | builder.append("PK"); 50 | } else if (column.getForeignKeyTable() != null) { 51 | builder.append("FK"); 52 | } else { 53 | builder.append("-"); 54 | } 55 | builder.append(""); 56 | builder.append(column.getName()); 57 | builder.append(""); 58 | builder.append(column.getType()); 59 | builder.append(""); 60 | builder.append(getConstraints(column)); 61 | builder.append("
>];\n"); 64 | 65 | return builder.toString(); 66 | } 67 | 68 | /** 69 | * Entity for Plant UML IE Diagrams 70 | * 71 | * @return string in plant uml syntax 72 | */ 73 | @Override 74 | public String getPlantRepresentation() { 75 | StringBuilder builder = new StringBuilder(); 76 | builder.append(String.format("entity \"%s\" as %s {\n", table.getName(), Visualizer.makeDotName(table.getName().toLowerCase()))); 77 | int pk_count = 0; 78 | for (Column column : table.getColumns()) { 79 | if (column.isPrimaryKey()) { 80 | pk_count++; 81 | builder.append(String.format(" *%s : %s\n", column.getName(), column.getType())); 82 | } 83 | } 84 | if (pk_count > 0) { 85 | builder.append(" --\n"); 86 | } 87 | for (Column column : table.getColumns()) { 88 | if (!column.isPrimaryKey()) { 89 | builder.append(" "); 90 | if (column.isNotNull()) { 91 | builder.append("*"); 92 | } 93 | builder.append(String.format("%s : %s", column.getName(), column.getType())); 94 | if (column.getForeignKeyTable() != null) { 95 | builder.append(" <>"); 96 | } 97 | builder.append("\n"); 98 | } 99 | } 100 | builder.append("}\n"); 101 | return builder.toString(); 102 | } 103 | 104 | private String getConstraints(Column column) { 105 | StringBuilder constraints = new StringBuilder(); 106 | 107 | if (column.isNotNull()) { 108 | constraints.append("not null"); 109 | } 110 | if (column.isUnique()) { 111 | if (column.isNotNull()) { 112 | constraints.append(", "); 113 | } 114 | constraints.append("unique"); 115 | } 116 | return constraints.toString(); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/visualize/SimpleTableVisualizer.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.visualize; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Table; 4 | 5 | public class SimpleTableVisualizer implements TableVisualizer { 6 | 7 | private Table table; 8 | 9 | public SimpleTableVisualizer(Table table) { 10 | this.table = table; 11 | } 12 | 13 | @Override 14 | public String getDotRepresentation() { 15 | String nodeName = Visualizer.makeDotName(table.getName().toLowerCase()); 16 | StringBuilder builder = new StringBuilder(nodeName); 17 | builder.append("[label=<"); 18 | builder.append("\n"); 19 | builder.append("
"); 20 | builder.append(table.getSimpleName()); 21 | builder.append("
"); 22 | builder.append(">];\n"); 23 | return builder.toString(); 24 | } 25 | 26 | @Override 27 | public String getPlantRepresentation() { 28 | StringBuilder builder = new StringBuilder(); 29 | return builder.toString(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/visualize/TableVisualizer.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.visualize; 2 | 3 | public interface TableVisualizer { 4 | /** 5 | * Create a node description for this table 6 | * 7 | * @return the dot representation of a table 8 | */ 9 | String getDotRepresentation(); 10 | 11 | /** 12 | * Create a node description for this table in plant uml syntax 13 | * 14 | * @return the dot representation of a table 15 | */ 16 | String getPlantRepresentation(); 17 | } 18 | -------------------------------------------------------------------------------- /app/src/main/java/com/skuehnel/dbvisualizer/visualize/Visualizer.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.visualize; 2 | 3 | import java.util.List; 4 | 5 | import com.skuehnel.dbvisualizer.domain.Table; 6 | 7 | /** 8 | * Create a file in dot language 9 | * 10 | * @author Stefan Kuehnel 11 | * 12 | */ 13 | public class Visualizer { 14 | 15 | private List tables; 16 | 17 | private boolean lrEnabled = false; 18 | private boolean entitiesOnly = false; 19 | 20 | /** 21 | * Constructor 22 | */ 23 | public Visualizer(List
tables) { 24 | this.tables = tables; 25 | } 26 | 27 | /** 28 | * Add a table 29 | * @param table a table object 30 | */ 31 | public void addTable(Table table) { 32 | tables.add(table); 33 | } 34 | 35 | /** 36 | * Set the list of tables to visualize 37 | * @param tables a list of table objects 38 | */ 39 | public void setTables(List
tables) { 40 | this.tables = tables; 41 | } 42 | 43 | /** 44 | * Setter for LR option 45 | * @param lrEnabled current value 46 | */ 47 | public void setLrEnabled(boolean lrEnabled) { 48 | this.lrEnabled = lrEnabled; 49 | } 50 | 51 | /** 52 | * Getter for LR option (GraphViz left to right layout) 53 | * 54 | * @return value of LR option 55 | */ 56 | public boolean isLrEnabled() { 57 | return lrEnabled; 58 | } 59 | 60 | /** 61 | * Getter for option "Entities only" 62 | * 63 | * @return value of setting "entities only" 64 | */ 65 | public boolean isEntitiesOnly() { 66 | return entitiesOnly; 67 | } 68 | 69 | /** 70 | * Setter for option "entities only" 71 | * 72 | * @param entitiesOnly value for option "entities only" 73 | */ 74 | public void setEntitiesOnly(boolean entitiesOnly) { 75 | this.entitiesOnly = entitiesOnly; 76 | } 77 | 78 | /** 79 | * Generate the .dot file 80 | * @return the ER-model as GraphViz dot file 81 | */ 82 | public String getDotRepresentation() { 83 | StringBuilder builder = new StringBuilder(); 84 | builder.append("digraph tables {\n"); 85 | if (lrEnabled) { 86 | builder.append(" rankdir=LR;\n"); 87 | } 88 | builder.append(" node [shape=plaintext];\n"); 89 | for (Table table : tables) { 90 | TableVisualizer tv = getTableVisualizer(table); 91 | builder.append(tv.getDotRepresentation()); 92 | } 93 | for (Table table : tables) { 94 | List
foreignKeyRelations = table.getForeignKeyRelations(); 95 | if (!foreignKeyRelations.isEmpty()) { 96 | for (Table other : foreignKeyRelations) { 97 | builder.append(makeDotName(table.getName().toLowerCase())); 98 | builder.append(":p0"); 99 | builder.append(" -> "); 100 | builder.append(makeDotName(other.getName().toLowerCase())); 101 | builder.append(":p0"); 102 | builder.append(" [arrowtail=crow;dir=back];\n"); 103 | } 104 | } 105 | } 106 | builder.append("}\n"); 107 | return builder.toString(); 108 | } 109 | 110 | /** 111 | * Get Output for Plant IE (ER) Diagrams 112 | * 113 | * @return a string describing the database in PlantUML notation 114 | */ 115 | public String getPlantRepresentation() { 116 | StringBuilder builder = new StringBuilder(); 117 | builder.append("@startuml\n"); 118 | builder.append("'hide the spot\n"); 119 | builder.append("hide circle\n"); 120 | builder.append("' comment\n"); 121 | builder.append("skinparam linetype ortho\n"); 122 | for (Table table : tables) { 123 | TableVisualizer tv = getTableVisualizer(table); 124 | builder.append(tv.getPlantRepresentation()); 125 | builder.append("\n"); 126 | } 127 | builder.append("\n"); 128 | for (Table table : tables) { 129 | List
foreignKeyRelations = table.getForeignKeyRelations(); 130 | if (!foreignKeyRelations.isEmpty()) { 131 | for (Table other : foreignKeyRelations) { 132 | builder.append(Visualizer.makeDotName(table.getName()).toLowerCase()); 133 | builder.append(" }|--|| "); 134 | builder.append(Visualizer.makeDotName(other.getName()).toLowerCase()); 135 | builder.append("\n"); 136 | } 137 | } 138 | } 139 | builder.append("@enduml\n"); 140 | return builder.toString(); 141 | } 142 | 143 | protected static String makeDotName(String in) { 144 | return in.replaceAll("([\\.\\$])", "_"); 145 | } 146 | 147 | private TableVisualizer getTableVisualizer(Table table) { 148 | if (entitiesOnly) { 149 | return new SimpleTableVisualizer(table); 150 | } 151 | return new DetailedTableVisualizer(table); 152 | } 153 | 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/resources/simplelogger.properties: -------------------------------------------------------------------------------- 1 | # https://www.slf4j.org/api/org/slf4j/simple/SimpleLogger.html 2 | 3 | org.slf4j.simpleLogger.defaultLogLevel=debug -------------------------------------------------------------------------------- /app/src/test/java/com/skuehnel/dbvisualizer/ConfigurationTest.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer; 2 | 3 | import com.skuehnel.dbvisualizer.util.*; 4 | import org.apache.commons.cli.*; 5 | import org.junit.jupiter.api.Assertions; 6 | import org.junit.jupiter.api.Test; 7 | 8 | public class ConfigurationTest { 9 | 10 | @Test 11 | public void variableAssignmentFromProperties() throws ParseException { 12 | CommandLineParser parser = new DefaultParser(); 13 | String[] args = {"-C", "src/test/resources/test.properties"}; 14 | CommandLine commandLine = parser.parse(OPTS.getOptions(), args); 15 | DBVisualizer dbVisualizer = new DBVisualizer(); 16 | dbVisualizer.assignCommandLineOptionsAndConfigurationValues(commandLine); 17 | // Assertions 18 | Assertions.assertEquals("test-catalog", dbVisualizer.getCatalog()); 19 | Assertions.assertEquals("test-schema", dbVisualizer.getSchema()); 20 | Assertions.assertEquals("test-password", dbVisualizer.getDatabasePassword()); 21 | Assertions.assertEquals("test-user", dbVisualizer.getDatabaseUser()); 22 | Assertions.assertEquals("test-driver", dbVisualizer.getJdbcDriver()); 23 | Assertions.assertEquals("test-driver-path", dbVisualizer.getJdbcDriverPath()); 24 | Assertions.assertEquals("test-url", dbVisualizer.getJdbcUrl()); 25 | Assertions.assertEquals("test-report.md", dbVisualizer.getReportFile()); 26 | Assertions.assertEquals("test-diagram.png", dbVisualizer.getOutputFileName()); 27 | Assertions.assertEquals(false, dbVisualizer.isEntitiesOnly()); 28 | Assertions.assertEquals(false, dbVisualizer.islROption()); 29 | Assertions.assertEquals(true, dbVisualizer.isReportMeta()); 30 | Assertions.assertTrue(dbVisualizer.getFilter().matcher("DB_PREFIX.SUBSYSTEM.TEST").matches()); 31 | Assertions.assertFalse(dbVisualizer.getFilter().matcher("TEST.DB_PREFIX.SUBSYSTEM").matches()); 32 | Assertions.assertEquals(DB_DIALECT.POSTGRESQL, dbVisualizer.getDbDialect()); 33 | Assertions.assertEquals(FORMAT.PNG, dbVisualizer.getOutputFormat()); 34 | Assertions.assertEquals(REPORT_FORMAT.MARKDOWN, dbVisualizer.getReportFormat()); 35 | } 36 | 37 | @Test 38 | public void commandLineHasPriorityTest() throws ParseException { 39 | CommandLineParser parser = new DefaultParser(); 40 | String[] args = {"-C", "src/test/resources/test.properties", "-p", "test-password-overwritten"}; 41 | CommandLine commandLine = parser.parse(OPTS.getOptions(), args); 42 | DBVisualizer dbVisualizer = new DBVisualizer(); 43 | dbVisualizer.assignCommandLineOptionsAndConfigurationValues(commandLine); 44 | // Assertions 45 | Assertions.assertEquals("test-password-overwritten", dbVisualizer.getDatabasePassword()); 46 | 47 | } 48 | 49 | @Test 50 | void checkForMandatoryOptions() throws ParseException { 51 | CommandLineParser parser = new DefaultParser(); 52 | String[] args = {"-u", "test-user", "-p", "test-password-overwritten"}; 53 | CommandLine commandLine = parser.parse(OPTS.getOptions(), args); 54 | DBVisualizer dbVisualizer = new DBVisualizer(); 55 | MissingMandatoryException thrown = Assertions.assertThrows( 56 | MissingMandatoryException.class, 57 | () -> dbVisualizer.assignCommandLineOptionsAndConfigurationValues(commandLine), 58 | "Expected exception for missing mandatory parameters"); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /app/src/test/java/com/skuehnel/dbvisualizer/report/ReportGeneratorTest.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.report; 2 | 3 | import com.skuehnel.dbvisualizer.domain.Column; 4 | import com.skuehnel.dbvisualizer.domain.Model; 5 | import com.skuehnel.dbvisualizer.domain.Table; 6 | import com.skuehnel.dbvisualizer.util.REPORT_FORMAT; 7 | import org.junit.jupiter.api.Assertions; 8 | import org.junit.jupiter.api.BeforeAll; 9 | import org.junit.jupiter.api.Test; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.File; 13 | import java.io.IOException; 14 | import java.nio.file.Files; 15 | import java.nio.file.Paths; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | public class ReportGeneratorTest { 20 | 21 | private static Model model; 22 | 23 | @BeforeAll 24 | public static void initModel() { 25 | model = new Model(); 26 | model.setDatabaseName("TestDatabase"); 27 | model.setSchemaName("TestSchema"); 28 | 29 | Table employee_table = new Table("EMP"); 30 | Table department_table = new Table("DEPT"); 31 | 32 | List emp_columns = new ArrayList<>(); 33 | List dept_columns = new ArrayList<>(); 34 | 35 | Column dept_pk = new Column("PK_DEPT_ID", "INT"); 36 | dept_pk.setPrimaryKey(true); 37 | dept_pk.setNotNull(true); 38 | dept_columns.add(dept_pk); 39 | 40 | Column dept_name = new Column("NAME", "VARCHAR(80)"); 41 | dept_name.setNotNull(true); 42 | dept_columns.add(dept_name); 43 | 44 | Column emp_id = new Column("PK_EMP_ID", "INT"); 45 | emp_id.setPrimaryKey(true); 46 | emp_id.setNotNull(true); 47 | emp_columns.add(emp_id); 48 | 49 | Column emp_lastname = new Column("LNAME", "VARCHAR(80)"); 50 | emp_lastname.setNotNull(true); 51 | emp_columns.add(emp_lastname); 52 | 53 | Column emp_fk_dept = new Column("FK_DEPT_ID", "INT"); 54 | emp_fk_dept.setForeignKeyColumn(dept_pk); 55 | emp_fk_dept.setForeignKeyTable(department_table); 56 | emp_columns.add(emp_fk_dept); 57 | 58 | employee_table.setColumns(emp_columns); 59 | department_table.setColumns(dept_columns); 60 | List
tables = new ArrayList<>(); 61 | tables.add(employee_table); 62 | tables.add(department_table); 63 | model.setTableList(tables); 64 | } 65 | 66 | 67 | @Test 68 | public void markDownGeneratorTest() throws IOException { 69 | ReportGenerator reportGenerator = ReportGeneratorFactory.createReportGeneratorInstance(REPORT_FORMAT.MARKDOWN.name()); 70 | File f = File.createTempFile("test", ".md"); 71 | f.deleteOnExit(); 72 | reportGenerator.generateReport(f.getAbsolutePath(), model, ReportGenerator.REPORT_OPT.WITH_META_INFORMATION); 73 | Assertions.assertTrue(f.exists()); 74 | Assertions.assertTrue(f.isFile()); 75 | Assertions.assertTrue(f.length() > 0); 76 | String content = Files.readString(f.toPath()); 77 | Assertions.assertNotNull(content); 78 | Assertions.assertTrue(content.contains("## Table EMP")); 79 | Assertions.assertTrue(content.contains("## Table DEPT")); 80 | Assertions.assertTrue(content.contains("PK_EMP_ID")); 81 | Assertions.assertTrue(content.contains("PK_DEPT_ID")); 82 | Assertions.assertTrue(content.contains("LNAME")); 83 | Assertions.assertTrue(content.contains("FK_DEPT_ID")); 84 | } 85 | 86 | @Test 87 | public void htmlGeneratorTest() throws IOException { 88 | ReportGenerator reportGenerator = ReportGeneratorFactory.createReportGeneratorInstance(REPORT_FORMAT.HTML.name()); 89 | File f = File.createTempFile("test", ".html"); 90 | f.deleteOnExit(); 91 | reportGenerator.generateReport(f.getAbsolutePath(), model, ReportGenerator.REPORT_OPT.WITH_META_INFORMATION); 92 | Assertions.assertTrue(f.exists()); 93 | Assertions.assertTrue(f.isFile()); 94 | Assertions.assertTrue(f.length() > 0); 95 | String content = Files.readString(f.toPath()); 96 | Assertions.assertNotNull(content); 97 | Assertions.assertTrue(content.contains(">Table EMP<")); 98 | Assertions.assertTrue(content.contains(">Table DEPT<")); 99 | Assertions.assertTrue(content.contains("PK_EMP_ID")); 100 | Assertions.assertTrue(content.contains("PK_DEPT_ID")); 101 | Assertions.assertTrue(content.contains("LNAME")); 102 | Assertions.assertTrue(content.contains("FK_DEPT_ID")); 103 | } 104 | 105 | 106 | @Test 107 | public void pdfGeneratorTest() throws IOException { 108 | ReportGenerator reportGenerator = ReportGeneratorFactory.createReportGeneratorInstance(REPORT_FORMAT.PDF.name()); 109 | File f = File.createTempFile("test", ".pdf"); 110 | f.deleteOnExit(); 111 | reportGenerator.generateReport(f.getAbsolutePath(), model); 112 | Assertions.assertTrue(f.exists()); 113 | Assertions.assertTrue(f.isFile()); 114 | Assertions.assertTrue(f.length() > 0); 115 | } 116 | 117 | 118 | } 119 | -------------------------------------------------------------------------------- /app/src/test/java/com/skuehnel/dbvisualizer/visualize/VisualizerTest.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.visualize; 2 | 3 | 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | 7 | 8 | import com.skuehnel.dbvisualizer.domain.Column; 9 | import com.skuehnel.dbvisualizer.domain.Table; 10 | import com.skuehnel.dbvisualizer.report.ReportGeneratorFactory; 11 | import com.skuehnel.dbvisualizer.util.InvalidParamException; 12 | import com.skuehnel.dbvisualizer.util.TestDBGenerator; 13 | import org.junit.jupiter.api.BeforeAll; 14 | import org.junit.jupiter.api.Test; 15 | 16 | import static org.junit.jupiter.api.Assertions.assertEquals; 17 | import static org.junit.jupiter.api.Assertions.assertNotNull; 18 | 19 | 20 | public class VisualizerTest { 21 | 22 | private static Table employees = new Table("EMPLOYEES"); 23 | private static Table departments = new Table("DEPARTMENTS"); 24 | private static TestDBGenerator testDBGenerator = new TestDBGenerator(); 25 | 26 | @BeforeAll 27 | public static void setUpTestData() { 28 | 29 | Column dept_id = new Column("ID","NUMBER",true,false,false); 30 | Column dept_name = new Column("NAME","VARCHAR",false,false,true); 31 | 32 | List deptColumns = new ArrayList<>(); 33 | deptColumns.add(dept_id); 34 | deptColumns.add(dept_name); 35 | 36 | departments.setColumns(deptColumns); 37 | 38 | 39 | Column emp_id = new Column("ID", "NUMBER" ,true ,false,false); 40 | Column emp_fname = new Column("FNAME","VARCHAR" ,false,false,true); 41 | Column emp_lname = new Column("LNAME","VARCHAR" ,false,false,true); 42 | Column emp_dept_id = new Column("DEPT_ID","NUMBER" ,false,false,true); 43 | 44 | emp_dept_id.setForeignKeyTable(departments); 45 | emp_dept_id.setForeignKeyColumn(dept_id); 46 | 47 | List empColumns = new ArrayList<>(); 48 | empColumns.add(emp_id); 49 | empColumns.add(emp_fname); 50 | empColumns.add(emp_lname); 51 | empColumns.add(emp_dept_id); 52 | 53 | employees.setColumns(empColumns); 54 | } 55 | 56 | @Test 57 | public void visualizationEmployeeDepartmentTest() { 58 | Visualizer v = new Visualizer(new ArrayList
()); 59 | v.addTable(departments); 60 | v.addTable(employees); 61 | String dot = v.getDotRepresentation(); 62 | assertNotNull(dot); 63 | } 64 | 65 | @Test 66 | public void randomTest20Tables() throws InvalidParamException { 67 | List
tables = testDBGenerator.generateRandomTables(20,10); 68 | Visualizer v = new Visualizer(tables); 69 | String dot = v.getDotRepresentation(); 70 | assertNotNull(dot); 71 | } 72 | 73 | @Test 74 | public void randomTest100Tables() throws InvalidParamException { 75 | List
tables = testDBGenerator.generateRandomTables(100,20); 76 | Visualizer v = new Visualizer(tables); 77 | String dot = v.getDotRepresentation(); 78 | assertNotNull(dot); 79 | } 80 | 81 | @Test 82 | public void testMakeDotName() { 83 | assertEquals("test_abc_123", Visualizer.makeDotName("test.abc$123")); 84 | assertEquals("test_abc_123", Visualizer.makeDotName("test$abc$123")); 85 | assertEquals("test_abc_123", Visualizer.makeDotName("test$abc_123")); 86 | assertEquals("test_abc_123", Visualizer.makeDotName("test.abc_123")); 87 | } 88 | 89 | } 90 | -------------------------------------------------------------------------------- /app/src/test/resources/test.properties: -------------------------------------------------------------------------------- 1 | database.dialect=PostgreSQL 2 | database.jdbc.url=test-url 3 | database.jdbc.driver.class=test-driver 4 | database.jdbc.driver.path=test-driver-path 5 | output.graphviz.lroption=false 6 | output.diagram.entitiesonly=false 7 | output.diagram.format=PNG 8 | database.user=test-user 9 | database.password=test-password 10 | database.schema=test-schema 11 | database.catalog=test-catalog 12 | database.filter=DB_PREFIX\.SUBSYSTEM.* 13 | output.report.format=MARKDOWN 14 | output.report.metadata=true 15 | output.diagram.filename=test-diagram.png 16 | output.report.filename=test-report.md -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | This directory contains examples to demonstrate some capabilities of the tool. 4 | 5 | ## PostgreSQL example 6 | 7 | ![ER-Diagram in PNG format](postgresql_test.png) 8 | 9 | * [DDL script for example database](postgresql_test.sql) 10 | * [Markdown Report](postgresql_test.md) 11 | * [.dot file for PlantUML](postgresql_test.dot) 12 | * [ER-Diagram in PNG format](postgresql_test.png) (created by PlantUML) 13 | 14 | ## Huge Example 15 | 16 | ![Preview](dbvisualizer_preview.png) 17 | 18 | The [dbvisualizer.sql](dbvisualizer.sql) DDL script has been generated with the TestDBGenerator tool. It contains 200 19 | randomly created tables with random columns and 200 relations (also randomly created). The following files were created 20 | from this test database: 21 | 22 | * [.dot file form GraphViz](dbvisualizer.dot) 23 | * [ER-Diagram in PNG format](dbvisualizer.png) 24 | * [ER-Diagram in PDF format](dbvisualizer.pdf) 25 | 26 | -------------------------------------------------------------------------------- /example/dbvisualizer.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eska-muc/dbvisualizer/d1055925d8713ba086ae984751768a62ab89be48/example/dbvisualizer.pdf -------------------------------------------------------------------------------- /example/dbvisualizer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eska-muc/dbvisualizer/d1055925d8713ba086ae984751768a62ab89be48/example/dbvisualizer.png -------------------------------------------------------------------------------- /example/dbvisualizer.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE AlHYzn (id int PRIMARY KEY , pbbop real, xfVwu date, vaPaz real, juOfm varchar(255), oQHKW varchar(255), IEsNV date, PpTJX date, eojpFF_ID int); 2 | CREATE TABLE PxQWNj (id int PRIMARY KEY , bVdYA date, ZgLty date, MlQdc date, cyQav varchar(255), JtjWy real, azkpP varchar(255), yCILS real, EuRSi real, KjnfkQ_ID int); 3 | CREATE TABLE ldnWOM (id int PRIMARY KEY , hwKfq real, CxWNE date, lubeh date, PoDHnF_ID int); 4 | CREATE TABLE reEOyJ (id int PRIMARY KEY , bABoi date, qvQZk date, kiqOb int, kwYBh real, gvfpK real, Wyxsl date, dmruv int, mGIzg date, WNmMPb_ID int); 5 | CREATE TABLE cKmFEN (id int PRIMARY KEY , TOWAB real, yNBsQ varchar(255), PSHZo int, ajzua date, fFmtEY_ID int); 6 | CREATE TABLE sstGay (id int PRIMARY KEY , UEnKt varchar(255), icTdL real, iNakW real, XUgsN int, fbuVz int, oGfDL date, HgmJV varchar(255), GYGHt date, fMkPwr_ID int); 7 | CREATE TABLE txQUBM (id int PRIMARY KEY , UIAEh int, QDOTj real, ALdMz varchar(255), qwJTd real, lLdySD_ID int); 8 | CREATE TABLE KAkXqG (id int PRIMARY KEY , WoftG varchar(255), CJaFl date, zuTZZ varchar(255), GBHWP real, egexK int, pIePP date, EhNTd varchar(255), GNabq int, AGpmFj_ID int); 9 | CREATE TABLE MDDmXB (id int PRIMARY KEY , cLZNN int, ObVjI real, wILyZ int, HHKHu real, UlFrK date, fuJCv real, DUBYJ int, SXVqAW_ID int); 10 | CREATE TABLE xkBdMq (id int PRIMARY KEY , Bvqjh date, jobJu varchar(255), HSJNw real, jXYQi int, asSGbe_ID int); 11 | CREATE TABLE SMWciT (id int PRIMARY KEY , ZPZcs varchar(255), chYjD real, IaHuf varchar(255), rWCQq real, GqGSy int, sdkmX real, NSdsPc_ID int); 12 | CREATE TABLE UpnvHd (id int PRIMARY KEY , NTRPC real, ThCgv date, EOCIWK_ID int); 13 | CREATE TABLE yaHiKG (id int PRIMARY KEY , kqfeL int, RkVMkT_ID int); 14 | CREATE TABLE yLzRCK (id int PRIMARY KEY , HtVWV varchar(255), zgdkX int, ETAuiI_ID int); 15 | CREATE TABLE oykGJl (id int PRIMARY KEY , QAgSk varchar(255), frJVD real, vAMnt real, aShkK date, pVbPo date, yuTct varchar(255), QGvVo int, HVPkI varchar(255), RLplfQ_ID int); 16 | CREATE TABLE MKmkAN (id int PRIMARY KEY , AxmSM int, NjOoa int, atTXF varchar(255), xoMKG date, OpePE date, TMPuyI_ID int); 17 | CREATE TABLE wqpwQp (id int PRIMARY KEY , BJjjq int, sxLMSr_ID int); 18 | CREATE TABLE pYEkSq (id int PRIMARY KEY , Grmke date, KkRzI real, QKLTQ date, NGbkFR_ID int); 19 | CREATE TABLE jBwJVP (id int PRIMARY KEY , WFoIT real, vLaOU date, wktQQy_ID int); 20 | CREATE TABLE lDbhwB (id int PRIMARY KEY , DvLvv varchar(255), FgkIE int, ZkkAy date, PxQWNj_ID int); 21 | CREATE TABLE sOLmWO (id int PRIMARY KEY , CfUZS int, BJHOw date, olNZo date, ZJvmI date, Sctdt real, KuEdY varchar(255), TGwdSW_ID int); 22 | CREATE TABLE LVAYmz (id int PRIMARY KEY , YWhvA real, VqfCJ varchar(255), dKIcG real, EGLIkO_ID int); 23 | CREATE TABLE ykrHsd (id int PRIMARY KEY , fjwlo varchar(255), IDJFi real, xkVibA_ID int); 24 | CREATE TABLE NbORDP (id int PRIMARY KEY , XqZrI int, KmlOc real, AzizM date, FBQOK real, suvRs varchar(255), iYzoC date, CUPCGG_ID int); 25 | CREATE TABLE MITiAg (id int PRIMARY KEY , LjJAo varchar(255), JBgOW date, zJAYlX_ID int); 26 | CREATE TABLE VkrsiX (id int PRIMARY KEY , vbTLq real, Uteun real, TsxqnH_ID int); 27 | CREATE TABLE pPdJMK (id int PRIMARY KEY , axQPF int, PDcGx date, HaKpzz_ID int); 28 | CREATE TABLE jmiiSG (id int PRIMARY KEY , oIerQ varchar(255), bJxxP real, FCiap date, JJctq int, rZGoIt_ID int); 29 | CREATE TABLE KfyQLw (id int PRIMARY KEY , oOXQi real, lQaUJ real, fGyDY date, gHWRu real, GtpDj real, rwdaq real, KbRdH varchar(255), lpkhv int, EfRLUb_ID int); 30 | CREATE TABLE DntkOC (id int PRIMARY KEY , JWMol int, sFVLc varchar(255), rLYfF int, oxAeU varchar(255), MlfiM date, reuYX varchar(255), MRRNuJ_ID int); 31 | CREATE TABLE pQcMRA (id int PRIMARY KEY , pFWtu real, zkEqp varchar(255), TOHPiM_ID int); 32 | CREATE TABLE kUBKBI (id int PRIMARY KEY , UPmQe varchar(255), GAujK int, cKCvf int, kjIZZZ_ID int); 33 | CREATE TABLE LpQhZI (id int PRIMARY KEY , uxbRP int, wVmLv int, PhTOE date, CNjhn real, Aujfh int, vPghiH_ID int); 34 | CREATE TABLE vbnySX (id int PRIMARY KEY , Zgrov varchar(255), bekvd int, KjnfkQ_ID int); 35 | CREATE TABLE fMkPwr (id int PRIMARY KEY , VJRDj varchar(255), iwIAy varchar(255), lBFvB date, SUBPW varchar(255), xHoSg real, VioGs real, riSvh date, gepNR int, JCixda_ID int); 36 | CREATE TABLE hCgWvz (id int PRIMARY KEY , iMuLB int, yLItj real, whkbef_ID int); 37 | CREATE TABLE DGzlkm (id int PRIMARY KEY , pzIoX varchar(255), gzuyT date, QwUPl real, bLUZrQ_ID int); 38 | CREATE TABLE JCixda (id int PRIMARY KEY , nAMIU varchar(255), NSwtH real, iZqJn int, afHhp varchar(255), isfOc varchar(255), yJaEX date, sadfg varchar(255), LpQhZI_ID int); 39 | CREATE TABLE YblLZW (id int PRIMARY KEY , eSppp date, cVqkZ date, ugUEN int, TfffM date, ZFckAf_ID int); 40 | CREATE TABLE MRRNuJ (id int PRIMARY KEY , AOhSl date, hjjCpx_ID int); 41 | CREATE TABLE ibzzsF (id int PRIMARY KEY , COXgT int, iLSAv int, kYpkM real, HiUjRB_ID int); 42 | CREATE TABLE gENXMt (id int PRIMARY KEY , lGotv date, aGMBp int, TOHPiM_ID int); 43 | CREATE TABLE yVYdQs (id int PRIMARY KEY , VvNgg int, AXEud date, tezpK int, OBvnz int, pPdJMK_ID int); 44 | CREATE TABLE KiBGLM (id int PRIMARY KEY , XqjeF date, dgRuX varchar(255), YzvOJ date, dUBRb real, tMjzMd_ID int); 45 | CREATE TABLE ZbTRFz (id int PRIMARY KEY , xpZpv varchar(255), cXqnF date, hEoBl real, Rslhs real, fcAeH real, yHXtM int, aArev real, eVjDV varchar(255), cQRqpB_ID int); 46 | CREATE TABLE qoJWAy (id int PRIMARY KEY , mjFJB int, hpwlV date, pfUMmQ_ID int); 47 | CREATE TABLE HJQEDj (id int PRIMARY KEY , VWXya int, wrTNJ real, aqoMZ real, QWFiBa_ID int); 48 | CREATE TABLE irQfhQ (id int PRIMARY KEY , ppkDE real, eveGu date, ecVyD date, oDwMR int, OQzWn real, YycAu real, YbhZQ varchar(255), LrxfcC_ID int); 49 | CREATE TABLE OsNSgX (id int PRIMARY KEY , HKLSo real, GadLh date, YGfoZ date, cdwyH real, UnUiH real, zjXxD int, nGovu varchar(255), BfcNaO_ID int); 50 | CREATE TABLE zLvsfF (id int PRIMARY KEY , kJzWs int, rByzcn_ID int); 51 | CREATE TABLE WyeKsa (id int PRIMARY KEY , nYrVE date, jYObT varchar(255), SkBOe real, HUBwU date, RMOlO varchar(255), eahMiA_ID int); 52 | CREATE TABLE Qbxmza (id int PRIMARY KEY , MncMb date, JwpCF date, NUqYU varchar(255), uYRAw int, WNmMPb_ID int); 53 | CREATE TABLE wtNGtl (id int PRIMARY KEY , qeHKa varchar(255), AXoDi date, nfuPc real, GAkYV date, sBbKQ varchar(255), NACnL date, vXyep real, ouraf varchar(255), GZFKjJ_ID int); 54 | CREATE TABLE AGpmFj (id int PRIMARY KEY , FgINm real, BvTiH varchar(255), VEOrK real, cbxRE varchar(255), CueaJ varchar(255), dYKps varchar(255), fhUikX_ID int); 55 | CREATE TABLE XWBvWi (id int PRIMARY KEY , lOXcw real, dAClXU_ID int); 56 | CREATE TABLE ebiQXH (id int PRIMARY KEY , CZQog varchar(255), qghGP int, IEKgu varchar(255), UutJW varchar(255), MmEZO varchar(255), iHXQL real, pQcMRA_ID int); 57 | CREATE TABLE NGbkFR (id int PRIMARY KEY , HGMtN varchar(255), TeCtM date, iqjaH int, vAyPW int, NjQLG varchar(255), SMWciT_ID int); 58 | CREATE TABLE FXwoBM (id int PRIMARY KEY , DimDj real, bVXGX real, NUCoi real, AGpmFj_ID int); 59 | CREATE TABLE glitlo (id int PRIMARY KEY , FFEmw int, uVcJS date, gaulo date, XCCwun_ID int); 60 | CREATE TABLE rByzcn (id int PRIMARY KEY , zbCLT varchar(255), BqGDN real, bpskr varchar(255), uKUEF real, YYIBg varchar(255), hfRyn varchar(255), ccZAeN_ID int); 61 | CREATE TABLE rCjJOY (id int PRIMARY KEY , wemYP varchar(255), IGPfX date, opQYf varchar(255), MhxJr int, hMWkT varchar(255), uzKvM real, KAYyf int, suXDU real, SXVqAW_ID int); 62 | CREATE TABLE UJdYsj (id int PRIMARY KEY , kSJYc date, BztsG varchar(255), Tkaqs int, SmZvH real, HJHYr varchar(255), YMzpf varchar(255), RsTLSw_ID int); 63 | CREATE TABLE lxOZzT (id int PRIMARY KEY , JkbZG real, zdZVz varchar(255), osyZP real, TGwdSW_ID int); 64 | CREATE TABLE vPghiH (id int PRIMARY KEY , hLeMX int, pPdJMK_ID int); 65 | CREATE TABLE TsRrQc (id int PRIMARY KEY , TnOhR int, nvPQx varchar(255), oasDo varchar(255), cVPrX int, DDXlrn_ID int); 66 | CREATE TABLE WeoIOJ (id int PRIMARY KEY , dKCav date, TqBlm date, JhDUQ real, xkBdMq_ID int); 67 | CREATE TABLE SsSwtG (id int PRIMARY KEY , XzBKl int, ESyIE date, poFUa int, ZhncL real, pYEkSq_ID int); 68 | CREATE TABLE zNEJUG (id int PRIMARY KEY , ofJpx real, lUlvv int, uotmH varchar(255), UHoXw real, CpXzX varchar(255), yaqJn date, SGADUe_ID int); 69 | CREATE TABLE MofNeU (id int PRIMARY KEY , uEIQP real, ZJzGG int, fLTYB int, iRllw varchar(255), rcsFI varchar(255), ykrHsd_ID int); 70 | CREATE TABLE HJUKod (id int PRIMARY KEY , JGhyy real, DoYvs date, bEWFm varchar(255), NHOfA real, FEyOy date, SQuPE date, sxwxZ real, UUmhZo_ID int); 71 | CREATE TABLE BkdpgJ (id int PRIMARY KEY , CqzYY varchar(255), hihWf int, cBRXU date, tSNxP date, SZheB real, BSpFU date, rmcCB int, ZaCpBx_ID int); 72 | CREATE TABLE vuohmP (id int PRIMARY KEY , ikRJE real, pCtwL real, sgCYn real, AJPBd varchar(255), FtSbd real, raLtw date, SXqUqX_ID int); 73 | CREATE TABLE wktQQy (id int PRIMARY KEY , LtKqo int, QCQNK date, nxlgA real, TGwdSW_ID int); 74 | CREATE TABLE RkVMkT (id int PRIMARY KEY , usoWf date, vGCre varchar(255), qJHgf real, bbXCl int, vuohmP_ID int); 75 | CREATE TABLE XvFPTt (id int PRIMARY KEY , SSEsr date, DgDkJ varchar(255), cQijd varchar(255), rFbgB real, FnslY int, vsevQ int, XuInYq_ID int); 76 | CREATE TABLE iPTlhi (id int PRIMARY KEY , NfbDq date, PbjylL_ID int); 77 | CREATE TABLE yErwOg (id int PRIMARY KEY , DxcDJ varchar(255), yLcihn_ID int); 78 | CREATE TABLE TGwdSW (id int PRIMARY KEY , XtNng int, wqpXH int, gtvRs varchar(255), DcdMb real, WGMJh date, UHTJz real, gENXMt_ID int); 79 | CREATE TABLE tDlMnM (id int PRIMARY KEY , hMnNB int, JJUaI date, fOERV date, Habqf varchar(255), kvtJw real, qVAWz varchar(255), wJqiQ int, bsDHHY_ID int); 80 | CREATE TABLE kjIZZZ (id int PRIMARY KEY , XKjKE int, EsLxW real, kxpdR date, aCLnk int, pFevd int, fHIkS date, NwDkY int, HvJMn real, PhyVtj_ID int); 81 | CREATE TABLE bPpvuj (id int PRIMARY KEY , CBWYv real, VQmXL date, qQgIL real, TsxqnH_ID int); 82 | CREATE TABLE TMPuyI (id int PRIMARY KEY , RgyQh varchar(255), JvvJb real, EdFiV date, Vatkk varchar(255), BZOkF real, JMHXM varchar(255), lxOZzT_ID int); 83 | CREATE TABLE sxUYAt (id int PRIMARY KEY , PgrgK real, WUiWu real, FDZBx date, YvWkb date, jaSVV date, rCjJOY_ID int); 84 | CREATE TABLE rshxkL (id int PRIMARY KEY , qriXZ date, fjnzR real, XqWDr int, bLUZrQ_ID int); 85 | CREATE TABLE GBETzd (id int PRIMARY KEY , DrLIs real, OToZi int, OMOqz date, XCCwun_ID int); 86 | CREATE TABLE RCvyeN (id int PRIMARY KEY , jmNQf date, YzIMO real, STdrVR_ID int); 87 | CREATE TABLE ZrrQju (id int PRIMARY KEY , yEwFy real, pLkgN date, RtjUT int, IOceG real, mNkog varchar(255), mouYmR_ID int); 88 | CREATE TABLE EGLIkO (id int PRIMARY KEY , zZgIz int, aXoxp real, eDNGf int, erVfK varchar(255), RLplfQ_ID int); 89 | CREATE TABLE eahMiA (id int PRIMARY KEY , MhWWl int, vxRKr varchar(255), bJXcZ date, Kaewj int, cMgny varchar(255), NYSuL varchar(255), MDDmXB_ID int); 90 | CREATE TABLE dAClXU (id int PRIMARY KEY , baPwC date, NdAFH real, MVdph varchar(255), vvvSv date, cRNQs int, yZJwy varchar(255), THdVup_ID int); 91 | CREATE TABLE lLdySD (id int PRIMARY KEY , YKolF varchar(255), jzZHAj_ID int); 92 | CREATE TABLE HaKpzz (id int PRIMARY KEY , hThWS int, PXnEu varchar(255), ToZIr int, ZhclB varchar(255), XCCwun_ID int); 93 | CREATE TABLE fmVXeS (id int PRIMARY KEY , FAqdB date, gqVgV date, gPXVp varchar(255), cBXrk int, PHUvL int, KfyQLw_ID int); 94 | CREATE TABLE ETAuiI (id int PRIMARY KEY , YftSL date, LtkSi real, akSmV int, EbNlS int, FXwoBM_ID int); 95 | CREATE TABLE JgukmY (id int PRIMARY KEY , Xpbxi real, ACdOj date, pWASU real, uuLSu date, IhVJN real, KJjDR varchar(255), DntkOC_ID int); 96 | CREATE TABLE ccZAeN (id int PRIMARY KEY , UZtRK date, dtugA int, TqBgg int, oqNlf varchar(255), NGbkFR_ID int); 97 | CREATE TABLE KuMlGI (id int PRIMARY KEY , mcjHL int, LFfsK real, oykGJl_ID int); 98 | CREATE TABLE cXNZNq (id int PRIMARY KEY , uMpRN varchar(255), lShAO real, PxQWNj_ID int); 99 | CREATE TABLE bLUZrQ (id int PRIMARY KEY , kRqXx int, AIKwT real, fbNUl int, rwfSm varchar(255), reEOyJ_ID int); 100 | CREATE TABLE CUPCGG (id int PRIMARY KEY , GMwPH varchar(255), OsNSgX_ID int); 101 | CREATE TABLE eojpFF (id int PRIMARY KEY , NfHco date, umFgC date, fDsJn varchar(255), nAIHW date, hPrgA int, BsjKA varchar(255), EDGFN int, oykGJl_ID int); 102 | CREATE TABLE zTVgDf (id int PRIMARY KEY , CCWhx varchar(255), zIzuw date, QMTtD real, iBHAc real, iCHCf date, hZsUi date, WsZeR real, BxlLj date, EtttHE_ID int); 103 | CREATE TABLE PhyVtj (id int PRIMARY KEY , aajsb varchar(255), YHTwp real, gZRHk date, Qgyba varchar(255), Smhcm real, ogRCM real, UpnvHd_ID int); 104 | CREATE TABLE oBynip (id int PRIMARY KEY , RlVUp varchar(255), BEqgR date, zXLjV int, UsPEnL_ID int); 105 | CREATE TABLE JlaUqh (id int PRIMARY KEY , Nqgzc date, ojlHr real, IAZLZ int, exLcO varchar(255), rCjJOY_ID int); 106 | CREATE TABLE RLplfQ (id int PRIMARY KEY , nyoMl int, ZhxxFq_ID int); 107 | CREATE TABLE taZSIF (id int PRIMARY KEY , RilPQ real, DdlZm date, XOXmu real, ZFckAf_ID int); 108 | CREATE TABLE CAfYiR (id int PRIMARY KEY , QuNBd date, xZmMu varchar(255), XKwKt varchar(255), gvGFk varchar(255), cqJxnk_ID int); 109 | CREATE TABLE yoLlCT (id int PRIMARY KEY , GRwtP date, RLBok varchar(255), RxEMb varchar(255), IJWhV real, SjqES int, kKYuG date, OZxOo varchar(255), rshxkL_ID int); 110 | CREATE TABLE BiTmSA (id int PRIMARY KEY , hqKBs real, bPpvuj_ID int); 111 | CREATE TABLE PneQEt (id int PRIMARY KEY , XNDTM varchar(255), buapd varchar(255), UudLx int, tHMsB date, iGNmA int, zTVgDf_ID int); 112 | CREATE TABLE HlwFkA (id int PRIMARY KEY , fICvf varchar(255), DShXp date, QyafG varchar(255), CCoQz int, eojpFF_ID int); 113 | CREATE TABLE tMjzMd (id int PRIMARY KEY , qljHu real, ZlQua int, eszIs real, vzqUp int, XcGQn varchar(255), jfRqG date, DntkOC_ID int); 114 | CREATE TABLE UsPEnL (id int PRIMARY KEY , pRTTH int, eGzOn real, ZDaWV real, uWJch int, sWPLl int, TNULV date, zZrhy varchar(255), LjllEi_ID int); 115 | CREATE TABLE leTpvV (id int PRIMARY KEY , iLnLZ varchar(255), PokNxo_ID int); 116 | CREATE TABLE SXVqAW (id int PRIMARY KEY , lNigk date, CvnbT date, MbGZU date, eojpFF_ID int); 117 | CREATE TABLE ntHgoG (id int PRIMARY KEY , CDlAB int, aXNAP int, XnONb int, sVmAt int, oqaCK int, zLvsfF_ID int); 118 | CREATE TABLE rbusXi (id int PRIMARY KEY , nOaoV varchar(255), OqWmh int, ockJG varchar(255), fmjwe int, srrZm real, asSGbe_ID int); 119 | CREATE TABLE LCMPEq (id int PRIMARY KEY , eTUOQ varchar(255), XrWXp date, XOXTF int, XWBvWi_ID int); 120 | CREATE TABLE bsDHHY (id int PRIMARY KEY , iHjLb varchar(255), aNwWcB_ID int); 121 | CREATE TABLE xkVibA (id int PRIMARY KEY , Wyuwu date, cVtMb real, HNoLa int, BifxK date, lPjNS int, GhnrC int, NRxsk date, ZxOyu date, NGbkFR_ID int); 122 | CREATE TABLE rZGoIt (id int PRIMARY KEY , AjKcU varchar(255), EvXlj real, MXvRY int, bPpvuj_ID int); 123 | CREATE TABLE PokNxo (id int PRIMARY KEY , jTFqc int, qDfvA real, vmQej real, TDirQ real, SHdEO varchar(255), eNMGy date, IiMZo int, Gkmum real, KuMlGI_ID int); 124 | CREATE TABLE BfcNaO (id int PRIMARY KEY , ilesS real, GYeGf date, TGuno int, zDLgx int, NSdsPc_ID int); 125 | CREATE TABLE PbjylL (id int PRIMARY KEY , CSjwM real, TsbFi varchar(255), gdUaf real, WQTcA date, NwZla varchar(255), HgyVg varchar(255), tlfFs int, TsxqnH_ID int); 126 | CREATE TABLE UUmhZo (id int PRIMARY KEY , IxQVD int, qZnMQ real, JJFEx int, yjQqW date, NKbXr int, vZnnf real, AHFgIV_ID int); 127 | CREATE TABLE agjKUU (id int PRIMARY KEY , pdGLK varchar(255), wnmCy varchar(255), uuoDJ varchar(255), jZSWq real, LJitm varchar(255), WyeKsa_ID int); 128 | CREATE TABLE HiUjRB (id int PRIMARY KEY , xZFMz varchar(255), GtaIw int, WeoIOJ_ID int); 129 | CREATE TABLE hvjdhH (id int PRIMARY KEY , ndNtl date, xiUsC date, RnmGs real, SStGgJ_ID int); 130 | CREATE TABLE euStHr (id int PRIMARY KEY , CYbJv int, oVOis int, Rvwkq int, CGxxQ date, SbsiQ real, yaHiKG_ID int); 131 | CREATE TABLE SzNKPJ (id int PRIMARY KEY , FPLei real, DgFRB varchar(255), iFzEt date, YDBvb varchar(255), bTqfR date, ZnDYV int, jVElC real, ldnWOM_ID int); 132 | CREATE TABLE UoDsiE (id int PRIMARY KEY , rnjME real, JzIPO int, taZSIF_ID int); 133 | CREATE TABLE MloAjY (id int PRIMARY KEY , WukkZ int, scjvT real, EOCIWK_ID int); 134 | CREATE TABLE DDXlrn (id int PRIMARY KEY , OcVKL int, UnygN date, ccZAeN_ID int); 135 | CREATE TABLE tTidRb (id int PRIMARY KEY , iEThw int, QYCmD int, CVNPD varchar(255), wqFlh int, DXHVJ date, OsNSgX_ID int); 136 | CREATE TABLE fhUikX (id int PRIMARY KEY , RlAHg date, EXjAP real, fVXHJ date, piSzX real, meFdY int, ZFckAf_ID int); 137 | CREATE TABLE xkAQKi (id int PRIMARY KEY , xTOxt date, aIhlF date, xsFos real, wYiTw date, TOHPiM_ID int); 138 | CREATE TABLE XuInYq (id int PRIMARY KEY , eMnBg date, KAkXqG_ID int); 139 | CREATE TABLE reLstq (id int PRIMARY KEY , WywFU varchar(255), KXkUK date, LrIlf int, rshxkL_ID int); 140 | CREATE TABLE QFtmGe (id int PRIMARY KEY , EGpfi int, odsVS int, cqJxnk_ID int); 141 | CREATE TABLE XCCwun (id int PRIMARY KEY , JoDNL int, yOtZo real, aUvRF real, PToZK int, kGxQH varchar(255), JVtDY int, WeoIOJ_ID int); 142 | CREATE TABLE EtttHE (id int PRIMARY KEY , pvsvn varchar(255), zXdde real, BfcNaO_ID int); 143 | CREATE TABLE yKlmln (id int PRIMARY KEY , fEFMv int, iBPWD date, vecBO date, AGpmFj_ID int); 144 | CREATE TABLE hHLVZi (id int PRIMARY KEY , PKJgg date, QGRRo int, VVTlA int, yonqh date, xHXCL int, VxxtB real, krujj int, YpOYO varchar(255), GZFKjJ_ID int); 145 | CREATE TABLE SXqUqX (id int PRIMARY KEY , Dzvml int, Eozag date, qEboy real, IKaNJ int, LgZUf real, DEzyb real, psYII varchar(255), dsfNE date, qAyLiP_ID int); 146 | CREATE TABLE pajnuX (id int PRIMARY KEY , VmrOX varchar(255), MJZuW date, SGADUe_ID int); 147 | CREATE TABLE QWFiBa (id int PRIMARY KEY , EtjUz int, rwJsx real, jIUYa varchar(255), iLrEt real, VExhP int, FiqaL real, TfjDL varchar(255), EOCIWK_ID int); 148 | CREATE TABLE asSGbe (id int PRIMARY KEY , EbRaz date, lAXox date, lFEJQ int, nDfYs real, ixGUej_ID int); 149 | CREATE TABLE pfUMmQ (id int PRIMARY KEY , SlRKE date, udABW date, nyKBZ date, VGuiM varchar(255), zunqH varchar(255), VpTKz real, zmEDK date, IZWAp real, qzjNFD_ID int); 150 | CREATE TABLE PoDHnF (id int PRIMARY KEY , eCCos date, DZYcR int, QfbLCm_ID int); 151 | CREATE TABLE qctAzd (id int PRIMARY KEY , PUhtF int, PcYSA date, skwCh int, MjIPG varchar(255), WiGME int, HJUKod_ID int); 152 | CREATE TABLE GhtmfN (id int PRIMARY KEY , mFgoj date, mNpmX date, aCFmJA_ID int); 153 | CREATE TABLE SStGgJ (id int PRIMARY KEY , cLlkh varchar(255), rKcer varchar(255), eBhRF date, agXMf varchar(255), CFDXf date, UDKdM date, rMIQt date, LpQhZI_ID int); 154 | CREATE TABLE GZFKjJ (id int PRIMARY KEY , ockrc date, SUnvW varchar(255), kucMV real, farmw date, iPyAN date, BmiWe real, OcDcJ real, AidnJ varchar(255), rZGoIt_ID int); 155 | CREATE TABLE ZhxxFq (id int PRIMARY KEY , MbZQP int, ecbmG real, cErFM date, zNBZq varchar(255), BXxSC int, asSGbe_ID int); 156 | CREATE TABLE hjjCpx (id int PRIMARY KEY , YixXA varchar(255), eqNrW date, AteXY real, vPEwk varchar(255), rZGoIt_ID int); 157 | CREATE TABLE WNmMPb (id int PRIMARY KEY , NTMoZ real, VIchO date, ZhCko real, QMuhs real, TOXxr int, OXxDI date, EOCIWK_ID int); 158 | CREATE TABLE aNwWcB (id int PRIMARY KEY , pzjbi int, DFqfh int, Rzmpn date, hKgrA real, tGKpG date, JxuHN date, fXKhh real, lUyhw date, qAyLiP_ID int); 159 | CREATE TABLE ZFckAf (id int PRIMARY KEY , cPQUg real, IXaMZ date, LKVTG varchar(255), VdxSj real, DGzlkm_ID int); 160 | CREATE TABLE mxZLSn (id int PRIMARY KEY , LdUHQ varchar(255), uFyVa int, zqKSU real, yKlmln_ID int); 161 | CREATE TABLE ZaCpBx (id int PRIMARY KEY , dqQVL date, ucozC real, yaHiKG_ID int); 162 | CREATE TABLE SGADUe (id int PRIMARY KEY , GTWXY varchar(255), OzFCN varchar(255), QmqqT varchar(255), cHxDA date, euStHr_ID int); 163 | CREATE TABLE yLcihn (id int PRIMARY KEY , xQrfN date, LtoNf int, lxOZzT_ID int); 164 | CREATE TABLE jzZHAj (id int PRIMARY KEY , AItlT date, vTfVm real, uqtGJ varchar(255), WNywc date, PJBwc varchar(255), ntHgoG_ID int); 165 | CREATE TABLE WrOqDW (id int PRIMARY KEY , XNJYn date, VNXoq int, rZGoIt_ID int); 166 | CREATE TABLE PcMLdG (id int PRIMARY KEY , uAjAd real, QHLFV real, jgkQW int, hPLSN real, OIaMJ varchar(255), AGpmFj_ID int); 167 | CREATE TABLE zJAYlX (id int PRIMARY KEY , obcyp date, qncyN varchar(255), nOHuz varchar(255), ibzzsF_ID int); 168 | CREATE TABLE NSdsPc (id int PRIMARY KEY , ptTRs varchar(255), TlSBw date, tRlhM date, JgkOK date, VJvDM real, AHFgIV_ID int); 169 | CREATE TABLE TOHPiM (id int PRIMARY KEY , hAstH real, PGBoV date, QlAaV int, cgYVG varchar(255), FPyTi real, yGErj varchar(255), WqXFJ int, EgAkY varchar(255), zJAYlX_ID int); 170 | CREATE TABLE qzjNFD (id int PRIMARY KEY , grhoG real, GyJtZ date, TerOV int, UVLTH date, ZiQpA date, RJSGf varchar(255), xGCjL int, ZPxDh real, rbusXi_ID int); 171 | CREATE TABLE OUCbVV (id int PRIMARY KEY , QakYq varchar(255), DhaNL int, zJAYlX_ID int); 172 | CREATE TABLE EOCIWK (id int PRIMARY KEY , sBeyZ date, ryOhj int, tMjzMd_ID int); 173 | CREATE TABLE LrxfcC (id int PRIMARY KEY , Konah real, crBxs date, GWnXr real, jXojC date, QnExj varchar(255), rCjJOY_ID int); 174 | CREATE TABLE AHFgIV (id int PRIMARY KEY , lKuEc int, qzjNFD_ID int); 175 | CREATE TABLE STdrVR (id int PRIMARY KEY , yZeTO varchar(255), CRSrs varchar(255), JATDF int, kTdKi int, ZmREE varchar(255), qZiSf real, QJSJh varchar(255), gAucg real, PbjylL_ID int); 176 | CREATE TABLE qAyLiP (id int PRIMARY KEY , CliPj int, ZFIer real, OiXZj int, krkYs date, hwQDG int, eahMiA_ID int); 177 | CREATE TABLE sxLMSr (id int PRIMARY KEY , xEdoy date, LjllEi_ID int); 178 | CREATE TABLE TsxqnH (id int PRIMARY KEY , XJIxy int, IhGEJ date, RBvCP int, kzNXZ date, cxvVl varchar(255), QSzyL int, uDXzw int, fUHeO int, ETAuiI_ID int); 179 | CREATE TABLE LQyHyh (id int PRIMARY KEY , FJJYa real, orllT date, hkBCo int, teHnO int, woLyC date, lLdySD_ID int); 180 | CREATE TABLE LjllEi (id int PRIMARY KEY , pGppt date, ZBCBu int, YBEtI real, VThbo varchar(255), XiEOa date, MRRNuJ_ID int); 181 | CREATE TABLE ixGUej (id int PRIMARY KEY , pmCOi date, cOURa int, eaZZN date, SIWSo date, HcwAL varchar(255), dAClXU_ID int); 182 | CREATE TABLE xTZRNJ (id int PRIMARY KEY , splcG int, eaIHZ real, hsQrq varchar(255), shZNX real, hZYbz real, wktQQy_ID int); 183 | CREATE TABLE tsVYiA (id int PRIMARY KEY , gSOSn date, duUQq date, xcMeh int, IJWyp real, VkrsiX_ID int); 184 | CREATE TABLE mouYmR (id int PRIMARY KEY , gxvgd int, EKOUi real, ZkOjk varchar(255), VypUU date, ZaCpBx_ID int); 185 | CREATE TABLE RsTLSw (id int PRIMARY KEY , lmiLm date, JAdFC real, KOuqu date, Uxrre date, MuFMy date, UnncL date, VfRhR date, cvXiu int, AlHYzn_ID int); 186 | CREATE TABLE HMWzTm (id int PRIMARY KEY , GnbJG real, HYlLN real, HaZQy real, XSoND real, wYdNY date, zMKLp varchar(255), KfyQLw_ID int); 187 | CREATE TABLE whkbef (id int PRIMARY KEY , reJjp varchar(255), fHBEa varchar(255), znbgp date, eSGpt date, iqKdX date, LlsLW date, MLSob int, VkrsiX_ID int); 188 | CREATE TABLE QfbLCm (id int PRIMARY KEY , InigB varchar(255), MloAjY_ID int); 189 | CREATE TABLE qFTkHX (id int PRIMARY KEY , geode varchar(255), iKBnv date, ZIVBB varchar(255), TrXim real, FYROr date, TQJoy real, DyxKz date, wryWq date, xkBdMq_ID int); 190 | CREATE TABLE hotsHd (id int PRIMARY KEY , kjcsF varchar(255), ykrHsd_ID int); 191 | CREATE TABLE aCFmJA (id int PRIMARY KEY , uWHki int, cfpsc real, tVRYS varchar(255), DGzlkm_ID int); 192 | CREATE TABLE cQRqpB (id int PRIMARY KEY , UsKUw real, NAsYR int, KZrBj real, ABtFH varchar(255), HuBVp int, MRRNuJ_ID int); 193 | CREATE TABLE KjnfkQ (id int PRIMARY KEY , uUhKY real, pYEkSq_ID int); 194 | CREATE TABLE cqJxnk (id int PRIMARY KEY , sBall int, jmiiSG_ID int); 195 | CREATE TABLE EfRLUb (id int PRIMARY KEY , ahfwr real, gMtlS real, bsDHHY_ID int); 196 | CREATE TABLE GUKozY (id int PRIMARY KEY , ClUJG real, lXXdn varchar(255), rnGiZ int, ShQWY date, eqGFx date, VSnab real, xkBdMq_ID int); 197 | CREATE TABLE sAhqfi (id int PRIMARY KEY , nyHil varchar(255), wRFoM date, GbYkp int, ILEev int, GBETzd_ID int); 198 | CREATE TABLE THdVup (id int PRIMARY KEY , NgnlS varchar(255), NSdsPc_ID int); 199 | CREATE TABLE fFmtEY (id int PRIMARY KEY , gIEGk date, hwRIH varchar(255), XrBYN varchar(255), erAww varchar(255), tRnFd date, PAIjQ int, qQcDj date, gfPTM real, MITiAg_ID int); 200 | CREATE TABLE mLrqBh (id int PRIMARY KEY , UXwYY varchar(255), jsxIK int, ckGen real, qoJWAy_ID int); 201 | ALTER TABLE AlHYzn ADD FOREIGN KEY (eojpFF_ID) REFERENCES eojpFF (id); 202 | ALTER TABLE PxQWNj ADD FOREIGN KEY (KjnfkQ_ID) REFERENCES KjnfkQ (id); 203 | ALTER TABLE ldnWOM ADD FOREIGN KEY (PoDHnF_ID) REFERENCES PoDHnF (id); 204 | ALTER TABLE reEOyJ ADD FOREIGN KEY (WNmMPb_ID) REFERENCES WNmMPb (id); 205 | ALTER TABLE cKmFEN ADD FOREIGN KEY (fFmtEY_ID) REFERENCES fFmtEY (id); 206 | ALTER TABLE sstGay ADD FOREIGN KEY (fMkPwr_ID) REFERENCES fMkPwr (id); 207 | ALTER TABLE txQUBM ADD FOREIGN KEY (lLdySD_ID) REFERENCES lLdySD (id); 208 | ALTER TABLE KAkXqG ADD FOREIGN KEY (AGpmFj_ID) REFERENCES AGpmFj (id); 209 | ALTER TABLE MDDmXB ADD FOREIGN KEY (SXVqAW_ID) REFERENCES SXVqAW (id); 210 | ALTER TABLE xkBdMq ADD FOREIGN KEY (asSGbe_ID) REFERENCES asSGbe (id); 211 | ALTER TABLE SMWciT ADD FOREIGN KEY (NSdsPc_ID) REFERENCES NSdsPc (id); 212 | ALTER TABLE UpnvHd ADD FOREIGN KEY (EOCIWK_ID) REFERENCES EOCIWK (id); 213 | ALTER TABLE yaHiKG ADD FOREIGN KEY (RkVMkT_ID) REFERENCES RkVMkT (id); 214 | ALTER TABLE yLzRCK ADD FOREIGN KEY (ETAuiI_ID) REFERENCES ETAuiI (id); 215 | ALTER TABLE oykGJl ADD FOREIGN KEY (RLplfQ_ID) REFERENCES RLplfQ (id); 216 | ALTER TABLE MKmkAN ADD FOREIGN KEY (TMPuyI_ID) REFERENCES TMPuyI (id); 217 | ALTER TABLE wqpwQp ADD FOREIGN KEY (sxLMSr_ID) REFERENCES sxLMSr (id); 218 | ALTER TABLE pYEkSq ADD FOREIGN KEY (NGbkFR_ID) REFERENCES NGbkFR (id); 219 | ALTER TABLE jBwJVP ADD FOREIGN KEY (wktQQy_ID) REFERENCES wktQQy (id); 220 | ALTER TABLE lDbhwB ADD FOREIGN KEY (PxQWNj_ID) REFERENCES PxQWNj (id); 221 | ALTER TABLE sOLmWO ADD FOREIGN KEY (TGwdSW_ID) REFERENCES TGwdSW (id); 222 | ALTER TABLE LVAYmz ADD FOREIGN KEY (EGLIkO_ID) REFERENCES EGLIkO (id); 223 | ALTER TABLE ykrHsd ADD FOREIGN KEY (xkVibA_ID) REFERENCES xkVibA (id); 224 | ALTER TABLE NbORDP ADD FOREIGN KEY (CUPCGG_ID) REFERENCES CUPCGG (id); 225 | ALTER TABLE MITiAg ADD FOREIGN KEY (zJAYlX_ID) REFERENCES zJAYlX (id); 226 | ALTER TABLE VkrsiX ADD FOREIGN KEY (TsxqnH_ID) REFERENCES TsxqnH (id); 227 | ALTER TABLE pPdJMK ADD FOREIGN KEY (HaKpzz_ID) REFERENCES HaKpzz (id); 228 | ALTER TABLE jmiiSG ADD FOREIGN KEY (rZGoIt_ID) REFERENCES rZGoIt (id); 229 | ALTER TABLE KfyQLw ADD FOREIGN KEY (EfRLUb_ID) REFERENCES EfRLUb (id); 230 | ALTER TABLE DntkOC ADD FOREIGN KEY (MRRNuJ_ID) REFERENCES MRRNuJ (id); 231 | ALTER TABLE pQcMRA ADD FOREIGN KEY (TOHPiM_ID) REFERENCES TOHPiM (id); 232 | ALTER TABLE kUBKBI ADD FOREIGN KEY (kjIZZZ_ID) REFERENCES kjIZZZ (id); 233 | ALTER TABLE LpQhZI ADD FOREIGN KEY (vPghiH_ID) REFERENCES vPghiH (id); 234 | ALTER TABLE vbnySX ADD FOREIGN KEY (KjnfkQ_ID) REFERENCES KjnfkQ (id); 235 | ALTER TABLE fMkPwr ADD FOREIGN KEY (JCixda_ID) REFERENCES JCixda (id); 236 | ALTER TABLE hCgWvz ADD FOREIGN KEY (whkbef_ID) REFERENCES whkbef (id); 237 | ALTER TABLE DGzlkm ADD FOREIGN KEY (bLUZrQ_ID) REFERENCES bLUZrQ (id); 238 | ALTER TABLE JCixda ADD FOREIGN KEY (LpQhZI_ID) REFERENCES LpQhZI (id); 239 | ALTER TABLE YblLZW ADD FOREIGN KEY (ZFckAf_ID) REFERENCES ZFckAf (id); 240 | ALTER TABLE MRRNuJ ADD FOREIGN KEY (hjjCpx_ID) REFERENCES hjjCpx (id); 241 | ALTER TABLE ibzzsF ADD FOREIGN KEY (HiUjRB_ID) REFERENCES HiUjRB (id); 242 | ALTER TABLE gENXMt ADD FOREIGN KEY (TOHPiM_ID) REFERENCES TOHPiM (id); 243 | ALTER TABLE yVYdQs ADD FOREIGN KEY (pPdJMK_ID) REFERENCES pPdJMK (id); 244 | ALTER TABLE KiBGLM ADD FOREIGN KEY (tMjzMd_ID) REFERENCES tMjzMd (id); 245 | ALTER TABLE ZbTRFz ADD FOREIGN KEY (cQRqpB_ID) REFERENCES cQRqpB (id); 246 | ALTER TABLE qoJWAy ADD FOREIGN KEY (pfUMmQ_ID) REFERENCES pfUMmQ (id); 247 | ALTER TABLE HJQEDj ADD FOREIGN KEY (QWFiBa_ID) REFERENCES QWFiBa (id); 248 | ALTER TABLE irQfhQ ADD FOREIGN KEY (LrxfcC_ID) REFERENCES LrxfcC (id); 249 | ALTER TABLE OsNSgX ADD FOREIGN KEY (BfcNaO_ID) REFERENCES BfcNaO (id); 250 | ALTER TABLE zLvsfF ADD FOREIGN KEY (rByzcn_ID) REFERENCES rByzcn (id); 251 | ALTER TABLE WyeKsa ADD FOREIGN KEY (eahMiA_ID) REFERENCES eahMiA (id); 252 | ALTER TABLE Qbxmza ADD FOREIGN KEY (WNmMPb_ID) REFERENCES WNmMPb (id); 253 | ALTER TABLE wtNGtl ADD FOREIGN KEY (GZFKjJ_ID) REFERENCES GZFKjJ (id); 254 | ALTER TABLE AGpmFj ADD FOREIGN KEY (fhUikX_ID) REFERENCES fhUikX (id); 255 | ALTER TABLE XWBvWi ADD FOREIGN KEY (dAClXU_ID) REFERENCES dAClXU (id); 256 | ALTER TABLE ebiQXH ADD FOREIGN KEY (pQcMRA_ID) REFERENCES pQcMRA (id); 257 | ALTER TABLE NGbkFR ADD FOREIGN KEY (SMWciT_ID) REFERENCES SMWciT (id); 258 | ALTER TABLE FXwoBM ADD FOREIGN KEY (AGpmFj_ID) REFERENCES AGpmFj (id); 259 | ALTER TABLE glitlo ADD FOREIGN KEY (XCCwun_ID) REFERENCES XCCwun (id); 260 | ALTER TABLE rByzcn ADD FOREIGN KEY (ccZAeN_ID) REFERENCES ccZAeN (id); 261 | ALTER TABLE rCjJOY ADD FOREIGN KEY (SXVqAW_ID) REFERENCES SXVqAW (id); 262 | ALTER TABLE UJdYsj ADD FOREIGN KEY (RsTLSw_ID) REFERENCES RsTLSw (id); 263 | ALTER TABLE lxOZzT ADD FOREIGN KEY (TGwdSW_ID) REFERENCES TGwdSW (id); 264 | ALTER TABLE vPghiH ADD FOREIGN KEY (pPdJMK_ID) REFERENCES pPdJMK (id); 265 | ALTER TABLE TsRrQc ADD FOREIGN KEY (DDXlrn_ID) REFERENCES DDXlrn (id); 266 | ALTER TABLE WeoIOJ ADD FOREIGN KEY (xkBdMq_ID) REFERENCES xkBdMq (id); 267 | ALTER TABLE SsSwtG ADD FOREIGN KEY (pYEkSq_ID) REFERENCES pYEkSq (id); 268 | ALTER TABLE zNEJUG ADD FOREIGN KEY (SGADUe_ID) REFERENCES SGADUe (id); 269 | ALTER TABLE MofNeU ADD FOREIGN KEY (ykrHsd_ID) REFERENCES ykrHsd (id); 270 | ALTER TABLE HJUKod ADD FOREIGN KEY (UUmhZo_ID) REFERENCES UUmhZo (id); 271 | ALTER TABLE BkdpgJ ADD FOREIGN KEY (ZaCpBx_ID) REFERENCES ZaCpBx (id); 272 | ALTER TABLE vuohmP ADD FOREIGN KEY (SXqUqX_ID) REFERENCES SXqUqX (id); 273 | ALTER TABLE wktQQy ADD FOREIGN KEY (TGwdSW_ID) REFERENCES TGwdSW (id); 274 | ALTER TABLE RkVMkT ADD FOREIGN KEY (vuohmP_ID) REFERENCES vuohmP (id); 275 | ALTER TABLE XvFPTt ADD FOREIGN KEY (XuInYq_ID) REFERENCES XuInYq (id); 276 | ALTER TABLE iPTlhi ADD FOREIGN KEY (PbjylL_ID) REFERENCES PbjylL (id); 277 | ALTER TABLE yErwOg ADD FOREIGN KEY (yLcihn_ID) REFERENCES yLcihn (id); 278 | ALTER TABLE TGwdSW ADD FOREIGN KEY (gENXMt_ID) REFERENCES gENXMt (id); 279 | ALTER TABLE tDlMnM ADD FOREIGN KEY (bsDHHY_ID) REFERENCES bsDHHY (id); 280 | ALTER TABLE kjIZZZ ADD FOREIGN KEY (PhyVtj_ID) REFERENCES PhyVtj (id); 281 | ALTER TABLE bPpvuj ADD FOREIGN KEY (TsxqnH_ID) REFERENCES TsxqnH (id); 282 | ALTER TABLE TMPuyI ADD FOREIGN KEY (lxOZzT_ID) REFERENCES lxOZzT (id); 283 | ALTER TABLE sxUYAt ADD FOREIGN KEY (rCjJOY_ID) REFERENCES rCjJOY (id); 284 | ALTER TABLE rshxkL ADD FOREIGN KEY (bLUZrQ_ID) REFERENCES bLUZrQ (id); 285 | ALTER TABLE GBETzd ADD FOREIGN KEY (XCCwun_ID) REFERENCES XCCwun (id); 286 | ALTER TABLE RCvyeN ADD FOREIGN KEY (STdrVR_ID) REFERENCES STdrVR (id); 287 | ALTER TABLE ZrrQju ADD FOREIGN KEY (mouYmR_ID) REFERENCES mouYmR (id); 288 | ALTER TABLE EGLIkO ADD FOREIGN KEY (RLplfQ_ID) REFERENCES RLplfQ (id); 289 | ALTER TABLE eahMiA ADD FOREIGN KEY (MDDmXB_ID) REFERENCES MDDmXB (id); 290 | ALTER TABLE dAClXU ADD FOREIGN KEY (THdVup_ID) REFERENCES THdVup (id); 291 | ALTER TABLE lLdySD ADD FOREIGN KEY (jzZHAj_ID) REFERENCES jzZHAj (id); 292 | ALTER TABLE HaKpzz ADD FOREIGN KEY (XCCwun_ID) REFERENCES XCCwun (id); 293 | ALTER TABLE fmVXeS ADD FOREIGN KEY (KfyQLw_ID) REFERENCES KfyQLw (id); 294 | ALTER TABLE ETAuiI ADD FOREIGN KEY (FXwoBM_ID) REFERENCES FXwoBM (id); 295 | ALTER TABLE JgukmY ADD FOREIGN KEY (DntkOC_ID) REFERENCES DntkOC (id); 296 | ALTER TABLE ccZAeN ADD FOREIGN KEY (NGbkFR_ID) REFERENCES NGbkFR (id); 297 | ALTER TABLE KuMlGI ADD FOREIGN KEY (oykGJl_ID) REFERENCES oykGJl (id); 298 | ALTER TABLE cXNZNq ADD FOREIGN KEY (PxQWNj_ID) REFERENCES PxQWNj (id); 299 | ALTER TABLE bLUZrQ ADD FOREIGN KEY (reEOyJ_ID) REFERENCES reEOyJ (id); 300 | ALTER TABLE CUPCGG ADD FOREIGN KEY (OsNSgX_ID) REFERENCES OsNSgX (id); 301 | ALTER TABLE eojpFF ADD FOREIGN KEY (oykGJl_ID) REFERENCES oykGJl (id); 302 | ALTER TABLE zTVgDf ADD FOREIGN KEY (EtttHE_ID) REFERENCES EtttHE (id); 303 | ALTER TABLE PhyVtj ADD FOREIGN KEY (UpnvHd_ID) REFERENCES UpnvHd (id); 304 | ALTER TABLE oBynip ADD FOREIGN KEY (UsPEnL_ID) REFERENCES UsPEnL (id); 305 | ALTER TABLE JlaUqh ADD FOREIGN KEY (rCjJOY_ID) REFERENCES rCjJOY (id); 306 | ALTER TABLE RLplfQ ADD FOREIGN KEY (ZhxxFq_ID) REFERENCES ZhxxFq (id); 307 | ALTER TABLE taZSIF ADD FOREIGN KEY (ZFckAf_ID) REFERENCES ZFckAf (id); 308 | ALTER TABLE CAfYiR ADD FOREIGN KEY (cqJxnk_ID) REFERENCES cqJxnk (id); 309 | ALTER TABLE yoLlCT ADD FOREIGN KEY (rshxkL_ID) REFERENCES rshxkL (id); 310 | ALTER TABLE BiTmSA ADD FOREIGN KEY (bPpvuj_ID) REFERENCES bPpvuj (id); 311 | ALTER TABLE PneQEt ADD FOREIGN KEY (zTVgDf_ID) REFERENCES zTVgDf (id); 312 | ALTER TABLE HlwFkA ADD FOREIGN KEY (eojpFF_ID) REFERENCES eojpFF (id); 313 | ALTER TABLE tMjzMd ADD FOREIGN KEY (DntkOC_ID) REFERENCES DntkOC (id); 314 | ALTER TABLE UsPEnL ADD FOREIGN KEY (LjllEi_ID) REFERENCES LjllEi (id); 315 | ALTER TABLE leTpvV ADD FOREIGN KEY (PokNxo_ID) REFERENCES PokNxo (id); 316 | ALTER TABLE SXVqAW ADD FOREIGN KEY (eojpFF_ID) REFERENCES eojpFF (id); 317 | ALTER TABLE ntHgoG ADD FOREIGN KEY (zLvsfF_ID) REFERENCES zLvsfF (id); 318 | ALTER TABLE rbusXi ADD FOREIGN KEY (asSGbe_ID) REFERENCES asSGbe (id); 319 | ALTER TABLE LCMPEq ADD FOREIGN KEY (XWBvWi_ID) REFERENCES XWBvWi (id); 320 | ALTER TABLE bsDHHY ADD FOREIGN KEY (aNwWcB_ID) REFERENCES aNwWcB (id); 321 | ALTER TABLE xkVibA ADD FOREIGN KEY (NGbkFR_ID) REFERENCES NGbkFR (id); 322 | ALTER TABLE rZGoIt ADD FOREIGN KEY (bPpvuj_ID) REFERENCES bPpvuj (id); 323 | ALTER TABLE PokNxo ADD FOREIGN KEY (KuMlGI_ID) REFERENCES KuMlGI (id); 324 | ALTER TABLE BfcNaO ADD FOREIGN KEY (NSdsPc_ID) REFERENCES NSdsPc (id); 325 | ALTER TABLE PbjylL ADD FOREIGN KEY (TsxqnH_ID) REFERENCES TsxqnH (id); 326 | ALTER TABLE UUmhZo ADD FOREIGN KEY (AHFgIV_ID) REFERENCES AHFgIV (id); 327 | ALTER TABLE agjKUU ADD FOREIGN KEY (WyeKsa_ID) REFERENCES WyeKsa (id); 328 | ALTER TABLE HiUjRB ADD FOREIGN KEY (WeoIOJ_ID) REFERENCES WeoIOJ (id); 329 | ALTER TABLE hvjdhH ADD FOREIGN KEY (SStGgJ_ID) REFERENCES SStGgJ (id); 330 | ALTER TABLE euStHr ADD FOREIGN KEY (yaHiKG_ID) REFERENCES yaHiKG (id); 331 | ALTER TABLE SzNKPJ ADD FOREIGN KEY (ldnWOM_ID) REFERENCES ldnWOM (id); 332 | ALTER TABLE UoDsiE ADD FOREIGN KEY (taZSIF_ID) REFERENCES taZSIF (id); 333 | ALTER TABLE MloAjY ADD FOREIGN KEY (EOCIWK_ID) REFERENCES EOCIWK (id); 334 | ALTER TABLE DDXlrn ADD FOREIGN KEY (ccZAeN_ID) REFERENCES ccZAeN (id); 335 | ALTER TABLE tTidRb ADD FOREIGN KEY (OsNSgX_ID) REFERENCES OsNSgX (id); 336 | ALTER TABLE fhUikX ADD FOREIGN KEY (ZFckAf_ID) REFERENCES ZFckAf (id); 337 | ALTER TABLE xkAQKi ADD FOREIGN KEY (TOHPiM_ID) REFERENCES TOHPiM (id); 338 | ALTER TABLE XuInYq ADD FOREIGN KEY (KAkXqG_ID) REFERENCES KAkXqG (id); 339 | ALTER TABLE reLstq ADD FOREIGN KEY (rshxkL_ID) REFERENCES rshxkL (id); 340 | ALTER TABLE QFtmGe ADD FOREIGN KEY (cqJxnk_ID) REFERENCES cqJxnk (id); 341 | ALTER TABLE XCCwun ADD FOREIGN KEY (WeoIOJ_ID) REFERENCES WeoIOJ (id); 342 | ALTER TABLE EtttHE ADD FOREIGN KEY (BfcNaO_ID) REFERENCES BfcNaO (id); 343 | ALTER TABLE yKlmln ADD FOREIGN KEY (AGpmFj_ID) REFERENCES AGpmFj (id); 344 | ALTER TABLE hHLVZi ADD FOREIGN KEY (GZFKjJ_ID) REFERENCES GZFKjJ (id); 345 | ALTER TABLE SXqUqX ADD FOREIGN KEY (qAyLiP_ID) REFERENCES qAyLiP (id); 346 | ALTER TABLE pajnuX ADD FOREIGN KEY (SGADUe_ID) REFERENCES SGADUe (id); 347 | ALTER TABLE QWFiBa ADD FOREIGN KEY (EOCIWK_ID) REFERENCES EOCIWK (id); 348 | ALTER TABLE asSGbe ADD FOREIGN KEY (ixGUej_ID) REFERENCES ixGUej (id); 349 | ALTER TABLE pfUMmQ ADD FOREIGN KEY (qzjNFD_ID) REFERENCES qzjNFD (id); 350 | ALTER TABLE PoDHnF ADD FOREIGN KEY (QfbLCm_ID) REFERENCES QfbLCm (id); 351 | ALTER TABLE qctAzd ADD FOREIGN KEY (HJUKod_ID) REFERENCES HJUKod (id); 352 | ALTER TABLE GhtmfN ADD FOREIGN KEY (aCFmJA_ID) REFERENCES aCFmJA (id); 353 | ALTER TABLE SStGgJ ADD FOREIGN KEY (LpQhZI_ID) REFERENCES LpQhZI (id); 354 | ALTER TABLE GZFKjJ ADD FOREIGN KEY (rZGoIt_ID) REFERENCES rZGoIt (id); 355 | ALTER TABLE ZhxxFq ADD FOREIGN KEY (asSGbe_ID) REFERENCES asSGbe (id); 356 | ALTER TABLE hjjCpx ADD FOREIGN KEY (rZGoIt_ID) REFERENCES rZGoIt (id); 357 | ALTER TABLE WNmMPb ADD FOREIGN KEY (EOCIWK_ID) REFERENCES EOCIWK (id); 358 | ALTER TABLE aNwWcB ADD FOREIGN KEY (qAyLiP_ID) REFERENCES qAyLiP (id); 359 | ALTER TABLE ZFckAf ADD FOREIGN KEY (DGzlkm_ID) REFERENCES DGzlkm (id); 360 | ALTER TABLE mxZLSn ADD FOREIGN KEY (yKlmln_ID) REFERENCES yKlmln (id); 361 | ALTER TABLE ZaCpBx ADD FOREIGN KEY (yaHiKG_ID) REFERENCES yaHiKG (id); 362 | ALTER TABLE SGADUe ADD FOREIGN KEY (euStHr_ID) REFERENCES euStHr (id); 363 | ALTER TABLE yLcihn ADD FOREIGN KEY (lxOZzT_ID) REFERENCES lxOZzT (id); 364 | ALTER TABLE jzZHAj ADD FOREIGN KEY (ntHgoG_ID) REFERENCES ntHgoG (id); 365 | ALTER TABLE WrOqDW ADD FOREIGN KEY (rZGoIt_ID) REFERENCES rZGoIt (id); 366 | ALTER TABLE PcMLdG ADD FOREIGN KEY (AGpmFj_ID) REFERENCES AGpmFj (id); 367 | ALTER TABLE zJAYlX ADD FOREIGN KEY (ibzzsF_ID) REFERENCES ibzzsF (id); 368 | ALTER TABLE NSdsPc ADD FOREIGN KEY (AHFgIV_ID) REFERENCES AHFgIV (id); 369 | ALTER TABLE TOHPiM ADD FOREIGN KEY (zJAYlX_ID) REFERENCES zJAYlX (id); 370 | ALTER TABLE qzjNFD ADD FOREIGN KEY (rbusXi_ID) REFERENCES rbusXi (id); 371 | ALTER TABLE OUCbVV ADD FOREIGN KEY (zJAYlX_ID) REFERENCES zJAYlX (id); 372 | ALTER TABLE EOCIWK ADD FOREIGN KEY (tMjzMd_ID) REFERENCES tMjzMd (id); 373 | ALTER TABLE LrxfcC ADD FOREIGN KEY (rCjJOY_ID) REFERENCES rCjJOY (id); 374 | ALTER TABLE AHFgIV ADD FOREIGN KEY (qzjNFD_ID) REFERENCES qzjNFD (id); 375 | ALTER TABLE STdrVR ADD FOREIGN KEY (PbjylL_ID) REFERENCES PbjylL (id); 376 | ALTER TABLE qAyLiP ADD FOREIGN KEY (eahMiA_ID) REFERENCES eahMiA (id); 377 | ALTER TABLE sxLMSr ADD FOREIGN KEY (LjllEi_ID) REFERENCES LjllEi (id); 378 | ALTER TABLE TsxqnH ADD FOREIGN KEY (ETAuiI_ID) REFERENCES ETAuiI (id); 379 | ALTER TABLE LQyHyh ADD FOREIGN KEY (lLdySD_ID) REFERENCES lLdySD (id); 380 | ALTER TABLE LjllEi ADD FOREIGN KEY (MRRNuJ_ID) REFERENCES MRRNuJ (id); 381 | ALTER TABLE ixGUej ADD FOREIGN KEY (dAClXU_ID) REFERENCES dAClXU (id); 382 | ALTER TABLE xTZRNJ ADD FOREIGN KEY (wktQQy_ID) REFERENCES wktQQy (id); 383 | ALTER TABLE tsVYiA ADD FOREIGN KEY (VkrsiX_ID) REFERENCES VkrsiX (id); 384 | ALTER TABLE mouYmR ADD FOREIGN KEY (ZaCpBx_ID) REFERENCES ZaCpBx (id); 385 | ALTER TABLE RsTLSw ADD FOREIGN KEY (AlHYzn_ID) REFERENCES AlHYzn (id); 386 | ALTER TABLE HMWzTm ADD FOREIGN KEY (KfyQLw_ID) REFERENCES KfyQLw (id); 387 | ALTER TABLE whkbef ADD FOREIGN KEY (VkrsiX_ID) REFERENCES VkrsiX (id); 388 | ALTER TABLE QfbLCm ADD FOREIGN KEY (MloAjY_ID) REFERENCES MloAjY (id); 389 | ALTER TABLE qFTkHX ADD FOREIGN KEY (xkBdMq_ID) REFERENCES xkBdMq (id); 390 | ALTER TABLE hotsHd ADD FOREIGN KEY (ykrHsd_ID) REFERENCES ykrHsd (id); 391 | ALTER TABLE aCFmJA ADD FOREIGN KEY (DGzlkm_ID) REFERENCES DGzlkm (id); 392 | ALTER TABLE cQRqpB ADD FOREIGN KEY (MRRNuJ_ID) REFERENCES MRRNuJ (id); 393 | ALTER TABLE KjnfkQ ADD FOREIGN KEY (pYEkSq_ID) REFERENCES pYEkSq (id); 394 | ALTER TABLE cqJxnk ADD FOREIGN KEY (jmiiSG_ID) REFERENCES jmiiSG (id); 395 | ALTER TABLE EfRLUb ADD FOREIGN KEY (bsDHHY_ID) REFERENCES bsDHHY (id); 396 | ALTER TABLE GUKozY ADD FOREIGN KEY (xkBdMq_ID) REFERENCES xkBdMq (id); 397 | ALTER TABLE sAhqfi ADD FOREIGN KEY (GBETzd_ID) REFERENCES GBETzd (id); 398 | ALTER TABLE THdVup ADD FOREIGN KEY (NSdsPc_ID) REFERENCES NSdsPc (id); 399 | ALTER TABLE fFmtEY ADD FOREIGN KEY (MITiAg_ID) REFERENCES MITiAg (id); 400 | ALTER TABLE mLrqBh ADD FOREIGN KEY (qoJWAy_ID) REFERENCES qoJWAy (id); 401 | -------------------------------------------------------------------------------- /example/dbvisualizer_preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eska-muc/dbvisualizer/d1055925d8713ba086ae984751768a62ab89be48/example/dbvisualizer_preview.png -------------------------------------------------------------------------------- /example/postgresql_test.dot: -------------------------------------------------------------------------------- 1 | @startuml 2 | 'hide the spot 3 | hide circle 4 | ' comment 5 | skinparam linetype ortho 6 | entity "test.address" as test_address { 7 | *pk_address_id : int4 8 | -- 9 | street : varchar(80) 10 | house_no : varchar(10) 11 | city : varchar(80) 12 | state_province : varchar(80) 13 | postal_code : varchar(20) 14 | country : varchar(80) 15 | } 16 | 17 | entity "test.person" as test_person { 18 | *pk_person_id : int4 19 | -- 20 | *first_name : varchar(80) 21 | *last_name : varchar(80) 22 | *date_of_birth : date 23 | } 24 | 25 | entity "test.person_address" as test_person_address { 26 | fk_adress_id : int4 <> 27 | fk_person_id : int4 <> 28 | } 29 | 30 | 31 | test_person_address }|--|| test_address 32 | test_person_address }|--|| test_person 33 | @enduml 34 | -------------------------------------------------------------------------------- /example/postgresql_test.md: -------------------------------------------------------------------------------- 1 | # Report on test 2 | 3 | ## Table test.address 4 | 5 | Address table. Many persons may have the same address. 6 | 7 | ### Columns 8 | 9 | |Name|Constraints|Type|Comment| 10 | |----|-----------|----|-------| 11 | |pk_address_id|PK, Not Null|int4|Primary Key of address| 12 | |street| |varchar(80)|Street part of an address, if applicable| 13 | |house_no| |varchar(10)| | 14 | |city| |varchar(80)| | 15 | |state_province| |varchar(80)| | 16 | |postal_code| |varchar(20)| | 17 | |country| |varchar(80)| | 18 | 19 | ## Table test.person 20 | 21 | ### Columns 22 | 23 | |Name|Constraints|Type|Comment| 24 | |----|-----------|----|-------| 25 | |pk_person_id|PK, Not Null|int4| | 26 | |first_name|Not Null|varchar(80)| | 27 | |last_name|Not Null|varchar(80)| | 28 | |date_of_birth|Not Null|date| | 29 | 30 | ## Table test.person_address 31 | 32 | ### Columns 33 | 34 | |Name|Constraints|Type|Comment| 35 | |----|-----------|----|-------| 36 | |fk_adress_id|FK (table: test.address)|int4| | 37 | |fk_person_id|FK (table: test.person)|int4| | 38 | -------------------------------------------------------------------------------- /example/postgresql_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eska-muc/dbvisualizer/d1055925d8713ba086ae984751768a62ab89be48/example/postgresql_test.png -------------------------------------------------------------------------------- /example/postgresql_test.sql: -------------------------------------------------------------------------------- 1 | -- 2 | -- PostgreSQL database dump 3 | -- 4 | 5 | -- Dumped from database version 14.1 6 | -- Dumped by pg_dump version 14.1 7 | 8 | SET statement_timeout = 0; 9 | SET lock_timeout = 0; 10 | SET idle_in_transaction_session_timeout = 0; 11 | SET client_encoding = 'UTF8'; 12 | SET standard_conforming_strings = on; 13 | SELECT pg_catalog.set_config('search_path', '', false); 14 | SET check_function_bodies = false; 15 | SET xmloption = content; 16 | SET client_min_messages = warning; 17 | SET row_security = off; 18 | 19 | -- 20 | -- Name: test; Type: SCHEMA; Schema: -; Owner: test 21 | -- 22 | 23 | CREATE SCHEMA test; 24 | 25 | 26 | ALTER SCHEMA test OWNER TO test; 27 | 28 | SET default_tablespace = ''; 29 | 30 | SET default_table_access_method = heap; 31 | 32 | -- 33 | -- Name: address; Type: TABLE; Schema: test; Owner: test 34 | -- 35 | 36 | CREATE TABLE test.address ( 37 | pk_address_id integer NOT NULL, 38 | street character varying(80), 39 | house_no character varying(10), 40 | city character varying(80), 41 | state_province character varying(80), 42 | postal_code character varying(20), 43 | country character varying(80) 44 | ); 45 | 46 | 47 | ALTER TABLE test.address OWNER TO test; 48 | 49 | -- 50 | -- Name: TABLE address; Type: COMMENT; Schema: test; Owner: test 51 | -- 52 | 53 | COMMENT ON TABLE test.address IS 'Address table. Many persons may have the same address.'; 54 | 55 | 56 | -- 57 | -- Name: COLUMN address.pk_address_id; Type: COMMENT; Schema: test; Owner: test 58 | -- 59 | 60 | COMMENT ON COLUMN test.address.pk_address_id IS 'Primary Key of address'; 61 | 62 | 63 | -- 64 | -- Name: COLUMN address.street; Type: COMMENT; Schema: test; Owner: test 65 | -- 66 | 67 | COMMENT ON COLUMN test.address.street IS 'Street part of an address, if applicable'; 68 | 69 | 70 | -- 71 | -- Name: person; Type: TABLE; Schema: test; Owner: test 72 | -- 73 | 74 | CREATE TABLE test.person ( 75 | pk_person_id integer NOT NULL, 76 | first_name character varying(80) NOT NULL, 77 | last_name character varying(80) NOT NULL, 78 | date_of_birth date NOT NULL 79 | ); 80 | 81 | 82 | ALTER TABLE test.person OWNER TO test; 83 | 84 | -- 85 | -- Name: person_address; Type: TABLE; Schema: test; Owner: test 86 | -- 87 | 88 | CREATE TABLE test.person_address ( 89 | fk_adress_id integer, 90 | fk_person_id integer 91 | ); 92 | 93 | 94 | ALTER TABLE test.person_address OWNER TO test; 95 | 96 | -- 97 | -- Data for Name: address; Type: TABLE DATA; Schema: test; Owner: test 98 | -- 99 | 100 | COPY test.address (pk_address_id, street, house_no, city, state_province, postal_code, country) FROM stdin; 101 | \. 102 | 103 | 104 | -- 105 | -- Data for Name: person; Type: TABLE DATA; Schema: test; Owner: test 106 | -- 107 | 108 | COPY test.person (pk_person_id, first_name, last_name, date_of_birth) FROM stdin; 109 | \. 110 | 111 | 112 | -- 113 | -- Data for Name: person_address; Type: TABLE DATA; Schema: test; Owner: test 114 | -- 115 | 116 | COPY test.person_address (fk_adress_id, fk_person_id) FROM stdin; 117 | \. 118 | 119 | 120 | -- 121 | -- Name: address address_pkey; Type: CONSTRAINT; Schema: test; Owner: test 122 | -- 123 | 124 | ALTER TABLE ONLY test.address 125 | ADD CONSTRAINT address_pkey PRIMARY KEY (pk_address_id); 126 | 127 | 128 | -- 129 | -- Name: person person_pkey; Type: CONSTRAINT; Schema: test; Owner: test 130 | -- 131 | 132 | ALTER TABLE ONLY test.person 133 | ADD CONSTRAINT person_pkey PRIMARY KEY (pk_person_id); 134 | 135 | 136 | -- 137 | -- Name: person_address person_address_fk_adress_id_fkey; Type: FK CONSTRAINT; Schema: test; Owner: test 138 | -- 139 | 140 | ALTER TABLE ONLY test.person_address 141 | ADD CONSTRAINT person_address_fk_adress_id_fkey FOREIGN KEY (fk_adress_id) REFERENCES test.address(pk_address_id); 142 | 143 | 144 | -- 145 | -- Name: person_address person_address_fk_person_id_fkey; Type: FK CONSTRAINT; Schema: test; Owner: test 146 | -- 147 | 148 | ALTER TABLE ONLY test.person_address 149 | ADD CONSTRAINT person_address_fk_person_id_fkey FOREIGN KEY (fk_person_id) REFERENCES test.person(pk_person_id); 150 | 151 | 152 | -- 153 | -- PostgreSQL database dump complete 154 | -- 155 | 156 | -------------------------------------------------------------------------------- /maven-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/** 2 | .vscode/** 3 | target/** 4 | **/**.class 5 | **/**.iml 6 | -------------------------------------------------------------------------------- /maven-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Maven Plugin 2 | 3 | This module contains a maven plugin for DBVisualizer. 4 | 5 | If you want to try out an example, please refer to "plugin-demo" 6 | 7 | ## Usage: 8 | 9 | Example for H2: 10 | 11 | 12 | com.skuehnel 13 | dbvisualizer-maven-plugin 14 | 15 | 1.0.0-SNAPSHOT 16 | 17 | test 18 | test 19 | org.h2.Driver 20 | jdbc:h2:mem:test;MODE=PostgreSQL;INIT=RUNSCRIPT FROM '${baseDirForH2}/src/main/resources/init.sql'; 21 | test-diagram.png 22 | PNG 23 | test-report.html 24 | HTML 25 | test 26 | 27 | PUBLIC 28 | H2 29 | 30 | 31 | 32 | compile 33 | 34 | dbvisualizer 35 | 36 | 37 | 38 | 39 | 40 | Example for PostgreSQL: 41 | 42 | 43 | _replace_with_your_user_ 44 | _replace_with_your_password_ 45 | org.postgresql.Driver 46 | jdbc:postgresql://[::1]:5432/test 47 | test-diagram.png 48 | PNG 49 | test-report.html 50 | HTML 51 | test 52 | -------------------------------------------------------------------------------- /maven-plugin/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.skuehnel 6 | dbvisualizer 7 | 1.0.0-SNAPSHOT 8 | 9 | com.skuehnel 10 | dbvisualizer-maven-plugin 11 | 1.0.0-SNAPSHOT 12 | DB Visualizer Maven Plugin 13 | maven-plugin 14 | Maven plugin to create ER-Diagrams as GraphViz files and textual reports from a DB schema 15 | 16 | 17 | 1.8 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.apache.maven 24 | maven-plugin-api 25 | 3.8.1 26 | provided 27 | 28 | 29 | org.apache.maven.plugin-tools 30 | maven-plugin-annotations 31 | 3.7.0 32 | provided 33 | 34 | 35 | org.apache.maven 36 | maven-project 37 | 2.2.1 38 | provided 39 | 40 | 41 | 42 | com.skuehnel 43 | dbvisualizer-app 44 | ${project.version} 45 | 46 | 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-plugin-plugin 52 | 3.7.0 53 | 54 | 55 | default-descriptor 56 | process-classes 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /maven-plugin/src/main/java/com/skuehnel/dbvisualizer/mavenplugin/DBVisualizerMavenPluginMojo.java: -------------------------------------------------------------------------------- 1 | package com.skuehnel.dbvisualizer.mavenplugin; 2 | 3 | import com.skuehnel.dbvisualizer.DBVisualizer; 4 | import org.apache.maven.plugin.AbstractMojo; 5 | import org.apache.maven.plugin.MojoExecutionException; 6 | import org.apache.maven.plugin.MojoFailureException; 7 | import org.apache.maven.plugins.annotations.*; 8 | import org.apache.maven.project.MavenProject; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | 12 | import java.util.Locale; 13 | import java.util.Objects; 14 | import java.util.Properties; 15 | 16 | @Mojo(name = "dbvisualizer", defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.COMPILE) 17 | public class DBVisualizerMavenPluginMojo extends AbstractMojo { 18 | 19 | private static final Logger LOGGER = LoggerFactory.getLogger(DBVisualizerMavenPluginMojo.class); 20 | 21 | @Parameter(defaultValue = "${project}", readonly = true, required = true) 22 | MavenProject mavenProject; 23 | 24 | @Parameter(property = "user") 25 | String db_user; 26 | 27 | @Parameter(property = "password") 28 | String db_password; 29 | 30 | @Parameter(property = "driver") 31 | String driver; 32 | 33 | @Parameter(property = "jdbc-url") 34 | String jdbcurl; 35 | 36 | @Parameter(property = "report-file") 37 | String reportFile; 38 | 39 | @Parameter(property = "report-format") 40 | String reportFormat; 41 | 42 | @Parameter(property = "diagram-format") 43 | String diagramFormat; 44 | 45 | @Parameter(property = "diagram-file") 46 | String diagramFile; 47 | 48 | @Parameter(property = "schema") 49 | String schema; 50 | 51 | @Parameter(property = "catalog") 52 | String catalog; 53 | 54 | @Parameter(property = "dialect") 55 | String dialect; 56 | 57 | @Parameter(property = "reportMetadata") 58 | boolean reportMetadata = false; 59 | 60 | @Parameter(property = "filter") 61 | String filter; 62 | 63 | @Override 64 | public void execute() throws MojoExecutionException, MojoFailureException { 65 | 66 | DBVisualizer dbVisualizer = DBVisualizer.DBVisualizerBuilder.builder() 67 | .withDatabaseUser(db_user) 68 | .withDatabasePassword(db_password) 69 | .withJdbcUrl(jdbcurl) 70 | .withJdbcDriver(driver) 71 | .withOutputFileName(diagramFile) 72 | .withOutputFormat(diagramFormat) 73 | .withReportFile(reportFile) 74 | .withReportFormat(reportFormat) 75 | .withReportMetadata(reportMetadata) 76 | .withSchema(schema) 77 | .withCatalog(catalog) 78 | .withDBDialect(dialect) 79 | .withFilter(filter) 80 | .build(); 81 | try { 82 | dbVisualizer.execute(); 83 | } catch (Exception e) { 84 | LOGGER.error("Could not execute DBVisualizer Maven Plugin", e); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /plugin-demo/README.md: -------------------------------------------------------------------------------- 1 | # Demos for Maven Plugin 2 | 3 | ## H2 demo 4 | 5 | The H2 in memory database is created when the JDBC connection is established as an in-memory database. 6 | The database structure (and some data) is defined in src/main/resources/init.sql 7 | 8 | The database does just contain three tables: 9 | 10 | * EMPLOYEE 11 | * DEPARTMENT 12 | * EMPLOYEE_DEPARTMENT 13 | 14 | Please remove the comments in the pom.xml to run the demo locally. 15 | Currently the H2 JDBC driver is affected by CVE-2022-45868, so the dependency is also commented out. 16 | To execute the demo, you also have to remove the comments around the dependency, as well. 17 | 18 | ## PostgreSQL Demo 19 | 20 | The pom.xml also contains some settings for a typical PostgreSQL database. 21 | To try this out run the script postgres_demo.sql to create the demo schema: 22 | 23 | pgsql -U -d --password -f src/main/resources/postgresql_demo.sql 24 | 25 | Then remove the comments in the pom.xml and change username, password and other seetings according to your local setup. 26 | 27 | ## MySQL Demo 28 | 29 | The pom.xml also contains some settings for a typical MySQL database where a database (schema) "mysql-test" and one 30 | or more tables which names starts with "employee" exists. Please uncomment and adapt this section according to your 31 | set-up. 32 | 33 | ## Execute maven 34 | 35 | When you have made the changes in the pom.xml just run 36 | 37 | mvn install 38 | 39 | This will exceutue DBVisualizer and create the files as configured. -------------------------------------------------------------------------------- /plugin-demo/pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.skuehnel 6 | dbvisualizer 7 | 1.0.0-SNAPSHOT 8 | 9 | com.skuehnel 10 | dbvisualizer-plugin-demo 11 | DB Visualizer Plugin Demo 12 | 13 | Demo with an in-memory H2 Database. ER-Diagram and HTML-Report are generated by the maven plugin 14 | 15 | 16 | 17 | 11 18 | 11 19 | 20 | 21 | 22 | 23 | 24 | org.codehaus.mojo 25 | build-helper-maven-plugin 26 | 3.2.0 27 | 28 | 29 | regex-property 30 | 31 | regex-property 32 | 33 | 34 | baseDirForH2 35 | \\ 36 | / 37 | ${project.basedir} 38 | false 39 | 40 | 41 | 42 | 43 | 44 | com.skuehnel 45 | dbvisualizer-maven-plugin 46 | 1.0.0-SNAPSHOT 47 | 48 | 49 | 50 | 51 | 63 | 64 | 65 | test 66 | test 67 | org.h2.Driver 68 | jdbc:h2:mem:test;MODE=PostgreSQL;INIT=RUNSCRIPT FROM '${baseDirForH2}/src/main/resources/init.sql'; 69 | test-diagram.png 70 | PNG 71 | test-report.html 72 | HTML 73 | test 74 | PUBLIC 75 | H2 76 | 77 | 78 | 91 | 92 | 93 | 94 | compile 95 | 96 | dbvisualizer 97 | 98 | 99 | 100 | 101 | 102 | org.postgresql 103 | postgresql 104 | 42.7.4 105 | 106 | 107 | mysql 108 | mysql-connector-java 109 | 8.0.33 110 | 111 | 115 | 116 | com.h2database 117 | h2 118 | 2.3.232 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /plugin-demo/src/main/resources/init.sql: -------------------------------------------------------------------------------- 1 | -- DDL 2 | CREATE TABLE DEPARTMENT(PK_DEP_ID INTEGER,NAME VARCHAR2(80),PRIMARY KEY(PK_DEP_ID)); 3 | COMMENT ON TABLE DEPARTMENT IS 'Department of ACME Inc.'; 4 | COMMENT ON COLUMN DEPARTMENT.PK_DEP_ID IS 'Primary key of table DEPARTMENT'; 5 | COMMENT ON COLUMN DEPARTMENT.NAME IS 'Name of the department'; 6 | CREATE TABLE EMPLOYEE(PK_EMP_ID INTEGER,NAME VARCHAR2(80),FIRST_MAME VARCHAR(80),DATE_OF_BIRTH DATE,DATE_OF_HIRE DATE,PRIMARY KEY(PK_EMP_ID)); 7 | COMMENT ON TABLE EMPLOYEE IS 'Employees of ACME Inc.'; 8 | COMMENT ON COLUMN EMPLOYEE.PK_EMP_ID IS 'Primary key of table EMPLOYEE'; 9 | COMMENT ON COLUMN EMPLOYEE.NAME IS 'Family name of the employee'; 10 | COMMENT ON COLUMN EMPLOYEE.FIRST_MAME IS 'First name of the employee'; 11 | COMMENT ON COLUMN EMPLOYEE.DATE_OF_BIRTH IS 'Date of birth of the employee'; 12 | COMMENT ON COLUMN EMPLOYEE.DATE_OF_HIRE IS 'Date, when the employee was hired'; 13 | CREATE TABLE EMPLOYEE_DEPARTMENT( 14 | FK_DEP_ID INTEGER , 15 | FK_EMP_ID INTEGER, 16 | CONSTRAINT FK_DEPARTMENT FOREIGN KEY (FK_DEP_ID) REFERENCES DEPARTMENT(PK_DEP_ID), 17 | CONSTRAINT FK_EMPLOYEE FOREIGN KEY (FK_EMP_ID) REFERENCES EMPLOYEE(PK_EMP_ID)); 18 | 19 | COMMENT ON TABLE EMPLOYEE_DEPARTMENT IS 'Assignment of employees to departments'; 20 | -- DML 21 | INSERT INTO DEPARTMENT(PK_DEP_ID,NAME) VALUES(1,'Research and Development'); 22 | INSERT INTO DEPARTMENT(PK_DEP_ID,NAME) VALUES(2,'Accounting'); 23 | INSERT INTO DEPARTMENT(PK_DEP_ID,NAME) VALUES(3,'Human Resources'); 24 | INSERT INTO DEPARTMENT(PK_DEP_ID,NAME) VALUES(4,'Marketing'); 25 | INSERT INTO EMPLOYEE(PK_EMP_ID,NAME,FIRST_MAME) VALUES(1,'Smith','John'); 26 | INSERT INTO EMPLOYEE(PK_EMP_ID,NAME,FIRST_MAME) VALUES(2,'Miller','Jane'); 27 | INSERT INTO EMPLOYEE(PK_EMP_ID,NAME,FIRST_MAME) VALUES(3,'Black','Arthur'); 28 | INSERT INTO EMPLOYEE(PK_EMP_ID,NAME,FIRST_MAME) VALUES(4,'White','Anne'); 29 | INSERT INTO EMPLOYEE(PK_EMP_ID,NAME,FIRST_MAME) VALUES(5,'Brown','Bernard'); 30 | INSERT INTO EMPLOYEE_DEPARTMENT(FK_DEP_ID,FK_EMP_ID) VALUES(1,1); 31 | INSERT INTO EMPLOYEE_DEPARTMENT(FK_DEP_ID,FK_EMP_ID) VALUES(2,3); 32 | INSERT INTO EMPLOYEE_DEPARTMENT(FK_DEP_ID,FK_EMP_ID) VALUES(3,2); 33 | INSERT INTO EMPLOYEE_DEPARTMENT(FK_DEP_ID,FK_EMP_ID) VALUES(4,4); 34 | INSERT INTO EMPLOYEE_DEPARTMENT(FK_DEP_ID,FK_EMP_ID) VALUES(4,5); 35 | -------------------------------------------------------------------------------- /plugin-demo/src/main/resources/postgresql_demo.sql: -------------------------------------------------------------------------------- 1 | -- DDL (for PostgreSQL) 2 | CREATE TABLE IF NOT EXISTS DEPARTMENT(PK_DEP_ID INTEGER,NAME VARCHAR(80),PRIMARY KEY(PK_DEP_ID)); 3 | COMMENT ON TABLE DEPARTMENT IS 'Department of ACME Inc.'; 4 | COMMENT ON COLUMN DEPARTMENT.PK_DEP_ID IS 'Primary key of table DEPARTMENT'; 5 | COMMENT ON COLUMN DEPARTMENT.NAME IS 'Name of the department'; 6 | CREATE TABLE IF NOT EXISTS EMPLOYEE(PK_EMP_ID INTEGER,NAME VARCHAR(80),FIRST_MAME VARCHAR(80),DATE_OF_BIRTH DATE,DATE_OF_HIRE DATE,PRIMARY KEY(PK_EMP_ID)); 7 | COMMENT ON TABLE EMPLOYEE IS 'Employees of ACME Inc.'; 8 | COMMENT ON COLUMN EMPLOYEE.PK_EMP_ID IS 'Primary key of table EMPLOYEE'; 9 | COMMENT ON COLUMN EMPLOYEE.NAME IS 'Family name of the employee'; 10 | COMMENT ON COLUMN EMPLOYEE.FIRST_MAME IS 'First name of the employee'; 11 | COMMENT ON COLUMN EMPLOYEE.DATE_OF_BIRTH IS 'Date of birth of the employee'; 12 | COMMENT ON COLUMN EMPLOYEE.DATE_OF_HIRE IS 'Date, when the employee was hired'; 13 | CREATE TABLE IF NOT EXISTS EMPLOYEE_DEPARTMENT( 14 | FK_DEP_ID INTEGER , 15 | FK_EMP_ID INTEGER, 16 | CONSTRAINT FK_DEPARTMENT FOREIGN KEY (FK_DEP_ID) REFERENCES DEPARTMENT(PK_DEP_ID), 17 | CONSTRAINT FK_EMPLOYEE FOREIGN KEY (FK_EMP_ID) REFERENCES EMPLOYEE(PK_EMP_ID)); 18 | 19 | COMMENT ON TABLE EMPLOYEE_DEPARTMENT IS 'Assignment of employees to departments'; 20 | 21 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.skuehnel 5 | dbvisualizer 6 | 1.0.0-SNAPSHOT 7 | pom 8 | 9 | app 10 | maven-plugin 11 | 12 | --------------------------------------------------------------------------------