├── .gitignore
├── LICENSE.txt
├── README.md
├── azure-pipelines.yml
├── images
├── cop-file-issues.png
├── sonarqube-issues-in-code.png
├── sqldev-check-result.png
├── sqldev-check.png
└── sqldev-preferences.png
├── install_tvdcc_libs.sh
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── trivadis
│ │ ├── sonar
│ │ └── plugin
│ │ │ ├── GLPValidatorConfig.java
│ │ │ ├── PlsqlCustomPlugin.java
│ │ │ └── TrivadisGuidelines3PlusValidatorConfig.java
│ │ └── tvdcc
│ │ ├── generators
│ │ ├── GLPGenmodel.java
│ │ ├── GenUtil.java
│ │ └── TrivadisGuidelines3PlusGenmodel.java
│ │ └── validators
│ │ ├── GLP.java
│ │ ├── Hint.java
│ │ ├── OverrideTrivadisGuidelines.java
│ │ ├── SQLInjection.java
│ │ ├── TrivadisGuidelines3Plus.java
│ │ └── TrivadisPlsqlNaming.java
└── resources
│ ├── GLP
│ ├── genmodel
│ │ ├── plsqlcop-model.xml
│ │ └── rules.xml
│ └── sample
│ │ ├── guideline_9001.sql
│ │ ├── guideline_9002.sql
│ │ └── guideline_9003.sql
│ └── TrivadisGuidelines3Plus
│ ├── genmodel
│ ├── plsqlcop-model.xml
│ └── rules.xml
│ └── sample
│ ├── guideline_9101.sql
│ ├── guideline_9102.sql
│ ├── guideline_9103.sql
│ ├── guideline_9104.sql
│ ├── guideline_9105.sql
│ ├── guideline_9106.sql
│ ├── guideline_9107.sql
│ ├── guideline_9108.sql
│ ├── guideline_9109.sql
│ ├── guideline_9110.sql
│ ├── guideline_9111.sql
│ ├── guideline_9112.sql
│ ├── guideline_9113.sql
│ ├── guideline_9114.sql
│ ├── guideline_9115.sql
│ ├── guideline_9501.sql
│ ├── guideline_9600.sql
│ ├── guideline_9601.sql
│ ├── guideline_9602.sql
│ ├── guideline_9603.sql
│ ├── guideline_9604.sql
│ └── guideline_9605.sql
└── test
└── java
└── com
└── trivadis
└── tvdcc
└── validators
└── tests
├── AbstractValidatorTest.java
├── GLPTest.java
├── HintTest.java
├── OverrideTrivadisGuidelinesTest.java
├── SQLInjectionTest.java
├── TrivadisGuidelines3PlusTest.java
├── TrivadisPlsqlNamingPropertiesFileTest.java
├── TrivadisPlsqlNamingSystemPropertiesTest.java
└── TrivadisPlsqlNamingTest.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *._trace
3 | *.xtendbin
4 | *.DS_Store
5 | *.log
6 | tvdcc_report.*
7 | code_coverage.html
8 | **/target
9 | **/bin
10 | **/test-output
11 | **/xtend-gen
12 | **/xtext-gen
13 | **/.sonar
14 | **/.project
15 | **/.classpath
16 | **/.settings
17 | **/.scannerwork
18 | **/.idea
19 | **/.vscode
20 |
21 | # Mobile Tools for Java (J2ME)
22 | .mtj.tmp/
23 |
24 | # Package Files #
25 | *.jar
26 | *.war
27 | *.ear
28 |
29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30 | hs_err_pid*
31 |
32 | /.metadata/
33 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
2 | Unported License (the "License"); you may not use this file except
3 | in compliance with the License. You may obtain a copy of the License at
4 |
5 | https://creativecommons.org/licenses/by-nc-nd/3.0/
6 |
7 | Unless required by applicable law or agreed to in writing, software
8 | distributed under the License is distributed on an "AS IS" BASIS,
9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 | See the License for the specific language governing permissions and
11 | limitations under the License.
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # db* CODECOP Validators
2 |
3 | db* CODECOP supports custom validators. A validator must implement the `PLSQLCopValidator` Java interface and has to be a direct or indirect descendant of the `PLSQLValidator` class. Such a class can be used in the command line utility and the SQL Developer extension.
4 |
5 | For SonarQube a `ValidationConfig` is required. A config defines the validator with its rules and quality profile for SonarQube. See [GLPValidatorConfig](src/main/java/com/trivadis/sonar/plugin/GLPValidatorConfig.java). The referenced XML files are generated based on the validator and the optional [sample guidelines](src/main/resources/GLP/sample).
6 |
7 | You may use these validators as is or amend/extend them to suit your needs.
8 |
9 | ## Provided Validators
10 |
11 | This project provides the following four custom validators in the package `com.trivadis.tvdcc.validators`:
12 |
13 | Class | Description
14 | ----- | -----------
15 | TrivadisPlsqlNaming | Checks [Naming Conventions](https://trivadis.github.io/plsql-and-sql-coding-guidelines/v4.4/2-naming-conventions/naming-conventions/#naming-conventions-for-plsql) of the Trivadis PL/SQL & SQL Coding Guidelines
16 | GLP | Checks naming of global and local variables and parameters
17 | SQLInjection | Looks for SQL injection vulnerabilities, e.g. unasserted parameters in dynamic SQL
18 | Hint | Looks for unknown hints and invalid table references
19 | OverrideTrivadisGuidelines | Extends TrivadisGuidelines3 and overrides check for [G-1050](https://trivadis.github.io/plsql-and-sql-coding-guidelines/v4.4/4-language-usage/1-general/g-1050/).
20 | TrivadisGuidelines3Plus | Combines the validators TrivadisPlsqlNaming, SQLInjection and OverrideTrivadisGuidelines.
21 |
22 | ### TrivadisPlsqlNaming
23 |
24 | This validator implements 15 guidelines to cover the chapter [2.2 Naming Conventions](https://trivadis.github.io/plsql-and-sql-coding-guidelines/v4.4/2-naming-conventions/naming-conventions/#naming-conventions-for-plsql) of the Trivadis PL/SQL & SQL Coding Guidelines.
25 |
26 | Guideline | Message
27 | --------- | -----------
28 | G-9101 | Always name global variables to match '^g_.+$'.
29 | G-9102 | Always name local variables to match '^l_.+$'.
30 | G-9103 | Always name cursors to match '^c_.+$'.
31 | G-9104 | Always name records to match '^r_.+$'.
32 | G-9105 | Always name collection types (arrays/tables) to match '^t_.+$'.
33 | G-9106 | Always name objects to match '^o_.+$'.
34 | G-9107 | Always name cursor parameters to match '^p_.+$'.
35 | G-9108 | Always name in parameters to match '^in_.+$'.
36 | G-9109 | Always name out parameters to match '^out_.+$'.
37 | G-9110 | Always name in/out parameters to match '^io_.+$'.
38 | G-9111 | Always name record type definitions to match '^r_.+_type$'.
39 | G-9112 | Always name collection type definitions (arrays/tables) to match '^t_.+_type$'.
40 | G-9113 | Always name exceptions to match '^e_.+$'.
41 | G-9114 | Always name constants to match '^co_.+$'.
42 | G-9115 | Always name subtypes to match '^.+_type$'.
43 |
44 | These regular expressions can be customized by using a `TrivadisPlsqlNaming.properties` file. This file must be placed in the user's home directory (`$HOME` for Linux or macOS and `%HOMEDRIVE%%HOMEPATH%` for Windows). If a property is omitted it will fall back to the default value (see table above). Furthermore, you can use Java system properties to configure the naming conventions, e.g. `-DREGEX_CONSTANT_NAME=^k_.+$`. However, the `TrivadisPlsqlNaming.properties` file overrides system properties that where set when starting the JVM.
45 |
46 | Here's an example of the `TrivadisPlsqlNaming.properties` file content using default values for all properties:
47 |
48 | ```
49 | # Override default for TrivadisPlsqlNaming validator
50 | REGEX_GLOBAL_VARIABLE_NAME = ^g_.+$
51 | REGEX_LOCAL_VARIABLE_NAME = ^l_.+$
52 | REGEX_CURSOR_NAME = ^c_.+$
53 | REGEX_RECORD_NAME = ^r_.+$
54 | REGEX_ARRAY_NAME = ^t_.+$
55 | REGEX_OBJECT_NAME = ^o_.+$
56 | REGEX_CURSOR_PARAMETER_NAME = ^p_.+$
57 | REGEX_IN_PARAMETER_NAME = ^in_.+$
58 | REGEX_OUT_PARAMETER_NAME = ^out_.+$
59 | REGEX_IN_OUT_PARAMETER_NAME = ^io_.+$
60 | REGEX_RECORD_TYPE_NAME = ^r_.+_type$
61 | REGEX_ARRAY_TYPE_NAME = ^t_.+_type$
62 | REGEX_EXCEPTION_NAME = ^e_.+$
63 | REGEX_CONSTANT_NAME = ^co_.+$
64 | REGEX_SUBTYPE_NAME = ^.+_type$
65 | # Override defaults for TrivadisGuidelines3 validator
66 | cop.1050.threshold = 2
67 | cop.2185.threshold = 4
68 | cop.2410.boolean.strings = true,false,t,f,0,1,2,yes,no,y,n,ja,nein,j,si,s,oui,non,o,l_true,l_false,co_true,co_false,co_numeric_true,co_numeric_false
69 | cop.5050.threshold.from = 20000
70 | cop.5050.threshold.to = 20999
71 | cop.7210.threshold = 2000
72 | ```
73 |
74 | If you are using the `TrivadisGuidelines3Plus` validator, the properties for the `TrivadisGuidelines3` validator can also be configured in this properties file.
75 |
76 | ### GLP
77 |
78 | This is a simple validator to check the following naming convention guidelines:
79 |
80 | Guideline | Message
81 | --------- | -----------
82 | G-9001 | Always prefix global variables with 'g_'.
83 | G-9002 | Always prefix local variables with 'l_'.
84 | G-9003 | Always prefix parameters with 'p_'.
85 |
86 | This validator checks just these three guidelines. It does not extend the [Trivadis PL/SQL & SQL Coding Guidelines](https://trivadis.github.io/plsql-and-sql-coding-guidelines/).
87 |
88 | ### SQLInjection
89 |
90 | This validator implements the following guideline:
91 |
92 | Guideline | Message
93 | --------- | -----------
94 | G-9501 | Never use parameter in string expression of dynamic SQL. Use asserted local variable instead.
95 |
96 | It looks for unasserted parameters used in [`EXECUTE IMMEDIATE`](https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/EXECUTE-IMMEDIATE-statement.html#GUID-C3245A95-B85B-4280-A01F-12307B108DC8) statements and [`OPEN FOR`](https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/OPEN-FOR-statement.html#GUID-EB7AF439-FDD3-4461-9E3F-B621E8ABFB96) statements. All parameters used in these statements must be asserted with one of the subprograms provided by [`DBMS_ASSERT`](https://docs.oracle.com/en/database/oracle/oracle-database/19/arpls/DBMS_ASSERT.html#GUID-27B4B484-7CD7-48FE-89A3-B630ADE1CB50).
97 |
98 | See [example](src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9501.sql)
99 |
100 | ### Hint
101 |
102 | This validator implements the following guidelines:
103 |
104 | Guideline | Message
105 | --------- | -----------
106 | G-9600 | Never define more than one comment with hints.
107 | G-9601 | Never use unknown hints.
108 | G-9602 | Always use the alias name instead of the table name.
109 | G-9603 | Never reference an unknown table/alias.
110 | G-9604 | Never use an invalid stats method.
111 | G-9605 | Never use an invalid stats keyword.
112 |
113 | Only the first comment containing hints is considered by the optimizer, therefore all hints violating `G-9600` are treated as ordinary comments by the Oracle Database.
114 |
115 | Using unknown hints might invalidate all subsequent hints. This happens when you use for example `NOLOGGING`. That's expected and not a bug. See MOS note 285285.1 or bug 8432870 for details. So, do not ignore `G-9601` violations.
116 |
117 | There are various hints that reference a table. The validator checks if the reference is valid. If an alias is defined for a table, but the table name is used in the hint then a `G-9602` violation is reported. If the table reference in the hint is neither a table name nor an alias then a `G-9603` violation is thrown. These violations should not be ignored either.
118 |
119 | However, the vadiator ignores the optional query block in the hint and assumes that all table references belong to the current query block. As a result some false positives are possible. Furthermore references to a table in a query block (e.g. `emp@qb1`) are not checked. This might lead to some false negatives.
120 |
121 | The guidelines `G-9604` and `G-9605` check the validity of the `method` and `keyword` in the `table_stats` hint.
122 |
123 | ### OverrideTrivadisGuidelines
124 |
125 | This validator shows how existing guideline checks can be overridden.
126 |
127 | The following guideline is overriden:
128 |
129 | Guideline | Message
130 | --------- | -----------
131 | [G-1050](https://trivadis.github.io/plsql-and-sql-coding-guidelines/v4.4/4-language-usage/1-general/g-1050/) | Avoid using literals in your code.
132 |
133 | Literals as part of a [Logger](https://github.com/OraOpenSource/Logger) package call are not reported (see also [issue 8](https://github.com/Trivadis/plsql-cop-validators/issues/8)).
134 |
135 | ### TrivadisGuidelines3Plus
136 |
137 | This validator combines the validators
138 |
139 | - [TrivadisPlsqlNaming](#trivadisplsqlnaming),
140 | - [SQLInjection](#sqlinjection),
141 | - [Hint](#hint) and
142 | - [OverrideTrivadisGuidelines](#overridetrivadisguidelines)
143 |
144 | This way you can deal with an unbound number of validators without comproming the maintainablity.
145 |
146 | ## Use in db* CODECOP
147 |
148 | 1. Download db* CODECOP Command Line
149 |
150 | Download db* CODECOP Command Line from [here](https://github.com/Trivadis/plsql-cop-cli/releases).
151 |
152 | 2. Install db* CODECOP Command Line
153 |
154 | - Uncompress the distributed db* CODECOP archive file (e.g. tvdcc-4.x.x.zip) into a folder of your choice (hereinafter referred to as `TVDCC_HOME`). I use `$HOME/tvdcc` for `TVDCC_HOME` on my MacBook Pro.
155 |
156 | - For Windows platforms only: Amend the settings for JAVA_HOME in the tvdcc.cmd file to meet your environment settings. Use at least a Java 8 runtime environment (JRE) or development kit (JDK).
157 |
158 | - Include `TVDCC_HOME` in your PATH environment variable for handy interactive usage.
159 |
160 | - Optionally copy your commercial license file into the `TVDCC_HOME` directory. For simplicity name the file tvdcc.lic.
161 |
162 | 3. Download Custom Validators
163 |
164 | Download `sonar-plsql-cop-custom-validators-plugin-4.x.x.jar` from [here](https://github.com/Trivadis/cop-validators/releases).
165 |
166 | 4. Install Custom Validators
167 |
168 | Copy the previously downloaded jar file into the `plugin` folder of your `TVDCC_HOME` folder.
169 |
170 | 5. Run db* CODECOP with a Custom Validator
171 |
172 | Open a terminal window, change to the `TVDCC_HOME` directory and run the following command to all files in `$HOME/github/utPLSQL/source` with the custom validator `com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus`:
173 |
174 | ```
175 | ./tvdcc.sh path=$HOME/github/utPLSQL/source validator=com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus
176 | ```
177 |
178 | The `tvdcc_report.html` file contain the results. Here's an excerpt:
179 |
180 | 
181 |
182 | ## Use in db* CODECOP for SQL Developer
183 |
184 | 1. Install db* CODECOP Command Line
185 |
186 | As explained [above](README.md#use-in-db*-codecop).
187 |
188 | 2. Download db* CODECOP for SQL Developer
189 |
190 | Download db* CODECOP for SQL Developer from [here](https://www.salvis.com/blog/plsql-cop-for-sql-developer/).
191 |
192 | 3. Install db* CODECOP for SQL Developer
193 |
194 | - Start SQL Developer
195 | - Select `Check for Updates…` in the help menu.
196 | - Use the `Install From Local File(s)` option to install the previously downloaded `TVDCC_for_SQLDev-*.zip` file.
197 | - Restart SQL Developer
198 |
199 | 4. Configure Validator
200 |
201 | Configure the validator in SQL Developer as shown in the following screenshot:
202 |
203 | 
204 |
205 | 5. Check Code
206 |
207 | Open the code to be checked in an editor and select `Check` from the context menu.
208 |
209 | 
210 |
211 | The check result is shown by default at the bottom of your SQL Developer workspace.
212 |
213 | 
214 |
215 |
216 | ## Use in db* CODECOP for SonarQube
217 |
218 | 1. Install SonarQube
219 |
220 | [See documentation](https://docs.sonarqube.org/latest/setup/install-server/).
221 |
222 | 2. Install Standalone or Secondary Plugin
223 |
224 | [See documentation](https://github.com/Trivadis/plsql-cop-sonar/tree/main#installation).
225 |
226 | 3. Install Child Plugin (Custom Validator Plugin)
227 |
228 | Download the `sonar-plsql-cop-custom-validators-plugin-x.x.x.jar` from [releases](https://github.com/Trivadis/plsql-cop-validators/releases). Then copy it to the extensions/plugins folder of your [SonarQube](http://docs.sonarqube.org/display/SONAR/Installing+a+Plugin) installation and restart the SonarQube server.
229 |
230 | 4. Configure Validator Config Class
231 |
232 | Login as Administrator in SonarQube. Go to `Administration`. Select `General Settings` from `Configuration` and click on `db* CODECOP`. Type one of the following into the `Validator Config class` field:
233 |
234 | - com.trivadis.sonar.plugin.GLPValidatorConfig
235 | - com.trivadis.sonar.plugin.TrivadisGuidelines3PlusValidatorConfig
236 |
237 | 5. Restart SonarQube
238 |
239 | Select `System` in the `Administration` menu and click on `Restart Server`.
240 |
241 | **Important**: Starting with SonarQube 9.1, rules and quality profiles are cached to improve the startup time (see [SONAR-15237](https://sonarsource.atlassian.net/browse/SONAR-15237)). To apply changes to `Language Key` and `Validator Config class`, the PL/SQL specific plugins must be uninstalled and then reinstalled. Configuration changes are not affected by this process.
242 |
243 | 6. Run Analysis
244 |
245 | Start an analysis from the command line as follows (see [docs](https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/) for more information):
246 |
247 | ```
248 | cd $HOME/github/trivadis/plsql-cop-validators/src/main/resources
249 | sonar-scanner -Dsonar.projectKey="plsql-cop-validators"
250 | ```
251 |
252 | By default the source code in the current directory is analyzed. Here's the result:
253 |
254 | 
255 |
256 | ## How to Build
257 |
258 | 1. Install db* CODECOP Command Line
259 |
260 | As explained [above](README.md#use-in-db*-codecop).
261 |
262 | 2. Install Maven
263 |
264 | [Download](https://maven.apache.org/download.cgi) and install Apache Maven 3.8.6
265 |
266 | 3. Clone the cop-validators repository
267 |
268 | Clone or download this repository.
269 |
270 | 3. Install the required db* CODECOP libraries
271 |
272 | These libraries are not available in public Maven repositories. However, they are part
273 | of the db* CODECOP Command Line installed in step 1. You need to install these libraries
274 | into your local Maven repository.
275 |
276 | Open a terminal window in the cop-validators root folder and run Run the following shell script:
277 |
278 | ./install_tvdcc_libs.sh
279 |
280 | The shell script expects to find the library `tvdcc.jar` in `$HOME/tvdcc`. If it is not there, pass the path to the directory as parameter to this script. For example
281 |
282 | ./install_tvdcc_libs.sh $HOME/tvdcc
283 |
284 | 4. Build validator jar file
285 |
286 | Open a terminal window in the cop-validators root folder and run the Maven build by the following command
287 |
288 | mvn clean package
289 |
290 | ## License
291 |
292 | The db* CODECOP Validators are licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License. You may obtain a copy of the License at https://creativecommons.org/licenses/by-nc-nd/3.0/.
293 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | trigger:
2 | branches:
3 | include:
4 | - main
5 | - feature/*
6 | - bugfix/*
7 | paths:
8 | include:
9 | - src
10 | - pom.xml
11 | - azure-pipelines.yml
12 | exclude:
13 | - README.md
14 |
15 | pool:
16 | vmImage: 'ubuntu-latest'
17 |
18 | variables:
19 | MAVEN_CACHE_FOLDER: $(Pipeline.Workspace)/.m2/repository
20 | MAVEN_OPTS: '-Dmaven.repo.local=$(MAVEN_CACHE_FOLDER)'
21 | Agent.Source.Git.ShallowFetchDepth: 1
22 |
23 | steps:
24 | - task: MavenAuthenticate@0
25 | displayName: 'Maven Authenticate'
26 | inputs:
27 | artifactsFeeds: plsqlcop
28 |
29 | - task: Cache@2
30 | inputs:
31 | key: 'maven | "$(Agent.OS)" | **/pom.xml'
32 | restoreKeys: |
33 | maven | "$(Agent.OS)"
34 | maven
35 | path: $(MAVEN_CACHE_FOLDER)
36 | displayName: Cache Maven local repo
37 |
38 | - task: Maven@3
39 | displayName: 'Maven com.trivadis.tvdcc'
40 | inputs:
41 | mavenPomFile: 'pom.xml'
42 | mavenOptions: '$(MAVEN_OPTS)'
43 | goals: 'clean deploy -U -Pdefault,CI'
44 | publishJUnitResults: true
45 | jdkVersion: 17
46 |
--------------------------------------------------------------------------------
/images/cop-file-issues.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Trivadis/plsql-cop-validators/5521d056b3bfb297f4262bd3dcdef9a5acf68e06/images/cop-file-issues.png
--------------------------------------------------------------------------------
/images/sonarqube-issues-in-code.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Trivadis/plsql-cop-validators/5521d056b3bfb297f4262bd3dcdef9a5acf68e06/images/sonarqube-issues-in-code.png
--------------------------------------------------------------------------------
/images/sqldev-check-result.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Trivadis/plsql-cop-validators/5521d056b3bfb297f4262bd3dcdef9a5acf68e06/images/sqldev-check-result.png
--------------------------------------------------------------------------------
/images/sqldev-check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Trivadis/plsql-cop-validators/5521d056b3bfb297f4262bd3dcdef9a5acf68e06/images/sqldev-check.png
--------------------------------------------------------------------------------
/images/sqldev-preferences.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Trivadis/plsql-cop-validators/5521d056b3bfb297f4262bd3dcdef9a5acf68e06/images/sqldev-preferences.png
--------------------------------------------------------------------------------
/install_tvdcc_libs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # set the directory where libraries of db* CODECOP CLI are stored
4 | if [[ "$1" = "" ]]; then
5 | TVDCC_DIR="$HOME/tvdcc"
6 | else
7 | TVDCC_DIR="$1"
8 | fi
9 |
10 | # check db* CODECOP CLI root directory
11 | if ! test -f "${TVDCC_DIR}/tvdcc.jar"; then
12 | echo "Error: ${TVDCC_DIR} is not a valid path to the root path of db* CODECOP CLI."
13 | echo " Please pass a valid path to this script."
14 | exit 1
15 | fi
16 |
17 | # define versions according usage in pom.xml
18 | TVDCC_VERSION="5.0.1"
19 | PLSQL_VERSION="5.0.1"
20 |
21 | # install JAR files into local Maven repository, these libs are not available in public Maven repositories
22 | mvn install:install-file -Dfile=$TVDCC_DIR/tvdcc.jar -DgeneratePom=true \
23 | -DgroupId=trivadis.tvdcc -DartifactId=tvdcc -Dversion=$TVDCC_VERSION -Dpackaging=jar
24 | mvn install:install-file -Dfile=$TVDCC_DIR/lib/plsql-${PLSQL_VERSION}.jar -DgeneratePom=true \
25 | -DgroupId=trivadis.oracle -DartifactId=plsql -Dversion=$PLSQL_VERSION -Dpackaging=jar
26 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 |
6 | trivadis.tvdcc
7 | sonar-plsql-cop-custom-validators-plugin
8 | 5.0.2-SNAPSHOT
9 | sonar-plugin
10 |
11 | UTF-8
12 | 8
13 | 17
14 | 2.28.0
15 | false
16 | false
17 |
18 |
19 |
20 | default
21 |
22 | true
23 |
24 |
25 |
26 |
27 | org.apache.maven.plugins
28 | maven-compiler-plugin
29 | 3.12.1
30 |
31 |
32 |
33 | ${jdk.version}
34 | ${jdk.test.version}
35 |
36 |
37 |
38 |
39 |
40 |
41 | idea
42 |
43 | false
44 |
45 | idea.maven.embedder.version
46 |
47 |
48 |
49 |
50 |
51 | org.apache.maven.plugins
52 | maven-compiler-plugin
53 | 3.12.1
54 |
55 |
56 |
57 | ${jdk.test.version}
58 | ${jdk.test.version}
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | false
67 |
68 | CI
69 |
70 |
71 | plsqlcop
72 | https://pkgs.dev.azure.com/tvdvsts/2001.5038513/_packaging/plsqlcop/maven/v1
73 |
74 | true
75 |
76 |
77 | true
78 |
79 |
80 |
81 |
82 |
83 | plsqlcop
84 | https://pkgs.dev.azure.com/tvdvsts/2001.5038513/_packaging/plsqlcop/maven/v1
85 |
86 | true
87 |
88 |
89 | true
90 |
91 |
92 |
93 |
94 |
95 | plsqlcop
96 | https://pkgs.dev.azure.com/tvdvsts/2001.5038513/_packaging/plsqlcop/maven/v1
97 |
98 |
99 | plsqlcop
100 | https://pkgs.dev.azure.com/tvdvsts/2001.5038513/_packaging/plsqlcop/maven/v1
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 | trivadis.tvdcc
109 | tvdcc
110 | 5.0.1
111 | provided
112 |
113 |
114 |
115 | trivadis.oracle
116 | plsql
117 | 5.0.1
118 | provided
119 |
120 |
121 |
122 | org.sonarsource.sonarqube
123 | sonar-plugin-api
124 | 7.9
125 | provided
126 |
127 |
128 |
129 |
130 | org.eclipse.xtext
131 | org.eclipse.xtext
132 | ${xtext.version}
133 | provided
134 |
135 |
136 | org.eclipse.xtext
137 | org.eclipse.xtext.testing
138 | ${xtext.version}
139 | test
140 |
141 |
142 | org.eclipse.xtext
143 | org.eclipse.xtext.common.types
144 | ${xtext.version}
145 | test
146 |
147 |
148 | junit
149 | junit
150 | 4.13.2
151 | test
152 |
153 |
154 |
155 |
156 |
157 | ${project.basedir}/src/main/java
158 |
159 |
160 | src/main/resources
161 |
162 | **/*.*
163 |
164 |
165 |
166 |
167 |
168 | org.sonarsource.sonar-packaging-maven-plugin
169 | sonar-packaging-maven-plugin
170 | 1.21.0.505
171 | true
172 |
173 | plsql-cop-custom-validators
174 | com.trivadis.sonar.plugin.PlsqlCustomPlugin
175 | plsqlcop
176 |
177 |
178 |
179 | org.apache.maven.plugins
180 | 3.12.1
181 | maven-compiler-plugin
182 |
183 | ${jdk.version}
184 | ${jdk.version}
185 |
186 | **/*.java
187 |
188 |
189 |
190 |
191 | org.apache.maven.plugins
192 | maven-deploy-plugin
193 | 3.1.1
194 |
195 |
196 | org.codehaus.mojo
197 | exec-maven-plugin
198 | 3.1.1
199 |
200 |
201 |
202 | glp
203 | compile
204 |
205 | java
206 |
207 |
208 | com.trivadis.tvdcc.generators.GLPGenmodel
209 | test
210 | false
211 | ${skip.genmodel}
212 |
213 |
214 |
215 | guidelines3plus
216 | compile
217 |
218 | java
219 |
220 |
221 | com.trivadis.tvdcc.generators.TrivadisGuidelines3PlusGenmodel
222 | test
223 | false
224 | ${skip.genmodel}
225 |
226 |
227 |
228 |
229 |
230 | org.apache.maven.plugins
231 | maven-surefire-plugin
232 | 3.2.5
233 |
234 |
235 | default-test
236 |
237 | test
238 |
239 |
240 | ${skipTests}
241 | 1
242 | true
243 |
244 | **/*.java
245 |
246 |
247 | **/TrivadisPlsqlNamingTest.java
248 | **/TrivadisPlsqlNamingPropertiesFileTest.java
249 | **/TrivadisPlsqlNamingSystemPropertiesTest.java
250 | **/GLPTest.java
251 | **/SQLInjectionTest.java
252 | **/OverrideTrivadisGuidelinesTest.java
253 | **/TrivadisGuidelines3PlusTest.java
254 | **/HintTest.java
255 |
256 |
257 |
258 |
259 | trivadis-plsql-naming-test
260 |
261 | test
262 |
263 |
264 | ${skipTests}
265 | 1
266 | true
267 |
268 | **/TrivadisPlsqlNamingTest.java
269 |
270 |
271 |
272 |
273 | trivadis-plsql-naming-properties-file-test
274 |
275 | test
276 |
277 |
278 | ${skipTests}
279 | 1
280 | true
281 |
282 | **/TrivadisPlsqlNamingPropertiesFileTest.java
283 |
284 |
285 |
286 |
287 | trivadis-plsql-naming-system-properties-test
288 |
289 | test
290 |
291 |
292 | ${skipTests}
293 | 1
294 | true
295 |
296 | **/TrivadisPlsqlNamingSystemPropertiesTest.java
297 |
298 |
299 |
300 |
301 | glp-test
302 |
303 | test
304 |
305 |
306 | ${skipTests}
307 | 1
308 | true
309 |
310 | **/GLPTest.java
311 |
312 |
313 |
314 |
315 | sqlinjection-test
316 |
317 | test
318 |
319 |
320 | ${skipTests}
321 | 1
322 | true
323 |
324 | **/SQLInjectionTest.java
325 |
326 |
327 |
328 |
329 | override-trivadis-guidelines-test
330 |
331 | test
332 |
333 |
334 | ${skipTests}
335 | 1
336 | true
337 |
338 | **/OverrideTrivadisGuidelinesTest.java
339 |
340 |
341 |
342 |
343 | trivadis-guidelines-3plus-test
344 |
345 | test
346 |
347 |
348 | ${skipTests}
349 | 1
350 | true
351 |
352 | **/TrivadisGuidelines3PlusTest.java
353 |
354 |
355 |
356 |
357 | hint-test
358 |
359 | test
360 |
361 |
362 | ${skipTests}
363 | 1
364 | true
365 |
366 | **/HintTest.java
367 |
368 |
369 |
370 |
371 |
372 |
373 |
374 |
375 |
376 |
377 | org.eclipse.m2e
378 | lifecycle-mapping
379 | 1.0.0
380 |
381 |
382 |
383 |
384 |
385 |
386 | org.codehaus.mojo
387 |
388 |
389 | exec-maven-plugin
390 |
391 |
392 | [3.0.0,)
393 |
394 |
395 | java
396 |
397 |
398 |
399 |
400 |
401 |
402 |
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 | db* CODECOP for SonarQube (Child)
412 | Custom validators to analyze PL/SQL and SQL code. Extends db* CODECOP for SonarQube (Standalone/Secondary), db* CODECOP CLI and db* CODECOP for SQL Developer.
413 | https://github.com/Trivadis/plsql-cop-validators
414 | 2017
415 |
416 |
417 | CC BY-NC-ND 3.0
418 | https://creativecommons.org/licenses/by-nc-nd/3.0/
419 | manual
420 |
421 |
422 |
423 | Trivadis - Part of Accenture
424 | https://www.accenture.com/
425 |
426 |
427 |
428 | philipp.salvisberg@accenture.com
429 | Philipp Salvisberg
430 | https://github.com/PhilippSalvisberg/
431 | PhilippSalvisberg
432 |
433 | lead
434 | developer
435 |
436 |
437 |
438 |
439 | scm:git:https://github.com/Trivadis/plsql-cop-validators.git
440 | https://github.com/Trivadis/plsql-cop-validators
441 |
442 |
443 | GitHub
444 | https://github.com/Trivadis/plsql-cop-validators/issues
445 |
446 |
447 |
448 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/sonar/plugin/GLPValidatorConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.sonar.plugin;
18 |
19 | import com.trivadis.tvdcc.validators.GLP;
20 |
21 | public class GLPValidatorConfig implements ValidatorConfig {
22 |
23 | @Override
24 | public String getModelResourcePath() {
25 | return "/GLP/genmodel/plsqlcop-model.xml";
26 | }
27 |
28 | @Override
29 | public String getRulesResourcePath() {
30 | return "/GLP/genmodel/rules.xml";
31 | }
32 |
33 | @Override
34 | public Class getValidatorClass() {
35 | return GLP.class;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/sonar/plugin/PlsqlCustomPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.sonar.plugin;
18 |
19 | import org.sonar.api.Plugin;
20 |
21 | public class PlsqlCustomPlugin implements Plugin {
22 | public PlsqlCustomPlugin() {
23 | }
24 |
25 | @Override
26 | public void define(Context context) {
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/sonar/plugin/TrivadisGuidelines3PlusValidatorConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.sonar.plugin;
18 |
19 | import com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus;
20 |
21 | public class TrivadisGuidelines3PlusValidatorConfig implements ValidatorConfig {
22 |
23 | @Override
24 | public String getModelResourcePath() {
25 | return "/TrivadisGuidelines3Plus/genmodel/plsqlcop-model.xml";
26 | }
27 |
28 | @Override
29 | public String getRulesResourcePath() {
30 | return "/TrivadisGuidelines3Plus/genmodel/rules.xml";
31 | }
32 |
33 | @Override
34 | public Class getValidatorClass() {
35 | return TrivadisGuidelines3Plus.class;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/generators/GLPGenmodel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.tvdcc.generators;
18 |
19 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
20 | import com.trivadis.tvdcc.genmodel.GenRulesXml;
21 | import com.trivadis.tvdcc.genmodel.GenSqaleXml;
22 | import com.trivadis.tvdcc.validators.GLP;
23 |
24 | public class GLPGenmodel {
25 |
26 | public static void genPlsqlcopModelXml() {
27 | GenSqaleXml gen = new GenSqaleXml();
28 | gen.generate("./src/main/resources/GLP");
29 | }
30 |
31 | public static void genRulesXml() {
32 | GenRulesXml gen = new GenRulesXml();
33 | String targetDir = "./src/main/resources/GLP";
34 | gen.generate(targetDir, "./src/main/resources/GLP/sample");
35 | }
36 |
37 | public static void main(String[] args) {
38 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(GLP.class);
39 | genPlsqlcopModelXml();
40 | genRulesXml();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/generators/GenUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.tvdcc.generators;
18 |
19 | import java.io.IOException;
20 | import java.nio.file.FileVisitOption;
21 | import java.nio.file.Files;
22 | import java.nio.file.Path;
23 | import java.nio.file.Paths;
24 | import java.util.List;
25 | import java.util.stream.Collectors;
26 |
27 |
28 | public class GenUtil {
29 | public static String getPath(String dirName) throws IOException {
30 | String ret = null;
31 | List dirs = Files.walk(Paths.get(""), FileVisitOption.FOLLOW_LINKS).filter(f -> f.toFile().getAbsolutePath().contains(dirName.substring(2)))
32 | .collect(Collectors.toList());
33 | if (dirs.size() > 0) {
34 | ret = dirs.get(0).toFile().getAbsolutePath();
35 | }
36 | return ret;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/generators/TrivadisGuidelines3PlusGenmodel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2021 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.trivadis.tvdcc.generators;
18 |
19 | import java.io.File;
20 | import java.io.IOException;
21 | import java.io.InputStream;
22 | import java.net.URISyntaxException;
23 | import java.nio.file.Files;
24 | import java.nio.file.Path;
25 | import java.nio.file.Paths;
26 | import java.nio.file.StandardCopyOption;
27 | import java.util.Enumeration;
28 | import java.util.jar.JarEntry;
29 | import java.util.jar.JarFile;
30 |
31 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
32 | import com.trivadis.tvdcc.genmodel.GenRulesXml;
33 | import com.trivadis.tvdcc.genmodel.GenSqaleXml;
34 | import com.trivadis.tvdcc.validators.TrivadisGuidelines3;
35 | import com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus;
36 |
37 | public class TrivadisGuidelines3PlusGenmodel {
38 |
39 | public static void genPlsqlcopModelXml() {
40 | GenSqaleXml gen = new GenSqaleXml();
41 | gen.generate("./src/main/resources/TrivadisGuidelines3Plus");
42 | }
43 |
44 | public static void copy(String sourceDir, String targetDir) throws IOException {
45 | Files.walk(Paths.get(sourceDir)).forEach(sourceFile -> {
46 | Path targetFile = Paths.get(targetDir, sourceFile.toString().substring(sourceDir.length()));
47 | try {
48 | if (sourceFile.toFile().isFile()) {
49 | Files.copy(sourceFile, targetFile, StandardCopyOption.REPLACE_EXISTING);
50 | }
51 | } catch (IOException e) {
52 | throw new RuntimeException(e);
53 | }
54 | });
55 | }
56 |
57 | public static void copyGuidelinesFromJar(String targetDir) throws IOException, URISyntaxException {
58 | File tvdccJarFile = new File(
59 | TrivadisGuidelines3.class.getProtectionDomain().getCodeSource().getLocation().toURI());
60 | JarFile jarFile = new JarFile(tvdccJarFile);
61 | Enumeration entries = jarFile.entries();
62 | while (entries.hasMoreElements()) {
63 | JarEntry entry = entries.nextElement();
64 | if (!entry.isDirectory() && entry.getName().startsWith("guidelines/")) {
65 | InputStream entryInputStream = jarFile.getInputStream(entry);
66 | Path targetFile = Paths.get(targetDir, entry.getName().substring(10));
67 | Files.copy(entryInputStream, targetFile, StandardCopyOption.REPLACE_EXISTING);
68 | }
69 | }
70 | jarFile.close();
71 | }
72 |
73 | public static void genRulesXml() throws URISyntaxException, IOException {
74 | GenRulesXml gen = new GenRulesXml();
75 | String tempDir = Files.createTempDirectory("genmodel_").toString();
76 | copyGuidelinesFromJar(tempDir);
77 | copy("./src/main/resources/TrivadisGuidelines3Plus/sample", tempDir);
78 | gen.generate("./src/main/resources/TrivadisGuidelines3Plus", tempDir.toString());
79 | }
80 |
81 | public static void main(String[] args) throws URISyntaxException, IOException {
82 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(TrivadisGuidelines3Plus.class);
83 | genPlsqlcopModelXml();
84 | genRulesXml();
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/validators/GLP.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators;
17 |
18 | import com.trivadis.oracle.plsql.plsql.CreatePackage;
19 | import com.trivadis.oracle.plsql.plsql.CreatePackageBody;
20 | import com.trivadis.oracle.plsql.plsql.ParameterDeclaration;
21 | import com.trivadis.oracle.plsql.plsql.VariableDeclaration;
22 | import com.trivadis.oracle.plsql.validation.PLSQLCopGuideline;
23 | import com.trivadis.oracle.plsql.validation.PLSQLCopValidator;
24 | import com.trivadis.oracle.plsql.validation.PLSQLValidator;
25 | import com.trivadis.oracle.plsql.validation.Remediation;
26 | import java.util.HashMap;
27 | import java.util.List;
28 | import org.eclipse.emf.ecore.EObject;
29 | import org.eclipse.emf.ecore.EPackage;
30 | import org.eclipse.xtext.validation.Check;
31 | import org.eclipse.xtext.validation.EValidatorRegistrar;
32 |
33 | public class GLP extends PLSQLValidator implements PLSQLCopValidator {
34 | private HashMap guidelines;
35 |
36 | // must be overridden to avoid duplicate issues when used via ComposedChecks
37 | @Override
38 | public void register(EValidatorRegistrar registrar) {
39 | final List ePackages = getEPackages();
40 | if (registrar.getRegistry().get(ePackages.get(0)) == null) {
41 | // standalone validator, default registration required
42 | super.register(registrar);
43 | }
44 | }
45 |
46 | @Override
47 | public HashMap getGuidelines() {
48 | if (guidelines == null) {
49 | guidelines = new HashMap<>();
50 | // register parent guidelines
51 | for (final Integer k : super.getGuidelines().keySet()) {
52 | guidelines.put(k, super.getGuidelines().get(k));
53 | }
54 | // register guidelines
55 | guidelines.put(9001, new PLSQLCopGuideline(9001, "Always prefix global variables with 'g_'.", MINOR,
56 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
57 | guidelines.put(9002, new PLSQLCopGuideline(9002, "Always prefix local variables with 'l_'.", MINOR,
58 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
59 | guidelines.put(9003, new PLSQLCopGuideline(9003, "Always prefix parameters with 'p_'.", MINOR,
60 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
61 | }
62 | return guidelines;
63 | }
64 |
65 | @Check
66 | public void checkVariableName(VariableDeclaration v) {
67 | final EObject parent = v.eContainer().eContainer();
68 | final String name = v.getVariable().getValue().toLowerCase();
69 | if (parent instanceof CreatePackage || parent instanceof CreatePackageBody) {
70 | if (!name.startsWith("g_")) {
71 | warning(9001, v.getVariable(), v);
72 | }
73 | } else {
74 | if (!name.startsWith("l_")) {
75 | warning(9002, v.getVariable(), v);
76 | }
77 | }
78 | }
79 |
80 | @Check
81 | public void checkParameterName(ParameterDeclaration p) {
82 | if (!p.getParameter().getValue().toLowerCase().startsWith("p_")) {
83 | warning(9003, p.getParameter(), p);
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/validators/OverrideTrivadisGuidelines.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators;
17 |
18 | import java.util.ArrayList;
19 | import java.util.HashMap;
20 | import java.util.List;
21 |
22 | import org.eclipse.emf.ecore.EObject;
23 | import org.eclipse.emf.ecore.EPackage;
24 | import org.eclipse.xtext.EcoreUtil2;
25 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
26 | import org.eclipse.xtext.validation.Check;
27 | import org.eclipse.xtext.validation.EValidatorRegistrar;
28 |
29 | import com.trivadis.oracle.plsql.plsql.BinaryCompoundExpressionLevel6;
30 | import com.trivadis.oracle.plsql.plsql.BinaryCompoundExpressionLevel7;
31 | import com.trivadis.oracle.plsql.plsql.CollectionTypeDefinition;
32 | import com.trivadis.oracle.plsql.plsql.ConstantDeclaration;
33 | import com.trivadis.oracle.plsql.plsql.PLSQLFile;
34 | import com.trivadis.oracle.plsql.plsql.SimpleExpressionNameValue;
35 | import com.trivadis.oracle.plsql.plsql.SimpleExpressionNumberValue;
36 | import com.trivadis.oracle.plsql.plsql.SimpleExpressionStringValue;
37 | import com.trivadis.oracle.plsql.plsql.UserDefinedType;
38 | import com.trivadis.oracle.plsql.validation.PLSQLCopValidator;
39 |
40 | public class OverrideTrivadisGuidelines extends TrivadisGuidelines3 implements PLSQLCopValidator {
41 |
42 | // must be overridden to avoid duplicate issues when used via ComposedChecks
43 | @Override
44 | public void register(EValidatorRegistrar registrar) {
45 | List ePackages = getEPackages();
46 | if (registrar.getRegistry().get(ePackages.get(0)) == null) {
47 | // standalone validator, default registration required
48 | super.register(registrar);
49 | }
50 | }
51 |
52 | public boolean isConstantDeclaration(
53 |
54 | final EObject obj) {
55 | ConstantDeclaration constantDeclaration = EcoreUtil2.getContainerOfType(obj, ConstantDeclaration.class);
56 | return (constantDeclaration != null);
57 | }
58 |
59 | public boolean isLoggerCall(EObject obj) {
60 | if (obj == null) {
61 | return false;
62 | } else {
63 | BinaryCompoundExpressionLevel7 func = EcoreUtil2.getContainerOfType(obj,
64 | BinaryCompoundExpressionLevel7.class);
65 | if (func == null) {
66 | return false;
67 | } else {
68 | if (func.getLeft() instanceof SimpleExpressionNameValue) {
69 | if (func.eContainer() instanceof BinaryCompoundExpressionLevel6) {
70 | BinaryCompoundExpressionLevel6 pkg = (BinaryCompoundExpressionLevel6) func.eContainer();
71 | if (pkg.getBinaryOperator().equals(".")) {
72 | if (pkg.getLeft() instanceof SimpleExpressionNameValue) {
73 | SimpleExpressionNameValue pkgName = (SimpleExpressionNameValue) pkg.getLeft();
74 | if (pkgName.getValue().equalsIgnoreCase("logger")) {
75 | return true;
76 | }
77 | }
78 | }
79 | }
80 | }
81 | return isLoggerCall(func.eContainer());
82 | }
83 | }
84 | }
85 |
86 | /*
87 | * Override G-1050: Avoid using literals in your code. (guidelines version 3.x)
88 | * Override G-05: Avoid using literals in your code. (guidelines version 2.x)
89 | * re-implement existing functionality while ignoring logger calls
90 | * "&& !isLoggerCall(obj)" is the only addition to the original code
91 | */
92 | @Check
93 | @Override
94 | public void checkGuideline5(PLSQLFile file) {
95 | HashMap map = new HashMap<>();
96 | int threshold = Integer.parseInt(System.getProperty(COP_1050_THRESHOLD, "2"));
97 | List warnings = new ArrayList<>();
98 | List numbers = EcoreUtil2.getAllContentsOfType(file,
99 | SimpleExpressionNumberValue.class);
100 | for (SimpleExpressionNumberValue literal : numbers) {
101 | ConstantDeclaration declartion = EcoreUtil2.getContainerOfType(literal, ConstantDeclaration.class);
102 | UserDefinedType udf = EcoreUtil2.getContainerOfType(literal, UserDefinedType.class);
103 | CollectionTypeDefinition collDef = EcoreUtil2.getContainerOfType(literal, CollectionTypeDefinition.class);
104 | if (declartion == null && udf == null && collDef == null && !literal.getValue().replace(".", "").equals("0")
105 | && !literal.getValue().replace(".", "").equals("1")) {
106 | updateLiteralMap(literal, map, threshold);
107 | warnings.add(literal);
108 | }
109 | }
110 | List strings = EcoreUtil2.getAllContentsOfType(file,
111 | SimpleExpressionStringValue.class);
112 | for (SimpleExpressionStringValue literal : strings) {
113 | ConstantDeclaration declartion = EcoreUtil2.getContainerOfType(literal, ConstantDeclaration.class);
114 | if (declartion == null) {
115 | UserDefinedType udf = EcoreUtil2.getContainerOfType(literal, UserDefinedType.class);
116 | if (udf == null) {
117 | updateLiteralMap(literal, map, threshold);
118 | warnings.add(literal);
119 | }
120 | }
121 | }
122 | for (EObject obj : warnings) {
123 | if (!withinThreshold(obj, map, threshold) && !isLoggerCall(obj)) {
124 | warning(getGuidelineMsg(5), obj, null, getGuidelineId(5), serialize(NodeModelUtils.getNode(obj)));
125 | }
126 | }
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/validators/SQLInjection.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators;
17 |
18 | import com.trivadis.oracle.plsql.plsql.BinaryCompoundExpressionLevel6;
19 | import com.trivadis.oracle.plsql.plsql.BinaryCompoundExpressionLevel7;
20 | import com.trivadis.oracle.plsql.plsql.Body;
21 | import com.trivadis.oracle.plsql.plsql.Condition;
22 | import com.trivadis.oracle.plsql.plsql.ConstantDeclaration;
23 | import com.trivadis.oracle.plsql.plsql.ConstructorDeclaration;
24 | import com.trivadis.oracle.plsql.plsql.CreateFunction;
25 | import com.trivadis.oracle.plsql.plsql.CreateProcedure;
26 | import com.trivadis.oracle.plsql.plsql.DeclareSection;
27 | import com.trivadis.oracle.plsql.plsql.ElementType;
28 | import com.trivadis.oracle.plsql.plsql.ExecuteImmediateStatement;
29 | import com.trivadis.oracle.plsql.plsql.Expression;
30 | import com.trivadis.oracle.plsql.plsql.FuncDeclInType;
31 | import com.trivadis.oracle.plsql.plsql.FunctionDefinition;
32 | import com.trivadis.oracle.plsql.plsql.FunctionOrParenthesisParameter;
33 | import com.trivadis.oracle.plsql.plsql.OpenForStatement;
34 | import com.trivadis.oracle.plsql.plsql.ParameterDeclaration;
35 | import com.trivadis.oracle.plsql.plsql.PlsqlBlock;
36 | import com.trivadis.oracle.plsql.plsql.ProcDeclInType;
37 | import com.trivadis.oracle.plsql.plsql.ProcedureCallOrAssignmentStatement;
38 | import com.trivadis.oracle.plsql.plsql.ProcedureDefinition;
39 | import com.trivadis.oracle.plsql.plsql.QualifiedSqlNameExpression;
40 | import com.trivadis.oracle.plsql.plsql.SimpleExpressionNameValue;
41 | import com.trivadis.oracle.plsql.plsql.UserDefinedType;
42 | import com.trivadis.oracle.plsql.plsql.VariableDeclaration;
43 | import com.trivadis.oracle.plsql.validation.PLSQLCopGuideline;
44 | import com.trivadis.oracle.plsql.validation.PLSQLCopValidator;
45 | import com.trivadis.oracle.plsql.validation.PLSQLValidator;
46 | import com.trivadis.oracle.plsql.validation.Remediation;
47 |
48 | import java.util.*;
49 | import java.util.stream.Collectors;
50 |
51 | import org.eclipse.emf.ecore.EObject;
52 | import org.eclipse.emf.ecore.EPackage;
53 | import org.eclipse.xtext.EcoreUtil2;
54 | import org.eclipse.xtext.nodemodel.ICompositeNode;
55 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
56 | import org.eclipse.xtext.validation.Check;
57 | import org.eclipse.xtext.validation.EValidatorRegistrar;
58 | import org.eclipse.xtext.xbase.lib.CollectionLiterals;
59 |
60 | public class SQLInjection extends PLSQLValidator implements PLSQLCopValidator {
61 | private HashMap guidelines;
62 | private final List ASSERT_PACKAGES = Collections
63 | .unmodifiableList(CollectionLiterals.newArrayList("dbms_assert", "ut_utils"));
64 |
65 | // must be overridden to avoid duplicate issues when used via ComposedChecks
66 | @Override
67 | public void register(EValidatorRegistrar registrar) {
68 | final List ePackages = getEPackages();
69 | if (registrar.getRegistry().get(ePackages.get(0)) == null) {
70 | // standalone validator, default registration required
71 | super.register(registrar);
72 | }
73 | }
74 |
75 | @Override
76 | public HashMap getGuidelines() {
77 | if (guidelines == null) {
78 | guidelines = new HashMap<>();
79 | guidelines.put(9501, new PLSQLCopGuideline(9501,
80 | "Never use parameter in string expression of dynamic SQL. Use asserted local variable instead.",
81 | BLOCKER, SECURITY_FEATURES, Remediation.createConstantPerIssue(5)));
82 | }
83 | return guidelines;
84 | }
85 |
86 | public boolean isStringParameter(ParameterDeclaration param) {
87 | ElementType etype = param.getType();
88 | if (etype instanceof UserDefinedType) {
89 | QualifiedSqlNameExpression udf = ((UserDefinedType) etype).getUserDefinedType();
90 | ICompositeNode node = NodeModelUtils.getNode(udf);
91 | String nodeText = node.getText();
92 | return nodeText.toLowerCase().contains("char");
93 | }
94 | return false;
95 | }
96 |
97 | public boolean isParameter(CreateProcedure proc, SimpleExpressionNameValue n) {
98 | for (final ParameterDeclaration p : proc.getParams()) {
99 | if (p.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
100 | return isStringParameter(p);
101 | }
102 | }
103 | return false;
104 | }
105 |
106 | public boolean isParameter(CreateFunction func, SimpleExpressionNameValue n) {
107 | for (final ParameterDeclaration f : func.getParams()) {
108 | if (f.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
109 | return isStringParameter(f);
110 | }
111 | }
112 | return false;
113 | }
114 |
115 | public boolean isParameter(ProcedureDefinition proc, SimpleExpressionNameValue n) {
116 | for (final ParameterDeclaration p : proc.getHeading().getParams()) {
117 | if (p.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
118 | return isStringParameter(p);
119 | }
120 | }
121 | return false;
122 | }
123 |
124 | public boolean isParameter(FunctionDefinition func, SimpleExpressionNameValue n) {
125 | for (final ParameterDeclaration f : func.getHeading().getParams()) {
126 | if (f.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
127 | return isStringParameter(f);
128 | }
129 | }
130 | return false;
131 | }
132 |
133 | public boolean isParameter(ProcDeclInType proc, SimpleExpressionNameValue n) {
134 | for (final ParameterDeclaration p : proc.getParams()) {
135 | if (p.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
136 | return isStringParameter(p);
137 | }
138 | }
139 | return false;
140 | }
141 |
142 | public boolean isParameter(FuncDeclInType func, SimpleExpressionNameValue n) {
143 | for (final ParameterDeclaration f : func.getParams()) {
144 | if (f.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
145 | return isStringParameter(f);
146 | }
147 | }
148 | return false;
149 | }
150 |
151 | public boolean isParameter(ConstructorDeclaration func, SimpleExpressionNameValue n) {
152 | for (final ParameterDeclaration f : func.getParams()) {
153 | if (f.getParameter().getValue().equalsIgnoreCase(n.getValue())) {
154 | return isStringParameter(f);
155 | }
156 | }
157 | return false;
158 | }
159 |
160 | public boolean isParameter(SimpleExpressionNameValue n) {
161 | final CreateProcedure parentProcedure = EcoreUtil2.getContainerOfType(n, CreateProcedure.class);
162 | if (parentProcedure != null) {
163 | return isParameter(parentProcedure, n);
164 | } else {
165 | final CreateFunction parentFunction = EcoreUtil2.getContainerOfType(n, CreateFunction.class);
166 | if (parentFunction != null) {
167 | return isParameter(parentFunction, n);
168 | } else {
169 | final ProcedureDefinition parentPackageProcedure = EcoreUtil2.getContainerOfType(n,
170 | ProcedureDefinition.class);
171 | if (parentPackageProcedure != null) {
172 | return isParameter(parentPackageProcedure, n);
173 | } else {
174 | final FunctionDefinition parentPackageFunction = EcoreUtil2.getContainerOfType(n,
175 | FunctionDefinition.class);
176 | if (parentPackageFunction != null) {
177 | return isParameter(parentPackageFunction, n);
178 | } else {
179 | final ProcDeclInType parentTypeProcedure = EcoreUtil2.getContainerOfType(n,
180 | ProcDeclInType.class);
181 | if (parentTypeProcedure != null) {
182 | return isParameter(parentTypeProcedure, n);
183 | } else {
184 | final FuncDeclInType parentTypeFunction = EcoreUtil2.getContainerOfType(n,
185 | FuncDeclInType.class);
186 | if (parentTypeFunction != null) {
187 | return isParameter(parentTypeFunction, n);
188 | } else {
189 | final ConstructorDeclaration parentTypeConstructor = EcoreUtil2.getContainerOfType(n,
190 | ConstructorDeclaration.class);
191 | if (parentTypeConstructor != null) {
192 | return isParameter(parentTypeConstructor, n);
193 | }
194 | }
195 | }
196 | }
197 | }
198 | }
199 | }
200 | return false;
201 | }
202 |
203 | public String getQualifiedFunctionName(EObject obj) {
204 | final BinaryCompoundExpressionLevel7 expr7 = EcoreUtil2.getContainerOfType(obj,
205 | BinaryCompoundExpressionLevel7.class);
206 | if (expr7 != null) {
207 | final Expression left = expr7.getLeft();
208 | if (left instanceof SimpleExpressionNameValue) {
209 | final String functionName = ((SimpleExpressionNameValue) left).getValue();
210 | final BinaryCompoundExpressionLevel6 parent = EcoreUtil2.getContainerOfType(expr7,
211 | BinaryCompoundExpressionLevel6.class);
212 | if (parent != null) {
213 | final Expression parentLeft = parent.getLeft();
214 | if (parentLeft instanceof BinaryCompoundExpressionLevel6) {
215 | final Expression parentLeftLeft = ((BinaryCompoundExpressionLevel6) parentLeft).getLeft();
216 | if (parentLeftLeft instanceof SimpleExpressionNameValue) {
217 | final String schemaName = ((SimpleExpressionNameValue) parentLeftLeft).getValue();
218 | final Expression parentLeftRight = ((BinaryCompoundExpressionLevel6) parentLeft).getRight();
219 | if (parentLeftRight instanceof SimpleExpressionNameValue) {
220 | final String packageName = ((SimpleExpressionNameValue) parentLeftRight).getValue();
221 | return schemaName + "." + packageName + "." + functionName;
222 | }
223 | }
224 | } else if (parentLeft instanceof SimpleExpressionNameValue) {
225 | final String packageName = ((SimpleExpressionNameValue) parentLeft).getValue();
226 | return packageName + "." + functionName;
227 | }
228 | }
229 | }
230 | }
231 | return "";
232 | }
233 |
234 | public boolean contains(EObject obj, final String name) {
235 | final List names = EcoreUtil2.getAllContentsOfType(obj,
236 | SimpleExpressionNameValue.class);
237 | for (final SimpleExpressionNameValue n : names) {
238 | if (n.getValue().equalsIgnoreCase(name)) {
239 | return true;
240 | }
241 | }
242 | return false;
243 | }
244 |
245 | public ArrayList getItemsWithDefaults(SimpleExpressionNameValue n) {
246 | Body body = getBody(n);
247 | DeclareSection decl;
248 | if (body == null) {
249 | decl = EcoreUtil2.getContainerOfType(n, DeclareSection.class);
250 | } else {
251 | decl = getDeclareSection(body);
252 | }
253 | final ArrayList items = new ArrayList<>();
254 | final List variables = EcoreUtil2.getAllContentsOfType(decl, VariableDeclaration.class);
255 | for (final VariableDeclaration v : variables) {
256 | if (v.getDefault() != null) {
257 | if (contains(v.getDefault(), n.getValue())) {
258 | items.add(v.getVariable());
259 | }
260 | }
261 | }
262 | final List constants = EcoreUtil2.getAllContentsOfType(decl, ConstantDeclaration.class);
263 | for (final ConstantDeclaration c : constants) {
264 | if (c.getDefault() != null) {
265 | if (contains(c.getDefault(), n.getValue())) {
266 | items.add(c.getConstant());
267 | }
268 | }
269 | }
270 | if (body != null) {
271 | final ArrayList bodyItems = new ArrayList<>();
272 | final List names = EcoreUtil2.getAllContentsOfType(body,
273 | SimpleExpressionNameValue.class);
274 | for (final SimpleExpressionNameValue name : names) {
275 | for (final SimpleExpressionNameValue item : items) {
276 | if (name.getValue().equalsIgnoreCase(item.getValue())) {
277 | bodyItems.add(name);
278 | }
279 | }
280 | }
281 | items.addAll(bodyItems);
282 | }
283 | return items;
284 | }
285 |
286 | public boolean isAsserted(SimpleExpressionNameValue n) {
287 | EObject obj = EcoreUtil2.getContainerOfType(n, Body.class);
288 | if (obj == null) {
289 | obj = EcoreUtil2.getContainerOfType(n, DeclareSection.class);
290 | }
291 | final Iterable usages = EcoreUtil2
292 | .getAllContentsOfType(obj, SimpleExpressionNameValue.class).stream()
293 | .filter(it -> it.getValue().equalsIgnoreCase(n.getValue())).collect(Collectors.toList());
294 | for (final SimpleExpressionNameValue usage : usages) {
295 | final String name = getQualifiedFunctionName(usage);
296 | for (final String assertPackage : ASSERT_PACKAGES) {
297 | if (name.toLowerCase().contains(assertPackage + ".")) {
298 | return true;
299 | }
300 | }
301 | }
302 | return false;
303 | }
304 |
305 | public boolean isAssertedInParameterOrConstantsOrVariables(SimpleExpressionNameValue n) {
306 | // check parameter fist
307 | if (isAsserted(n)) {
308 | return true;
309 | }
310 | // check constants and variables with an assignment of the parameter
311 | for (final SimpleExpressionNameValue item : getItemsWithDefaults(n)) {
312 | if (isAsserted(item)) {
313 | return true;
314 | }
315 | }
316 | return false;
317 | }
318 |
319 | public boolean isParameterName(SimpleExpressionNameValue n) {
320 | if (n.eContainer() instanceof FunctionOrParenthesisParameter) {
321 | final FunctionOrParenthesisParameter param = (FunctionOrParenthesisParameter) n.eContainer();
322 | return param.getParameterName() == n;
323 | }
324 | return false;
325 | }
326 |
327 | public List getRelevantSimpleExpressionNameValues(EObject obj) {
328 | return EcoreUtil2.getAllContentsOfType(obj, SimpleExpressionNameValue.class).stream()
329 | .filter(it -> it != null && !isParameterName(it)).collect(Collectors.toList());
330 | }
331 |
332 | public void check(SimpleExpressionNameValue n, HashMap expressions) {
333 | if (!isParameterName(n)) {
334 | if (isParameter(n)) {
335 | if (!isAssertedInParameterOrConstantsOrVariables(n)) {
336 | warning(9501, n, n);
337 | return;
338 | }
339 | }
340 | final HashMap recursiveExpr = getSimpleExpressinNamesFromAssignments(n);
341 | final HashMap newExpressions = new HashMap<>();
342 | newExpressions.putAll(expressions);
343 | newExpressions.putAll(recursiveExpr);
344 | for (final String key : recursiveExpr.keySet()) {
345 | if (expressions.get(key) == null) {
346 | check(recursiveExpr.get(key), newExpressions);
347 | }
348 | }
349 | }
350 | }
351 |
352 | public DeclareSection getDeclareSection(Body body) {
353 | final EObject parent = body.eContainer();
354 | DeclareSection declareSection;
355 | if (parent instanceof CreateFunction) {
356 | declareSection = ((CreateFunction) parent).getDeclareSection();
357 | } else if (parent instanceof CreateProcedure) {
358 | declareSection = ((CreateProcedure) parent).getDeclareSection();
359 | } else if (parent instanceof FuncDeclInType) {
360 | declareSection = ((FuncDeclInType) parent).getDeclareSection();
361 | } else if (parent instanceof ProcDeclInType) {
362 | declareSection = ((ProcDeclInType) parent).getDeclareSection();
363 | } else if (parent instanceof ConstructorDeclaration) {
364 | declareSection = ((ConstructorDeclaration) parent).getDeclareSection();
365 | } else if (parent instanceof PlsqlBlock) {
366 | declareSection = ((PlsqlBlock) parent).getDeclareSection();
367 | } else if (parent instanceof FunctionDefinition) {
368 | declareSection = ((FunctionDefinition) parent).getDeclareSection();
369 | } else if (parent instanceof ProcedureDefinition) {
370 | declareSection = ((ProcedureDefinition) parent).getDeclareSection();
371 | } else {
372 | declareSection = null;
373 | }
374 |
375 | return declareSection;
376 | }
377 |
378 | public Body getBody(EObject obj) {
379 | final EObject parent = obj.eContainer();
380 | Body body;
381 | if (parent instanceof CreateFunction) {
382 | body = ((CreateFunction) parent).getBody();
383 | } else if (parent instanceof CreateProcedure) {
384 | body = ((CreateProcedure) parent).getBody();
385 | } else if (parent instanceof FuncDeclInType) {
386 | body = ((FuncDeclInType) parent).getBody();
387 | } else if (parent instanceof ProcDeclInType) {
388 | body = ((ProcDeclInType) parent).getBody();
389 | } else if (parent instanceof ConstructorDeclaration) {
390 | body = ((ConstructorDeclaration) parent).getBody();
391 | } else if (parent instanceof PlsqlBlock) {
392 | body = ((PlsqlBlock) parent).getBody();
393 | } else if (parent instanceof FunctionDefinition) {
394 | body = ((FunctionDefinition) parent).getBody();
395 | } else if (parent instanceof ProcedureDefinition) {
396 | body = ((ProcedureDefinition) parent).getBody();
397 | } else if (parent == null) {
398 | body = null;
399 | } else {
400 | body = getBody(parent);
401 | }
402 | return body;
403 | }
404 |
405 | public HashMap getSimpleExpressinNamesFromAssignments(
406 | final SimpleExpressionNameValue n) {
407 | final HashMap expressions = new HashMap<>();
408 | final Body body = EcoreUtil2.getContainerOfType(n, Body.class);
409 | List assignments = EcoreUtil2
410 | .getAllContentsOfType(body, ProcedureCallOrAssignmentStatement.class).stream()
411 | .filter(it -> it.getAssignment() != null).collect(Collectors.toList());
412 | for (final ProcedureCallOrAssignmentStatement assignment : assignments) {
413 | Expression varName = null;
414 | if (assignment.getProcedureOrTarget() != null) {
415 | varName = assignment.getProcedureOrTarget().getObject();
416 | }
417 | if (varName instanceof SimpleExpressionNameValue) {
418 | if (((SimpleExpressionNameValue) varName).getValue().equalsIgnoreCase(n.getValue())) {
419 | Condition a = assignment.getAssignment();
420 | if (a instanceof SimpleExpressionNameValue) {
421 | expressions.put(((SimpleExpressionNameValue) a).getValue().toLowerCase(),
422 | (SimpleExpressionNameValue) a);
423 | } else {
424 | Condition c;
425 | c = assignment.getAssignment();
426 | for (final SimpleExpressionNameValue name : getRelevantSimpleExpressionNameValues(c)) {
427 | expressions.put(name.getValue().toLowerCase(), name);
428 | }
429 | }
430 | }
431 | }
432 | }
433 | final DeclareSection declareSection = getDeclareSection(body);
434 | if (declareSection != null) {
435 | final Optional variable = EcoreUtil2
436 | .getAllContentsOfType(declareSection, VariableDeclaration.class).stream()
437 | .filter(it -> it.getVariable().getValue().equalsIgnoreCase(n.getValue()) && it.getDefault() != null)
438 | .findFirst();
439 | if (variable.isPresent()) {
440 | Iterable _relevantSimplExpressionNameValues = getRelevantSimpleExpressionNameValues(
441 | variable.get().getDefault());
442 | for (final SimpleExpressionNameValue name : _relevantSimplExpressionNameValues) {
443 | expressions.put(name.getValue().toLowerCase(), name);
444 | }
445 | } else {
446 | final Optional constant = EcoreUtil2
447 | .getAllContentsOfType(declareSection, ConstantDeclaration.class).stream()
448 | .filter(it -> it.getConstant().getValue().equalsIgnoreCase(n.getValue())
449 | && it.getDefault() != null)
450 | .findFirst();
451 | if (constant.isPresent()) {
452 | for (final SimpleExpressionNameValue name : getRelevantSimpleExpressionNameValues(
453 | constant.get().getDefault())) {
454 | expressions.put(name.getValue().toLowerCase(), name);
455 | }
456 | }
457 | }
458 | }
459 | return expressions;
460 | }
461 |
462 | public void checkAll(EObject obj) {
463 | final HashMap expressions = new HashMap<>();
464 | if (obj != null) {
465 | if (obj instanceof SimpleExpressionNameValue) {
466 | expressions.putAll(getSimpleExpressinNamesFromAssignments(((SimpleExpressionNameValue) obj)));
467 | if (expressions.size() == 0) {
468 | expressions.put(((SimpleExpressionNameValue) obj).getValue().toLowerCase(),
469 | ((SimpleExpressionNameValue) obj));
470 | }
471 | } else {
472 | for (final SimpleExpressionNameValue name : getRelevantSimpleExpressionNameValues(obj)) {
473 | expressions.put(name.getValue().toLowerCase(), name);
474 | }
475 | }
476 | }
477 | for (final SimpleExpressionNameValue name : expressions.values()) {
478 | check(name, expressions);
479 | }
480 | }
481 |
482 | @Check
483 | public void checkExecuteImmediate(ExecuteImmediateStatement s) {
484 | checkAll(s.getStatement());
485 | }
486 |
487 | @Check
488 | public void checkOpenFor(OpenForStatement s) {
489 | if (s.getExpression() != null) {
490 | checkAll(s.getExpression());
491 | }
492 | }
493 | }
494 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/validators/TrivadisGuidelines3Plus.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLCopGuideline;
19 | import com.trivadis.oracle.plsql.validation.PLSQLCopValidator;
20 | import com.trivadis.oracle.plsql.validation.PLSQLValidator;
21 |
22 | import java.lang.reflect.InvocationTargetException;
23 | import java.util.Arrays;
24 | import java.util.HashMap;
25 | import java.util.List;
26 | import java.util.stream.Collectors;
27 |
28 | import org.eclipse.xtext.validation.AbstractDeclarativeValidator;
29 | import org.eclipse.xtext.validation.ComposedChecks;
30 |
31 | @ComposedChecks(validators = { OverrideTrivadisGuidelines.class, SQLInjection.class, TrivadisPlsqlNaming.class,
32 | Hint.class })
33 | public class TrivadisGuidelines3Plus extends PLSQLValidator implements PLSQLCopValidator {
34 | private final TrivadisGuidelines3 converter = new TrivadisGuidelines3();
35 | private HashMap guidelines;
36 |
37 | // TODO: remove when TrivadisGuidelines2 uses new IDs
38 | @Override
39 | public String getGuidelineId(Integer id) {
40 | if (id < 1000) {
41 | return String.format("G-%04d", converter.getNewId(id));
42 | } else {
43 | return super.getGuidelineId(id);
44 | }
45 | }
46 |
47 | // TODO: remove when TrivadisGuidelines2 uses new IDs
48 | @Override
49 | public String getGuidelineMsg(Integer id) {
50 | if (id < 1000) {
51 | final Integer newId = converter.getNewId(id);
52 | final PLSQLCopGuideline guideline = getGuidelines().get(newId);
53 | String msg = null;
54 | if (guideline != null) {
55 | msg = guideline.getMsg();
56 | }
57 | return String.format("G-%04d: %s", newId, msg);
58 | } else {
59 | return super.getGuidelineMsg(id);
60 | }
61 | }
62 |
63 | @Override
64 | public HashMap getGuidelines() {
65 | if (guidelines == null) {
66 | guidelines = new HashMap<>();
67 | final List annotations = Arrays.stream(getClass().getAnnotations())
68 | .filter(it -> it.annotationType() == ComposedChecks.class).collect(Collectors.toList()).stream()
69 | .map(it -> (ComposedChecks) it).collect(Collectors.toList());
70 | for (final ComposedChecks annotation : annotations) {
71 | Class extends AbstractDeclarativeValidator>[] _validators = annotation.validators();
72 | for (final Class extends AbstractDeclarativeValidator> validator : _validators) {
73 | final AbstractDeclarativeValidator validatorInstance;
74 | try {
75 | validatorInstance = validator.getDeclaredConstructor().newInstance();
76 | } catch (InstantiationException | IllegalAccessException | InvocationTargetException
77 | | NoSuchMethodException e) {
78 | throw new RuntimeException(e);
79 | }
80 | for (final PLSQLCopGuideline guideline : ((PLSQLCopValidator) validatorInstance).getGuidelines()
81 | .values()) {
82 | if (guideline.getId() < 1000) {
83 | // TODO: remove when TrivadisGuidelines2 uses new IDs
84 | guidelines.put(converter.getNewId(guideline.getId()), guideline);
85 | } else {
86 | guidelines.put(guideline.getId(), guideline);
87 | }
88 | }
89 | }
90 | }
91 | }
92 | return guidelines;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/com/trivadis/tvdcc/validators/TrivadisPlsqlNaming.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators;
17 |
18 | import com.trivadis.oracle.plsql.plsql.CollectionTypeDefinition;
19 | import com.trivadis.oracle.plsql.plsql.ConstantDeclaration;
20 | import com.trivadis.oracle.plsql.plsql.ConstructorDeclaration;
21 | import com.trivadis.oracle.plsql.plsql.CreateFunction;
22 | import com.trivadis.oracle.plsql.plsql.CreatePackage;
23 | import com.trivadis.oracle.plsql.plsql.CreatePackageBody;
24 | import com.trivadis.oracle.plsql.plsql.CreateType;
25 | import com.trivadis.oracle.plsql.plsql.CursorDeclarationOrDefinition;
26 | import com.trivadis.oracle.plsql.plsql.ExceptionDeclaration;
27 | import com.trivadis.oracle.plsql.plsql.ExitStatement;
28 | import com.trivadis.oracle.plsql.plsql.FuncDeclInType;
29 | import com.trivadis.oracle.plsql.plsql.FunctionDefinition;
30 | import com.trivadis.oracle.plsql.plsql.ParameterDeclaration;
31 | import com.trivadis.oracle.plsql.plsql.PlsqlBlock;
32 | import com.trivadis.oracle.plsql.plsql.ProcDeclInType;
33 | import com.trivadis.oracle.plsql.plsql.ProcedureDefinition;
34 | import com.trivadis.oracle.plsql.plsql.RecordTypeDefinition;
35 | import com.trivadis.oracle.plsql.plsql.SimpleExpressionNameValue;
36 | import com.trivadis.oracle.plsql.plsql.SubTypeDefinition;
37 | import com.trivadis.oracle.plsql.plsql.UserDefinedType;
38 | import com.trivadis.oracle.plsql.plsql.VariableDeclaration;
39 | import com.trivadis.oracle.plsql.plsql.WhileLoopStatement;
40 | import com.trivadis.oracle.plsql.validation.PLSQLCopGuideline;
41 | import com.trivadis.oracle.plsql.validation.PLSQLCopValidator;
42 | import com.trivadis.oracle.plsql.validation.PLSQLValidator;
43 | import com.trivadis.oracle.plsql.validation.Remediation;
44 | import java.io.File;
45 | import java.io.FileInputStream;
46 | import java.io.IOException;
47 | import java.lang.reflect.Field;
48 | import java.util.*;
49 | import java.util.stream.Collectors;
50 |
51 | import org.eclipse.emf.ecore.EObject;
52 | import org.eclipse.emf.ecore.EPackage;
53 | import org.eclipse.xtext.EcoreUtil2;
54 | import org.eclipse.xtext.nodemodel.ICompositeNode;
55 | import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
56 | import org.eclipse.xtext.validation.Check;
57 | import org.eclipse.xtext.validation.EValidatorRegistrar;
58 |
59 | public class TrivadisPlsqlNaming extends PLSQLValidator implements PLSQLCopValidator {
60 | private HashMap guidelines;
61 |
62 | public static final String PROPERTIES_FILE_NAME = "TrivadisPlsqlNaming.properties";
63 | public static final int ISSUE_GLOBAL_VARIABLE_NAME = 9101;
64 | public static final int ISSUE_LOCAL_VARIABLE_NAME = 9102;
65 | public static final int ISSUE_CURSOR_NAME = 9103;
66 | public static final int ISSUE_RECORD_NAME = 9104;
67 | public static final int ISSUE_ARRAY_NAME = 9105;
68 | public static final int ISSUE_OBJECT_NAME = 9106;
69 | public static final int ISSUE_CURSOR_PARAMETER_NAME = 9107;
70 | public static final int ISSUE_IN_PARAMETER_NAME = 9108;
71 | public static final int ISSUE_OUT_PARAMETER_NAME = 9109;
72 | public static final int ISSUE_IN_OUT_PARAMETER_NAME = 9110;
73 | public static final int ISSUE_RECORD_TYPE_NAME = 9111;
74 | public static final int ISSUE_ARRAY_TYPE_NAME = 9112;
75 | public static final int ISSUE_EXCEPTION_NAME = 9113;
76 | public static final int ISSUE_CONSTANT_NAME = 9114;
77 | public static final int ISSUE_SUBTYPE_NAME = 9115;
78 |
79 | // default naming conventions, can be overridden via TrivadisPlsqlNaming.properties
80 | private static String REGEX_GLOBAL_VARIABLE_NAME = "^g_.+$";
81 | private static String REGEX_LOCAL_VARIABLE_NAME = "^l_.+$";
82 | private static String REGEX_CURSOR_NAME = "^c_.+$";
83 | private static String REGEX_RECORD_NAME = "^r_.+$";
84 | private static String REGEX_ARRAY_NAME = "^t_.+$";
85 | private static String REGEX_OBJECT_NAME = "^o_.+$";
86 | private static String REGEX_CURSOR_PARAMETER_NAME = "^p_.+$";
87 | private static String REGEX_IN_PARAMETER_NAME = "^in_.+$";
88 | private static String REGEX_OUT_PARAMETER_NAME = "^out_.+$";
89 | private static String REGEX_IN_OUT_PARAMETER_NAME = "^io_.+$";
90 | private static String REGEX_RECORD_TYPE_NAME = "^r_.+_type$";
91 | private static String REGEX_ARRAY_TYPE_NAME = "^t_.+_type$";
92 | private static String REGEX_EXCEPTION_NAME = "^e_.+$";
93 | private static String REGEX_CONSTANT_NAME = "^co_.+$";
94 | private static String REGEX_SUBTYPE_NAME = "^.+_type$";
95 |
96 | public TrivadisPlsqlNaming() {
97 | super();
98 | readProperties();
99 | applySystemProperties(); // this way properties can be passed to the JVM in other ways, e.g. via command-line
100 | }
101 |
102 | // must be overridden to avoid duplicate issues when used via ComposedChecks
103 | @Override
104 | public void register(EValidatorRegistrar registrar) {
105 | final List ePackages = getEPackages();
106 | if (registrar.getRegistry().get(ePackages.get(0)) == null) {
107 | // standalone validator, default registration required
108 | super.register(registrar);
109 | }
110 | }
111 |
112 | private void readProperties() {
113 | try {
114 | final FileInputStream fis = new FileInputStream(
115 | System.getProperty("user.home") + File.separator + PROPERTIES_FILE_NAME);
116 | final Properties prop = System.getProperties();
117 | prop.load(fis);
118 | fis.close();
119 | } catch (IOException e) {
120 | // ignore, see https://github.com/Trivadis/plsql-cop-validators/issues/13
121 | }
122 | }
123 |
124 | private void applySystemProperties() {
125 | final Properties prop = System.getProperties();
126 | final List fields = Arrays.stream(getClass().getDeclaredFields())
127 | .filter(it -> it.getName().startsWith("REGEX_"))
128 | .collect(Collectors.toList());
129 | for (final Field field : fields) {
130 | final Object value = prop.get(field.getName());
131 | if (value != null) {
132 | try {
133 | field.set(this, prop.get(field.getName()));
134 | } catch (IllegalArgumentException | IllegalAccessException e) {
135 | // ignore
136 | }
137 | }
138 | }
139 | }
140 |
141 | @Override
142 | public HashMap getGuidelines() {
143 | if (guidelines == null) {
144 | guidelines = new HashMap<>();
145 | // inherit all existing guidelines
146 | for (final Integer k : super.getGuidelines().keySet()) {
147 | guidelines.put(k, super.getGuidelines().get(k));
148 | }
149 | // register custom guidelines
150 | guidelines.put(ISSUE_GLOBAL_VARIABLE_NAME,
151 | new PLSQLCopGuideline(ISSUE_GLOBAL_VARIABLE_NAME,
152 | "Always name global variables to match '" + REGEX_GLOBAL_VARIABLE_NAME + "'.", MINOR,
153 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
154 | guidelines.put(ISSUE_LOCAL_VARIABLE_NAME,
155 | new PLSQLCopGuideline(ISSUE_LOCAL_VARIABLE_NAME,
156 | "Always name local variables to match '" + REGEX_LOCAL_VARIABLE_NAME + "'.", MINOR,
157 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
158 | guidelines.put(ISSUE_CURSOR_NAME,
159 | new PLSQLCopGuideline(ISSUE_CURSOR_NAME, "Always name cursors to match '" + REGEX_CURSOR_NAME + "'.",
160 | MINOR, UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
161 | guidelines.put(ISSUE_RECORD_NAME,
162 | new PLSQLCopGuideline(ISSUE_RECORD_NAME, "Always name records to match '" + REGEX_RECORD_NAME + "'.",
163 | MINOR, UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
164 | guidelines.put(ISSUE_ARRAY_NAME,
165 | new PLSQLCopGuideline(ISSUE_ARRAY_NAME,
166 | "Always name collection types (arrays/tables) to match '" + REGEX_ARRAY_NAME + "'.", MINOR,
167 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
168 | guidelines.put(ISSUE_OBJECT_NAME,
169 | new PLSQLCopGuideline(ISSUE_OBJECT_NAME, "Always name objects to match '" + REGEX_OBJECT_NAME + "'.",
170 | MINOR, UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
171 | guidelines.put(ISSUE_CURSOR_PARAMETER_NAME,
172 | new PLSQLCopGuideline(ISSUE_CURSOR_PARAMETER_NAME,
173 | "Always name cursor parameters to match '" + REGEX_CURSOR_PARAMETER_NAME + "'.", MINOR,
174 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
175 | guidelines.put(ISSUE_IN_PARAMETER_NAME,
176 | new PLSQLCopGuideline(ISSUE_IN_PARAMETER_NAME,
177 | "Always name in parameters to match '" + REGEX_IN_PARAMETER_NAME + "'.", MINOR,
178 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
179 | guidelines.put(ISSUE_OUT_PARAMETER_NAME,
180 | new PLSQLCopGuideline(ISSUE_OUT_PARAMETER_NAME,
181 | "Always name out parameters to match '" + REGEX_OUT_PARAMETER_NAME + "'.", MINOR,
182 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
183 | guidelines.put(ISSUE_IN_OUT_PARAMETER_NAME,
184 | new PLSQLCopGuideline(ISSUE_IN_OUT_PARAMETER_NAME,
185 | "Always name in/out parameters to match '" + REGEX_IN_OUT_PARAMETER_NAME + "'.", MINOR,
186 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
187 | guidelines.put(ISSUE_RECORD_TYPE_NAME,
188 | new PLSQLCopGuideline(ISSUE_RECORD_TYPE_NAME,
189 | "Always name record type definitions to match '" + REGEX_RECORD_TYPE_NAME + "'.", MINOR,
190 | UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
191 | guidelines.put(ISSUE_ARRAY_TYPE_NAME,
192 | new PLSQLCopGuideline(ISSUE_ARRAY_TYPE_NAME,
193 | "Always name collection type definitions (arrays/tables) to match '" + REGEX_ARRAY_TYPE_NAME
194 | + "'.", MINOR, UNDERSTANDABILITY, Remediation.createConstantPerIssue(1)));
195 | guidelines.put(ISSUE_EXCEPTION_NAME,
196 | new PLSQLCopGuideline(ISSUE_EXCEPTION_NAME,
197 | "Always name exceptions to match '" + REGEX_EXCEPTION_NAME + "'.", MINOR, UNDERSTANDABILITY,
198 | Remediation.createConstantPerIssue(1)));
199 | guidelines.put(ISSUE_CONSTANT_NAME,
200 | new PLSQLCopGuideline(ISSUE_CONSTANT_NAME,
201 | "Always name constants to match '" + REGEX_CONSTANT_NAME + "'.", MINOR, UNDERSTANDABILITY,
202 | Remediation.createConstantPerIssue(1)));
203 | guidelines.put(ISSUE_SUBTYPE_NAME,
204 | new PLSQLCopGuideline(ISSUE_SUBTYPE_NAME,
205 | "Always name subtypes to match '" + REGEX_SUBTYPE_NAME + "'.", MINOR, UNDERSTANDABILITY,
206 | Remediation.createConstantPerIssue(1)));
207 | }
208 | return guidelines;
209 | }
210 |
211 | private boolean isRowtype(EObject obj) {
212 | boolean ret = false;
213 | final List types = EcoreUtil2.getAllContentsOfType(obj, UserDefinedType.class);
214 | if (types.size() > 0) {
215 | if (types.get(0).isRefByRowtype()) {
216 | ret = true;
217 | }
218 | }
219 | return ret;
220 | }
221 |
222 | private boolean isRecordType(EObject obj) {
223 | boolean ret = false;
224 | List allTypes = EcoreUtil2.getAllContentsOfType(obj, UserDefinedType.class);
225 | UserDefinedType type;
226 | type = allTypes.get(0);
227 | if (type != null) {
228 | List rts = EcoreUtil2.getAllContentsOfType(EcoreUtil2.getRootContainer(obj),
229 | RecordTypeDefinition.class);
230 | if (rts.size() > 0) {
231 | final String typeName = type.getUserDefinedType().getNames().get(0).getValue();
232 | if (rts.stream().anyMatch(it -> it.getType().getValue().compareToIgnoreCase(typeName) == 0)) {
233 | ret = true;
234 | }
235 | }
236 | }
237 | return ret;
238 | }
239 |
240 | private boolean isCollectionType(EObject obj) {
241 | boolean ret = false;
242 | List allTypes = EcoreUtil2.getAllContentsOfType(obj, UserDefinedType.class);
243 | UserDefinedType type;
244 | type = allTypes.get(0);
245 | if (type != null) {
246 | List cts = EcoreUtil2.getAllContentsOfType(EcoreUtil2.getRootContainer(obj),
247 | CollectionTypeDefinition.class);
248 | if (cts.size() > 0) {
249 | final String typeName = type.getUserDefinedType().getNames().get(0).getValue();
250 | if (cts.stream().anyMatch(it -> it.getType().getValue().compareToIgnoreCase(typeName) == 0)) {
251 | ret = true;
252 | }
253 | }
254 | }
255 | return ret;
256 | }
257 |
258 | private boolean isObjectType(EObject obj) {
259 | boolean ret = false;
260 | List allTypes = EcoreUtil2.getAllContentsOfType(obj, UserDefinedType.class);
261 | UserDefinedType type;
262 | type = allTypes.get(0);
263 | if (type != null) {
264 | List ots = EcoreUtil2.getAllContentsOfType(EcoreUtil2.getRootContainer(obj), CreateType.class)
265 | .stream().filter(it -> it.getObjectTypeDef() != null).collect(Collectors.toList());
266 | if (ots.size() > 0) {
267 | final String typeName = type.getUserDefinedType().getNames().get(0).getValue();
268 | if (ots.stream().anyMatch(it -> it.getType().getValue().compareToIgnoreCase(typeName) == 0)) {
269 | ret = true;
270 | }
271 | }
272 | }
273 | return ret;
274 | }
275 |
276 | private boolean isSysRefcursor(VariableDeclaration v) {
277 | final ICompositeNode node = NodeModelUtils.getNode(v.getType());
278 | return "sys_refcursor".equalsIgnoreCase(node.getText().trim());
279 | }
280 |
281 | private boolean isQualifiedUdt(EObject obj) {
282 | boolean ret = false;
283 | List allTypes = EcoreUtil2.getAllContentsOfType(obj, UserDefinedType.class);
284 | UserDefinedType type;
285 | type = allTypes.get(0);
286 | if (type != null) {
287 | if (type.getUserDefinedType().getNames().size() > 1) {
288 | ret = true;
289 | }
290 | }
291 | return ret;
292 | }
293 |
294 | private boolean containsSimpleExpressionName(EObject container, String name) {
295 | boolean found = false;
296 | List values = EcoreUtil2.getAllContentsOfType(container,
297 | SimpleExpressionNameValue.class);
298 | for (SimpleExpressionNameValue value : values) {
299 | if (value.getValue().equalsIgnoreCase(name)) {
300 | found = true;
301 | break;
302 | }
303 | }
304 | return found;
305 | }
306 |
307 | protected EObject getParentOfBody(EObject obj) {
308 | EObject ret = obj;
309 | while (!(ret instanceof PlsqlBlock || ret instanceof ConstructorDeclaration || ret instanceof CreateFunction
310 | || ret instanceof CreatePackageBody || ret instanceof FuncDeclInType
311 | || ret instanceof FunctionDefinition || ret instanceof ProcDeclInType
312 | || ret instanceof ProcedureDefinition) && ret != null) {
313 | ret = ret.eContainer();
314 | }
315 | return ret;
316 | }
317 |
318 | private boolean isLoopIndexVariable(EObject obj) {
319 | if (obj instanceof SimpleExpressionNameValue) {
320 | String varName = ((SimpleExpressionNameValue) obj).getValue();
321 | EObject container = getParentOfBody(obj);
322 | List whileLoops = EcoreUtil2.getAllContentsOfType(container,
323 | WhileLoopStatement.class);
324 | boolean found = false;
325 | for (WhileLoopStatement whileLoop : whileLoops) {
326 | if (containsSimpleExpressionName(whileLoop.getCondition(), varName)) {
327 | found = true;
328 | break;
329 | }
330 | }
331 | if (!found) {
332 | List exits = EcoreUtil2.getAllContentsOfType(container, ExitStatement.class);
333 | for (ExitStatement exit : exits) {
334 | if (containsSimpleExpressionName(exit.getCondition(), varName)) {
335 | found = true;
336 | break;
337 | }
338 | }
339 | }
340 | return found;
341 | }
342 | return false;
343 | }
344 |
345 | @Check
346 | public void checkVariableName(VariableDeclaration v) {
347 | final EObject parent = v.eContainer().eContainer();
348 | final String name = v.getVariable().getValue().toLowerCase();
349 | if (isSysRefcursor(v)) {
350 | if (!name.matches(REGEX_CURSOR_NAME)) {
351 | warning(ISSUE_CURSOR_NAME, v.getVariable(), v);
352 | }
353 | } else if (isObjectType(v)) {
354 | if (!name.matches(REGEX_OBJECT_NAME)) {
355 | warning(ISSUE_OBJECT_NAME, v.getVariable(), v);
356 | }
357 | } else if (isCollectionType(v)) {
358 | if (!name.matches(REGEX_ARRAY_NAME)) {
359 | warning(ISSUE_ARRAY_NAME, v.getVariable(), v);
360 | }
361 | } else if (isRowtype(v) || isRecordType(v)) {
362 | if (!name.matches(REGEX_RECORD_NAME)) {
363 | warning(ISSUE_RECORD_NAME, v.getVariable(), v);
364 | }
365 | } else {
366 | // reduce false positives, skip checking variables base on qualified UDTs
367 | if (!isQualifiedUdt(v)) {
368 | if (parent instanceof CreatePackage || parent instanceof CreatePackageBody) {
369 | if (!name.matches(REGEX_GLOBAL_VARIABLE_NAME)) {
370 | warning(ISSUE_GLOBAL_VARIABLE_NAME, v.getVariable(), v);
371 | }
372 | } else {
373 | // reduce false positives, allow cursor/object/array names and loop indices (e.g. i and j)
374 | if (!name.matches(REGEX_LOCAL_VARIABLE_NAME) && !name.matches(REGEX_CURSOR_NAME)
375 | && !name.matches(REGEX_OBJECT_NAME) && !name.matches(REGEX_ARRAY_NAME)
376 | && !isLoopIndexVariable(v.getVariable())) {
377 | warning(ISSUE_LOCAL_VARIABLE_NAME, v.getVariable(), v);
378 | }
379 | }
380 | }
381 | }
382 | }
383 |
384 | @Check
385 | public void checkCursorName(CursorDeclarationOrDefinition c) {
386 | if (!c.getCursor().getValue().toLowerCase().matches(REGEX_CURSOR_NAME)) {
387 | warning(ISSUE_CURSOR_NAME, c.getCursor());
388 | }
389 | for (final ParameterDeclaration p : c.getParams()) {
390 | if (!p.getParameter().getValue().toLowerCase().matches(REGEX_CURSOR_PARAMETER_NAME)) {
391 | warning(ISSUE_CURSOR_PARAMETER_NAME, p.getParameter(), p);
392 | }
393 | }
394 | }
395 |
396 | @Check
397 | public void checkParameterName(ParameterDeclaration p) {
398 | final EObject parent = p.eContainer();
399 | if (!(parent instanceof CursorDeclarationOrDefinition)) {
400 | final String name = p.getParameter().getValue();
401 | if (!("self".equalsIgnoreCase(name))) {
402 | if (p.isIn() && p.isOut()) {
403 | if (!name.matches(REGEX_IN_OUT_PARAMETER_NAME)) {
404 | warning(ISSUE_IN_OUT_PARAMETER_NAME, p.getParameter(), p);
405 | }
406 | } else if (p.isOut()) {
407 | if (!name.matches(REGEX_OUT_PARAMETER_NAME)) {
408 | warning(ISSUE_OUT_PARAMETER_NAME, p.getParameter(), p);
409 | }
410 | } else {
411 | if (!name.matches(REGEX_IN_PARAMETER_NAME)) {
412 | warning(ISSUE_IN_PARAMETER_NAME, p.getParameter(), p);
413 | }
414 | }
415 | }
416 | }
417 | }
418 |
419 | @Check
420 | public void checkRecordTypeName(RecordTypeDefinition rt) {
421 | final String name = rt.getType().getValue().toLowerCase();
422 | if (!(name.matches(REGEX_RECORD_TYPE_NAME))) {
423 | warning(ISSUE_RECORD_TYPE_NAME, rt.getType(), rt);
424 | }
425 | }
426 |
427 | @Check
428 | public void checkArrayTypeName(CollectionTypeDefinition ct) {
429 | final String name = ct.getType().getValue().toLowerCase();
430 | if (!(name.matches(REGEX_ARRAY_TYPE_NAME))) {
431 | warning(ISSUE_ARRAY_TYPE_NAME, ct.getType(), ct);
432 | }
433 | }
434 |
435 | @Check
436 | public void checkExceptionName(ExceptionDeclaration e) {
437 | if (!e.getException().getValue().toLowerCase().matches(REGEX_EXCEPTION_NAME)) {
438 | warning(ISSUE_EXCEPTION_NAME, e.getException(), e);
439 | }
440 | }
441 |
442 | @Check
443 | public void checkConstantName(ConstantDeclaration co) {
444 | if (!co.getConstant().getValue().toLowerCase().matches(REGEX_CONSTANT_NAME)) {
445 | warning(ISSUE_CONSTANT_NAME, co.getConstant(), co);
446 | }
447 | }
448 |
449 | @Check
450 | public void checkSubtypeName(SubTypeDefinition st) {
451 | if (!st.getType().getValue().toLowerCase().matches(REGEX_SUBTYPE_NAME)) {
452 | warning(ISSUE_SUBTYPE_NAME, st.getType(), st);
453 | }
454 | }
455 | }
456 |
--------------------------------------------------------------------------------
/src/main/resources/GLP/genmodel/plsqlcop-model.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CHANGEABILITY
6 | Changeability
7 |
8 | ARCHITECTURE_CHANGEABILITY
9 | Architecture changeability
10 |
11 |
12 | DATA_CHANGEABILITY
13 | Data changeability
14 |
15 |
16 | LOGIC_CHANGEABILITY
17 | Logic changeability
18 |
19 |
20 |
21 | EFFICIENCY
22 | Efficiency
23 |
24 | CPU_EFFICIENCY
25 | Cpu efficiency
26 |
27 |
28 | MEMORY_EFFICIENCY
29 | Memory efficiency
30 |
31 |
32 | NETWORK_USE
33 | Network use
34 |
35 |
36 |
37 | MAINTAINABILITY
38 | Maintainability
39 |
40 | READABILITY
41 | Readability
42 |
43 |
44 | UNDERSTANDABILITY
45 | Understandability
46 |
47 |
48 | trivadis
49 | G-0000
50 |
51 | remediationFunction
52 | CONSTANT_ISSUE
53 |
54 |
55 | remediationFactor
56 | 0.0
57 | mn
58 |
59 |
60 | offset
61 | 0.0
62 | mn
63 |
64 |
65 |
66 |
67 | trivadis
68 | G-9001
69 |
70 | remediationFunction
71 | CONSTANT_ISSUE
72 |
73 |
74 | remediationFactor
75 | 0.0
76 | mn
77 |
78 |
79 | offset
80 | 1.0
81 | mn
82 |
83 |
84 |
85 |
86 | trivadis
87 | G-9002
88 |
89 | remediationFunction
90 | CONSTANT_ISSUE
91 |
92 |
93 | remediationFactor
94 | 0.0
95 | mn
96 |
97 |
98 | offset
99 | 1.0
100 | mn
101 |
102 |
103 |
104 |
105 | trivadis
106 | G-9003
107 |
108 | remediationFunction
109 | CONSTANT_ISSUE
110 |
111 |
112 | remediationFactor
113 | 0.0
114 | mn
115 |
116 |
117 | offset
118 | 1.0
119 | mn
120 |
121 |
122 |
123 |
124 |
125 | PORTABILITY
126 | Portability
127 |
128 | COMPILER_RELATED_PORTABILITY
129 | Compiler related portability
130 |
131 |
132 | HARDWARE_RELATED_PORTABILITY
133 | Hardware related portability
134 |
135 |
136 | LANGUAGE_RELATED_PORTABILITY
137 | Language related portability
138 |
139 |
140 | OS_RELATED_PORTABILITY
141 | Os related portability
142 |
143 |
144 | SOFTWARE_RELATED_PORTABILITY
145 | Software related portability
146 |
147 |
148 | TIME_ZONE_RELATED_PORTABILITY
149 | Time zone related portability
150 |
151 |
152 |
153 | RELIABILITY
154 | Reliability
155 |
156 | ARCHITECTURE_RELIABILITY
157 | Architecture reliability
158 |
159 |
160 | ARCHITECTURE_RELIABILITY
161 | Architecture reliability
162 |
163 |
164 | trivadis
165 | E-0001
166 |
167 | remediationFunction
168 | CONSTANT_ISSUE
169 |
170 |
171 | remediationFactor
172 | 0.0
173 | mn
174 |
175 |
176 | offset
177 | 1.0
178 | mn
179 |
180 |
181 |
182 |
183 | trivadis
184 | E-0002
185 |
186 | remediationFunction
187 | CONSTANT_ISSUE
188 |
189 |
190 | remediationFactor
191 | 0.0
192 | mn
193 |
194 |
195 | offset
196 | 1.0
197 | mn
198 |
199 |
200 |
201 |
202 | trivadis
203 | E-0003
204 |
205 | remediationFunction
206 | CONSTANT_ISSUE
207 |
208 |
209 | remediationFactor
210 | 0.0
211 | mn
212 |
213 |
214 | offset
215 | 1.0
216 | mn
217 |
218 |
219 |
220 |
221 | DATA_RELIABILITY
222 | Data reliability
223 |
224 |
225 | EXCEPTION_HANDLING
226 | Exception handling
227 |
228 |
229 | FAULT_TOLERANCE
230 | Fault tolerance
231 |
232 |
233 | INSTRUCTION_RELIABILITY
234 | Instruction reliability
235 |
236 |
237 | LOGIC_RELIABILITY
238 | Logic reliability
239 |
240 |
241 | RESOURCE_RELIABILITY
242 | Resource reliability
243 |
244 |
245 | SYNCHRONIZATION_RELIABILITY
246 | Synchronization reliability
247 |
248 |
249 | UNIT_TESTS
250 | Unit tests
251 |
252 |
253 |
254 | REUSABILITY
255 | Reusability
256 |
257 | MODULARITY
258 | Modularity
259 |
260 |
261 | TRANSPORTABILITY
262 | Transportability
263 |
264 |
265 |
266 | SECURITY
267 | Security
268 |
269 | API_ABUSE
270 | Api abuse
271 |
272 |
273 | ERRORS
274 | Errors
275 |
276 |
277 | INPUT_VALIDATION_AND_REPRESENTATION
278 | Input validation and representation
279 |
280 |
281 | SECURITY_FEATURES
282 | Security features
283 |
284 |
285 |
286 | TESTABILITY
287 | Testability
288 |
289 | INTEGRATION_TESTABILITY
290 | Integration testability
291 |
292 |
293 | UNIT_TESTABILITY
294 | Unit testability
295 |
296 |
297 |
298 |
--------------------------------------------------------------------------------
/src/main/resources/GLP/genmodel/rules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | G-0000
6 |
7 | CODE_SMELL
8 | G-0000
9 | INFO
10 | SINGLE
11 | READY
12 |
]]>
14 | avoid
15 |
16 |
17 | G-9001
18 |
19 | CODE_SMELL
20 | G-9001
21 | MINOR
22 | SINGLE
23 | READY
24 | Reason
26 | To easily distinguish between global and local variables.
27 | Furthermore, the use of a prefix avoids naming conflicts with reserved words.
28 | Bad
29 | create or replace package pkg as
30 | global_variable integer;
31 | end pkg;
32 | /
33 | Good
34 | create or replace package pkg as
35 | g_global_variable integer;
36 | end pkg;
37 | /
38 |
]]>
39 | always
40 |
41 |
42 | G-9002
43 |
44 | CODE_SMELL
45 | G-9002
46 | MINOR
47 | SINGLE
48 | READY
49 | Reason
51 | To easily distinguish between global and local variables.
52 | Furthermore, the use of a prefix avoids naming conflicts with reserved words.
53 | Bad
54 | create or replace procedure p as
55 | c integer;
56 | begin
57 | null;
58 | end p;
59 | /
60 | Good
61 | create or replace procedure p as
62 | l_something integer;
63 | begin
64 | null;
65 | end p;
66 | /
67 |
]]>
68 | always
69 |
70 |
71 | G-9003
72 |
73 | CODE_SMELL
74 | G-9003
75 | MINOR
76 | SINGLE
77 | READY
78 | Reason
80 | To easily distinguish between parameters and variables.
81 | Furthermore, the use of a prefix avoids naming conflicts with reserved words.
82 | Bad
83 | create or replace procedure p (a in integer, b in varchar2) as
84 | begin
85 | null;
86 | end p;
87 | /
88 | Good
89 | create or replace procedure p (p_1 in integer, p_2 in varchar2) as
90 | begin
91 | null;
92 | end p;
93 | /
94 |
]]>
95 | always
96 |
97 |
98 | E-0001
99 | E-0001: Timeout occurred (after n seconds) during load/parse/validation of resource.
100 | BUG
101 | E-0001
102 | BLOCKER
103 | SINGLE
104 | READY
105 | Reason
107 | Processing large SQL files takes time. Increase the db* CODECOP timeout parameter to avoid this error. The default timeout per file is 10 seconds.
108 | ]]>
109 | error
110 |
111 |
112 | E-0002
113 | E-0002: Syntax error. Please check the limitations and contact the author if the code can be compiled successfully in your environment.
114 | BUG
115 | E-0002
116 | BLOCKER
117 | SINGLE
118 | READY
119 | Reason
121 | It's either a db* CODECOP bug or a limitation , if the code compiles successfully in your environment.
122 | Please note, that syntax errors may lead to false positives. db* CODECOP will therefore not report guideline violations, if a syntax error was encountered in the processed file.
123 | ]]>
124 | error
125 |
126 |
127 | E-0003
128 | E-0003: License limit reached.
129 | BUG
130 | E-0003
131 | BLOCKER
132 | SINGLE
133 | READY
134 | Reason
136 | A db* CODECOP license key defines limitations for the validity date, the major version, the number of files, the number of lines, the number commands and the number of bytes to be processed. Please contact your sales representative to obtain a less restrictive license.
137 | ]]>
138 | error
139 |
140 |
141 |
--------------------------------------------------------------------------------
/src/main/resources/GLP/sample/guideline_9001.sql:
--------------------------------------------------------------------------------
1 | -- G-9001 Always prefix global variables with 'g_'.
2 |
3 | -- Reason
4 | /*To easily distinguish between global and local variables.
*/
5 | /*Furthermore, the use of a prefix avoids naming conflicts with reserved words.
*/
6 |
7 | -- Bad
8 | create or replace package pkg as
9 | global_variable integer;
10 | end pkg;
11 | /
12 |
13 | -- Good
14 | create or replace package pkg as
15 | g_global_variable integer;
16 | end pkg;
17 | /
18 |
--------------------------------------------------------------------------------
/src/main/resources/GLP/sample/guideline_9002.sql:
--------------------------------------------------------------------------------
1 | -- G-9002: Always prefix local variables with 'l_'.
2 |
3 | -- Reason
4 | /*To easily distinguish between global and local variables.
*/
5 | /*Furthermore, the use of a prefix avoids naming conflicts with reserved words.
*/
6 |
7 | -- Bad
8 | create or replace procedure p as
9 | c integer;
10 | begin
11 | null;
12 | end p;
13 | /
14 |
15 | -- Good
16 | create or replace procedure p as
17 | l_something integer;
18 | begin
19 | null;
20 | end p;
21 | /
22 |
--------------------------------------------------------------------------------
/src/main/resources/GLP/sample/guideline_9003.sql:
--------------------------------------------------------------------------------
1 | -- G-9003: Always prefix parameters with 'p_'.
2 |
3 | -- Reason
4 | /*To easily distinguish between parameters and variables.
*/
5 | /*Furthermore, the use of a prefix avoids naming conflicts with reserved words.
*/
6 |
7 | -- Bad
8 | create or replace procedure p (a in integer, b in varchar2) as
9 | begin
10 | null;
11 | end p;
12 | /
13 |
14 | -- Good
15 | create or replace procedure p (p_1 in integer, p_2 in varchar2) as
16 | begin
17 | null;
18 | end p;
19 | /
20 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9101.sql:
--------------------------------------------------------------------------------
1 | -- G-9101: Always name global variables to match '^g_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_GLOBAL_VARIABLE_NAME.
*/
6 |
7 | -- Bad
8 | create or replace package body example as
9 | some_name integer;
10 | end example;
11 | /
12 |
13 | -- Good
14 | create or replace package body example as
15 | g_some_name integer;
16 | end example;
17 | /
18 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9102.sql:
--------------------------------------------------------------------------------
1 | -- G-9102: Always name local variables to match '^l_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_LOCAL_VARIABLE_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | some_name integer;
10 | begin
11 | null;
12 | end;
13 | /
14 |
15 | -- Good
16 | declare
17 | l_some_name integer;
18 | begin
19 | null;
20 | end;
21 | /
22 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9103.sql:
--------------------------------------------------------------------------------
1 | -- G-9103: Always name cursors to match '^c_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_CURSOR_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | l_dept sys_refcursor;
10 | begin
11 | null;
12 | end;
13 | /
14 |
15 | -- Good
16 | declare
17 | c_dept sys_refcursor;
18 | begin
19 | null;
20 | end;
21 | /
22 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9104.sql:
--------------------------------------------------------------------------------
1 | -- G-9104: Always name records to match '^r_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_RECORD_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | emp emp%rowtype;
10 | type r_dept_type is record(
11 | deptno number,
12 | dname varchar2(14 char),
13 | loc loc(13 char)
14 | );
15 | dept r_dept_type;
16 | begin
17 | null;
18 | end;
19 | /
20 |
21 | -- Good
22 | declare
23 | r_emp emp%rowtype;
24 | type r_dept_type is record(
25 | deptno number,
26 | dname varchar2(14 char),
27 | loc loc(13 char)
28 | );
29 | r_dept r_dept_type;
30 | begin
31 | null;
32 | end;
33 | /
34 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9105.sql:
--------------------------------------------------------------------------------
1 | -- G-9105: Always name collection types (arrays/tables) to match '^t_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_ARRAY_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | type t_varray_type is varray(10) of string;
10 | array1 t_varray_type;
11 | type t_nested_table_type is table of string;
12 | array2 t_nested_table_type;
13 | type t_assoc_array_type is table of string index by pls_integer;
14 | array3 t_assoc_array_type;
15 | begin
16 | null;
17 | end;
18 | /
19 |
20 | -- Good
21 | declare
22 | type t_varray_type is varray(10) of string;
23 | t_array1 t_varray_type;
24 | type t_nested_table_type is table of string;
25 | t_array2 t_nested_table_type;
26 | type t_assoc_array_type is table of string index by pls_integer;
27 | t_array3 t_assoc_array_type;
28 | begin
29 | null;
30 | end;
31 | /
32 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9106.sql:
--------------------------------------------------------------------------------
1 | -- G-9106: Always name objects to match '^o_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_OBJECT_NAME.
*/
6 |
7 | -- Bad
8 | create or replace type dept_type as object (
9 | deptno integer,
10 | dname varchar2(14 char),
11 | loc varchar2(13 char)
12 | );
13 | /
14 |
15 | declare
16 | dept dept_type;
17 | begin
18 | null;
19 | end;
20 | /
21 |
22 | -- Good
23 | create or replace type dept_type as object (
24 | deptno integer,
25 | dname varchar2(14 char),
26 | loc varchar2(13 char)
27 | );
28 | /
29 |
30 | declare
31 | o_dept dept_type;
32 | begin
33 | null;
34 | end;
35 | /
36 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9107.sql:
--------------------------------------------------------------------------------
1 | -- G-9107: Always name cursor parameters to match '^p_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_CURSOR_PARAMETER_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | cursor c_emp(in_ename in varchar2) is
10 | select *
11 | from emp
12 | where ename like in_ename;
13 | begin
14 | null;
15 | end;
16 | /
17 |
18 | -- Good
19 | declare
20 | cursor c_emp(p_ename in varchar2) is
21 | select *
22 | from emp
23 | where ename like p_ename;
24 | begin
25 | null;
26 | end;
27 | /
28 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9108.sql:
--------------------------------------------------------------------------------
1 | -- G-9108: Always name in parameters to match '^in_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_IN_PARAMETER_NAME.
*/
6 |
7 | -- Bad
8 | create or replace package p is
9 | procedure p2(param in integer);
10 | end p;
11 | /
12 |
13 | -- Good
14 | create or replace package p is
15 | procedure p2(in_param in integer);
16 | end p;
17 | /
18 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9109.sql:
--------------------------------------------------------------------------------
1 | -- G-9109: Always name out parameters to match '^out_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_OUT_PARAMETER_NAME.
*/
6 |
7 | -- Bad
8 | create or replace package p is
9 | procedure p2(param out integer);
10 | end p;
11 | /
12 |
13 | -- Good
14 | create or replace package p is
15 | procedure p2(out_param out integer);
16 | end p;
17 | /
18 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9110.sql:
--------------------------------------------------------------------------------
1 | -- G-9110: Always name in/out parameters to match '^io_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_IN_OUT_PARAMETER_NAME.
*/
6 |
7 | -- Bad
8 | create or replace package p is
9 | procedure p2(param in out integer);
10 | end p;
11 | /
12 |
13 | -- Good
14 | create or replace package p is
15 | procedure p2(io_param in out integer);
16 | end p;
17 | /
18 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9111.sql:
--------------------------------------------------------------------------------
1 | -- G-9111: Always name record type definitions to match '^r_.+_type$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_RECORD_TYPE_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | type dept_typ is
10 | record(
11 | deptno number,
12 | dname varchar2(14 char),
13 | loc loc(13 char)
14 | );
15 | begin
16 | null;
17 | end;
18 | /
19 |
20 | -- Good
21 | declare
22 | type r_dept_type is
23 | record(
24 | deptno number,
25 | dname varchar2(14 char),
26 | loc loc(13 char)
27 | );
28 | begin
29 | null;
30 | end;
31 | /
32 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9112.sql:
--------------------------------------------------------------------------------
1 | -- G-9112: Always name collection type definitions (arrays/tables) to match '^t_.+_type$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_ARRAY_TYPE_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | type t_varray is varray(10) of string;
10 | type nested_table_type is table of string;
11 | type x_assoc_array_y is table of string index by pls_integer;
12 | begin
13 | null;
14 | end;
15 | /
16 |
17 | -- Good
18 | declare
19 | type t_varray_type is varray(10) of string;
20 | type t_nested_table_type is table of string;
21 | type t_assoc_array_type is table of string index by pls_integer;
22 | begin
23 | null;
24 | end;
25 | /
26 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9113.sql:
--------------------------------------------------------------------------------
1 | -- G-9113: Always name exceptions to match '^e_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_EXCEPTION_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | some_name exception;
10 | begin
11 | null;
12 | end;
13 | /
14 |
15 | -- Good
16 | declare
17 | e_some_name exception;
18 | begin
19 | null;
20 | end;
21 | /
22 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9114.sql:
--------------------------------------------------------------------------------
1 | -- G-9114: Always name constants to match '^co_.+$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_CONSTANT_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | maximum constant integer := 1000;
10 | begin
11 | null;
12 | end;
13 | /
14 |
15 | -- Good
16 | declare
17 | co_maximum constant integer := 1000;
18 | begin
19 | null;
20 | end;
21 | /
22 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9115.sql:
--------------------------------------------------------------------------------
1 | -- G-9115: Always name subtypes to match '^.+_type$'.
2 |
3 | -- Reason
4 | /*See Naming Conventions for PL/SQL .
5 | You can override the default via system property REGEX_SUBTYPE_NAME.
*/
6 |
7 | -- Bad
8 | declare
9 | subtype short_text is varchar2(100 char);
10 | begin
11 | null;
12 | end;
13 | /
14 |
15 | -- Good
16 | declare
17 | subtype short_text_type is varchar2(100 char);
18 | begin
19 | null;
20 | end;
21 | /
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9501.sql:
--------------------------------------------------------------------------------
1 | -- G-9501: Never use parameter in string expression of dynamic SQL. Use asserted local variable instead.
2 |
3 | -- Reason
4 | /*The use of static SQL eliminates the risk of SQL injection. However, if you write
5 | dynamic SQL you are responsible to ensure that the SQL cannot be injected with malicious
6 | SQL statements.
7 |
*/
8 |
9 | /*
This check looks for unasserted parameters used in execute immediate
statements
10 | and open for
statements. All parameters used in these statements must be asserted with
11 | one of the subprograms provided by dbms_assert
.
*/
12 |
13 | -- Bad
14 | -- The input parameter in_table_name is copied to the local variable l_table_name and then used
15 | -- without an assert to build the l_sql variable. Hence, the execute immediate statement is
16 | -- considered vulnerable to SQL injection, e.g. by passing DEPT CASCADE CONSTRAINTS.
17 | create or replace package body pkg is
18 | function f (in_table_name in varchar2) return boolean as
19 | co_templ constant varchar2(4000 byte) := 'DROP TABLE #in_table_name# PURGE';
20 | l_table_name varchar2(128 byte);
21 | l_sql varchar2(4000 byte);
22 | begin
23 | l_table_name := in_table_name;
24 | l_sql := replace(co_templ, '#in_table_name#', l_table_name);
25 | execute immediate l_sql;
26 | return true;
27 | end f;
28 | end pkg;
29 | /
30 |
31 | -- Good
32 | -- SQL injection is not possible, because the input parameter in_table_name is
33 | -- checked/modified with sys.dbms_assert.enquote_name.
34 | create or replace package body pkg is
35 | function f (in_table_name in varchar2) return boolean as
36 | co_templ constant varchar2(4000 byte) := 'DROP TABLE #in_table_name# PURGE';
37 | l_table_name varchar2(128 byte);
38 | l_sql varchar2(4000 byte);
39 | begin
40 | l_table_name := sys.dbms_assert.enquote_name(in_table_name);
41 | l_sql := replace(co_templ, '#in_table_name#', l_table_name);
42 | execute immediate l_sql;
43 | return true;
44 | end f;
45 | end pkg;
46 | /
47 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9600.sql:
--------------------------------------------------------------------------------
1 | -- G-9600: Never define more than one comment with hints.
2 |
3 | -- Reason
4 | /*Only the first comment containing hints is considered by the Oracle Database,
5 | therefore all hints violating this rule are treated as ordinary comments.
*/
6 |
7 | -- Bad
8 | select -- a comment
9 | /*+ full(e) */
10 | /* another comment */
11 | --+ full(d)
12 | e.empno,
13 | e.ename,
14 | d.dname
15 | from emp e
16 | join dept d
17 | on d.deptno = e.deptno
18 | where empno > 7900;
19 |
20 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
21 |
22 | /*
23 | ------------------------------------------------
24 | | Id | Operation | Name |
25 | ------------------------------------------------
26 | | 0 | SELECT STATEMENT | |
27 | | 1 | NESTED LOOPS | |
28 | | 2 | NESTED LOOPS | |
29 | | 3 | TABLE ACCESS FULL | EMP |
30 | | 4 | INDEX UNIQUE SCAN | PK_DEPT |
31 | | 5 | TABLE ACCESS BY INDEX ROWID| DEPT |
32 | ------------------------------------------------
33 |
34 | Hint Report (identified by operation id / Query Block Name / Object Alias):
35 | Total hints for statement: 1
36 | ---------------------------------------------------------------------------
37 |
38 | 3 - SEL$58A6D7F6 / E@SEL$1
39 | - full(e)
40 | */
41 |
42 | -- Better
43 | select -- a comment
44 | /*+ full(e) full(d) */
45 | /* another comment */
46 | e.empno,
47 | e.ename,
48 | d.dname
49 | from emp e
50 | join dept d
51 | on d.deptno = e.deptno
52 | where empno > 7900;
53 |
54 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
55 |
56 | /*
57 | -----------------------------------
58 | | Id | Operation | Name |
59 | -----------------------------------
60 | | 0 | SELECT STATEMENT | |
61 | | 1 | HASH JOIN | |
62 | | 2 | TABLE ACCESS FULL| EMP |
63 | | 3 | TABLE ACCESS FULL| DEPT |
64 | -----------------------------------
65 |
66 | Hint Report (identified by operation id / Query Block Name / Object Alias):
67 | Total hints for statement: 2
68 | ---------------------------------------------------------------------------
69 |
70 | 2 - SEL$58A6D7F6 / E@SEL$1
71 | - full(e)
72 |
73 | 3 - SEL$58A6D7F6 / D@SEL$1
74 | - full(d)
75 | */
76 |
77 | -- Good
78 | -- do not mix single-line and mult-line comments
79 | -- use hints first or hints last, do not hide them within other comments
80 | select --+ full(e) full(d)
81 | -- a comment
82 | -- another comment
83 | e.empno,
84 | e.ename,
85 | d.dname
86 | from emp e
87 | join dept d
88 | on d.deptno = e.deptno
89 | where empno > 7900;
90 |
91 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
92 |
93 | /*
94 | -----------------------------------
95 | | Id | Operation | Name |
96 | -----------------------------------
97 | | 0 | SELECT STATEMENT | |
98 | | 1 | HASH JOIN | |
99 | | 2 | TABLE ACCESS FULL| EMP |
100 | | 3 | TABLE ACCESS FULL| DEPT |
101 | -----------------------------------
102 |
103 | Hint Report (identified by operation id / Query Block Name / Object Alias):
104 | Total hints for statement: 2
105 | ---------------------------------------------------------------------------
106 |
107 | 2 - SEL$58A6D7F6 / E@SEL$1
108 | - full(e)
109 |
110 | 3 - SEL$58A6D7F6 / D@SEL$1
111 | - full(d)
112 | */
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9601.sql:
--------------------------------------------------------------------------------
1 | -- G-9601: Never use unknown hints.
2 |
3 | -- Reason
4 | /*Using unknown hints might invalidate all subsequent hints.
5 | This happens when you use for example NOLOGGING. That's expected
6 | and not a bug. See MOS note 285285.1 or bug 8432870 for details.
*/
7 |
8 | -- Bad
9 | -- "nologging" is not a hint. It does not exist in v$sql_hint.
10 | -- The "append" hint is ignored as a result "LOAD TABLE CONVENTIONAL" is applied.
11 | insert --+ nologging append
12 | into sales_hist
13 | select * from sales;
14 |
15 | select * from dbms_xplan.display_cursor(format => 'basic');
16 |
17 | /*
18 | -----------------------------------------------
19 | | Id | Operation | Name |
20 | -----------------------------------------------
21 | | 0 | INSERT STATEMENT | |
22 | | 1 | LOAD TABLE CONVENTIONAL | SALES_HIST |
23 | | 2 | PARTITION RANGE ALL | |
24 | | 3 | TABLE ACCESS FULL | SALES |
25 | -----------------------------------------------
26 | */
27 |
28 |
29 | -- Good
30 | -- "nologging" is applied on the table, however this is in most
31 | -- environments overridden by the force logging option on database level.
32 | -- The "append" hint is applied, as a result "LOAD AS SELECT" is applied.
33 | alter table sales_hist nologging;
34 |
35 | insert --+ append
36 | into sales_hist
37 | select * from sales;
38 |
39 | select * from dbms_xplan.display_cursor(format => 'basic');
40 |
41 | /*
42 | -------------------------------------------------------
43 | | Id | Operation | Name |
44 | -------------------------------------------------------
45 | | 0 | INSERT STATEMENT | |
46 | | 1 | LOAD AS SELECT | SALES_HIST |
47 | | 2 | OPTIMIZER STATISTICS GATHERING | |
48 | | 3 | PARTITION RANGE ALL | |
49 | | 4 | TABLE ACCESS FULL | SALES |
50 | -------------------------------------------------------
51 | */
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9602.sql:
--------------------------------------------------------------------------------
1 | -- G-9602: Always use the alias name instead of the table name.
2 |
3 | -- Reason
4 | /* There are various hints that reference a table or view. Typically, if an alias is defined
5 | for a table/view, but the table/view name is used in the hint, then the hint is
6 | ignored by the Oracle Database.
*/
7 |
8 | -- Bad
9 | select --+ leading(emp dept)
10 | *
11 | from emp e
12 | join dept d on d.deptno = e.deptno;
13 |
14 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
15 |
16 | /*
17 | ------------------------------------------------
18 | | Id | Operation | Name |
19 | ------------------------------------------------
20 | | 0 | SELECT STATEMENT | |
21 | | 1 | MERGE JOIN | |
22 | | 2 | TABLE ACCESS BY INDEX ROWID| DEPT |
23 | | 3 | INDEX FULL SCAN | PK_DEPT |
24 | | 4 | SORT JOIN | |
25 | | 5 | TABLE ACCESS FULL | EMP |
26 | ------------------------------------------------
27 |
28 | Hint Report (identified by operation id / Query Block Name / Object Alias):
29 | Total hints for statement: 1 (U - Unused (1))
30 | ---------------------------------------------------------------------------
31 |
32 | 1 - SEL$58A6D7F6
33 | U - leading(emp dept)
34 | */
35 |
36 |
37 | -- Good
38 | select --+ leading(e d)
39 | *
40 | from emp e
41 | join dept d on d.deptno = e.deptno;
42 |
43 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
44 |
45 | /*
46 | -----------------------------------
47 | | Id | Operation | Name |
48 | -----------------------------------
49 | | 0 | SELECT STATEMENT | |
50 | | 1 | HASH JOIN | |
51 | | 2 | TABLE ACCESS FULL| EMP |
52 | | 3 | TABLE ACCESS FULL| DEPT |
53 | -----------------------------------
54 |
55 | Hint Report (identified by operation id / Query Block Name / Object Alias):
56 | Total hints for statement: 1
57 | ---------------------------------------------------------------------------
58 |
59 | 1 - SEL$58A6D7F6
60 | - leading(e d)
61 | */
62 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9603.sql:
--------------------------------------------------------------------------------
1 | -- G-9603: Never reference an unknown table/alias.
2 |
3 | -- Reason
4 | /* There are various hints that reference a table or view. If the table or
5 | view reference in the hint is neither a table name nor an alias, then the hint
6 | is ignored by the Oracle Database.
*/
7 |
8 | -- Bad
9 | select --+ leading(emps depts)
10 | *
11 | from emp
12 | join dept on emp.deptno = dept.deptno;
13 |
14 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
15 |
16 | /*
17 | ------------------------------------------------
18 | | Id | Operation | Name |
19 | ------------------------------------------------
20 | | 0 | SELECT STATEMENT | |
21 | | 1 | MERGE JOIN | |
22 | | 2 | TABLE ACCESS BY INDEX ROWID| DEPT |
23 | | 3 | INDEX FULL SCAN | PK_DEPT |
24 | | 4 | SORT JOIN | |
25 | | 5 | TABLE ACCESS FULL | EMP |
26 | ------------------------------------------------
27 |
28 | Hint Report (identified by operation id / Query Block Name / Object Alias):
29 | Total hints for statement: 1 (U - Unused (1))
30 | ---------------------------------------------------------------------------
31 |
32 | 1 - SEL$58A6D7F6
33 | U - leading(emps depts)
34 | */
35 |
36 |
37 | -- Good
38 | select --+ leading(emp dept)
39 | *
40 | from emp
41 | join dept on emp.deptno = dept.deptno;
42 |
43 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
44 |
45 | /*
46 | -----------------------------------
47 | -----------------------------------
48 | | Id | Operation | Name |
49 | -----------------------------------
50 | | 0 | SELECT STATEMENT | |
51 | | 1 | HASH JOIN | |
52 | | 2 | TABLE ACCESS FULL| EMP |
53 | | 3 | TABLE ACCESS FULL| DEPT |
54 | -----------------------------------
55 |
56 | Hint Report (identified by operation id / Query Block Name / Object Alias):
57 | Total hints for statement: 1
58 | ---------------------------------------------------------------------------
59 |
60 | 1 - SEL$58A6D7F6
61 | - leading(emp dept)
62 | */
63 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9604.sql:
--------------------------------------------------------------------------------
1 | -- G-9604: Never use an invalid stats method.
2 |
3 | -- Reason
4 | /*The syntax for the gather_stats hints is:
5 | table_stats([<schema>.]<table> <method> [,] <keyword>=<value> [[,] <keyword>=<value>]...)
6 | Valid methods are:
7 |
8 | DEFAULT
9 | SET
10 | SCALE
11 | SAMPLE
12 |
13 | The Oracle Database treats other methods as a syntax error and will ignore the hint.
*/
14 |
15 | -- Bad
16 | select /*+ table_stats(emp faster rows=14) */ empno, ename
17 | from emp e
18 | where deptno = 20;
19 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
20 |
21 | /*
22 | ----------------------------------
23 | | Id | Operation | Name |
24 | ----------------------------------
25 | | 0 | SELECT STATEMENT | |
26 | | 1 | TABLE ACCESS FULL| EMP |
27 | ----------------------------------
28 |
29 | Hint Report (identified by operation id / Query Block Name / Object Alias):
30 | Total hints for statement: 1 (E - Syntax error (1))
31 | ---------------------------------------------------------------------------
32 |
33 | 1 - SEL$1
34 | E - table_stats
35 | */
36 |
37 | -- Good
38 | select /*+ table_stats(emp set rows=14) */ empno, ename
39 | from emp e
40 | where deptno = 20;
41 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
42 |
43 | /*
44 | ----------------------------------
45 | | Id | Operation | Name |
46 | ----------------------------------
47 | | 0 | SELECT STATEMENT | |
48 | | 1 | TABLE ACCESS FULL| EMP |
49 | ----------------------------------
50 |
51 | Hint Report (identified by operation id / Query Block Name / Object Alias):
52 | Total hints for statement: 1
53 | ---------------------------------------------------------------------------
54 |
55 | 0 - STATEMENT
56 | - table_stats(emp set rows=14)
57 | */
58 |
--------------------------------------------------------------------------------
/src/main/resources/TrivadisGuidelines3Plus/sample/guideline_9605.sql:
--------------------------------------------------------------------------------
1 | -- G-9605: Never use an invalid stats keyword.
2 |
3 | -- Reason
4 | /*The syntax for the gather_stats hints is:
5 | table_stats([<schema>.]<table> <method> [,] <keyword>=<value> [[,] <keyword>=<value>]...)
6 | Valid keywords are:
7 |
8 | ROWS
9 | BLOCKS
10 | ROW_LENGTH
11 |
12 | The Oracle Database treats other keywords as a syntax error and will ignore the hint.
*/
13 |
14 | -- Bad
15 | select /*+ table_stats(emp default rec=14 blk=1 rowlen=10) */ empno, ename
16 | from emp e
17 | where deptno = 20;
18 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
19 |
20 | /*
21 | ----------------------------------
22 | | Id | Operation | Name |
23 | ----------------------------------
24 | | 0 | SELECT STATEMENT | |
25 | | 1 | TABLE ACCESS FULL| EMP |
26 | ----------------------------------
27 |
28 | Hint Report (identified by operation id / Query Block Name / Object Alias):
29 | Total hints for statement: 1 (E - Syntax error (1))
30 | ---------------------------------------------------------------------------
31 |
32 | 1 - SEL$1
33 | E - table_stats
34 | */
35 |
36 | -- Good
37 | select /*+ table_stats(emp default rows=14 blocks=1 row_length=10) */ empno, ename
38 | from emp e
39 | where deptno = 20;
40 | select * from dbms_xplan.display_cursor(format => 'basic +hint_report');
41 |
42 | /*
43 | ----------------------------------
44 | | Id | Operation | Name |
45 | ----------------------------------
46 | | 0 | SELECT STATEMENT | |
47 | | 1 | TABLE ACCESS FULL| EMP |
48 | ----------------------------------
49 |
50 | Hint Report (identified by operation id / Query Block Name / Object Alias):
51 | Total hints for statement: 1
52 | ---------------------------------------------------------------------------
53 |
54 | 0 - STATEMENT
55 | - table_stats(emp set rows=14)
56 | */
57 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/AbstractValidatorTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.google.inject.Injector;
19 | import com.trivadis.oracle.plsql.PLSQLStandaloneSetup;
20 | import com.trivadis.oracle.plsql.validation.PLSQLCopGuideline;
21 | import com.trivadis.oracle.plsql.validation.PLSQLValidator;
22 | import com.trivadis.tvdcc.validators.TrivadisPlsqlNaming;
23 | import java.io.ByteArrayInputStream;
24 | import java.io.File;
25 | import java.io.IOException;
26 | import java.nio.charset.Charset;
27 | import java.nio.file.Files;
28 | import java.nio.file.Path;
29 | import java.nio.file.Paths;
30 | import java.nio.file.StandardCopyOption;
31 | import java.util.List;
32 |
33 | import org.eclipse.emf.common.util.EList;
34 | import org.eclipse.emf.common.util.URI;
35 | import org.eclipse.emf.ecore.resource.Resource;
36 | import org.eclipse.xtext.resource.XtextResource;
37 | import org.eclipse.xtext.resource.XtextResourceSet;
38 | import org.eclipse.xtext.validation.CheckMode;
39 | import org.eclipse.xtext.validation.Issue;
40 | import org.junit.AfterClass;
41 | import org.junit.BeforeClass;
42 | import org.junit.Test;
43 |
44 | import static org.hamcrest.MatcherAssert.assertThat;
45 | import static org.hamcrest.core.AnyOf.anyOf;
46 | import static org.hamcrest.core.StringStartsWith.startsWith;
47 |
48 | public abstract class AbstractValidatorTest {
49 | private static final String PROPERTIES_FILE_NAME = TrivadisPlsqlNaming.PROPERTIES_FILE_NAME;
50 | public static final String FULL_PROPERTIES_FILE_NAME = ((System.getProperty("user.home") + File.separator)
51 | + PROPERTIES_FILE_NAME);
52 | private static final String FULL_PROPERTIES_FILE_NAME_BACKUP = (FULL_PROPERTIES_FILE_NAME + ".backup");
53 |
54 | private final Injector injector = new PLSQLStandaloneSetup().createInjectorAndDoEMFRegistration();
55 |
56 | @BeforeClass
57 | public static void commonSetup() {
58 | stashPropertiesFile();
59 | }
60 |
61 | public static void stashPropertiesFile() {
62 | try {
63 | final Path file = Path.of(FULL_PROPERTIES_FILE_NAME);
64 | if (Files.exists(file)) {
65 | Files.copy(file, Paths.get(FULL_PROPERTIES_FILE_NAME_BACKUP));
66 | Files.delete(file);
67 | }
68 | } catch (IOException e) {
69 | throw new RuntimeException(e);
70 | }
71 | }
72 |
73 | @AfterClass
74 | public static void restorePropertiesFile() {
75 | try {
76 | final Path original = Path.of(FULL_PROPERTIES_FILE_NAME_BACKUP);
77 | final Path file = Path.of(FULL_PROPERTIES_FILE_NAME);
78 | if (Files.exists(original)) {
79 | Files.copy(original, file, StandardCopyOption.REPLACE_EXISTING);
80 | Files.delete(original);
81 | } else {
82 | if (Files.exists(file)) {
83 | Files.delete(file);
84 | }
85 | }
86 | } catch (IOException e) {
87 | throw new RuntimeException(e);
88 | }
89 | }
90 |
91 | @Test
92 | public void guidelineTitleStartsWithKeyword() {
93 | var guidelines = getValidator().getGuidelines().values().stream().filter(it -> it.getId() >= 9000).toList();
94 | for (final PLSQLCopGuideline g : guidelines) {
95 | assertThat('"' + g.getMsg() + "' does not start with keyword", g.getMsg(),
96 | anyOf(startsWith("Always"), startsWith("Never"), startsWith("Avoid"), startsWith("Try")));
97 | }
98 | }
99 |
100 | public XtextResource parse(String stmt) {
101 | final XtextResourceSet resourceSet = injector.getInstance(XtextResourceSet.class);
102 | resourceSet.addLoadOption(XtextResource.OPTION_RESOLVE_ALL, Boolean.TRUE);
103 | resourceSet.addLoadOption(XtextResource.OPTION_ENCODING, Charset.defaultCharset().name());
104 | final Resource resource = resourceSet.createResource(URI.createURI("dummy:/test.plsql"));
105 | final ByteArrayInputStream input = new ByteArrayInputStream(stmt.getBytes());
106 | try {
107 | resource.load(input, resourceSet.getLoadOptions());
108 | } catch (IOException e) {
109 | throw new RuntimeException(e);
110 | }
111 | return ((XtextResource) resource);
112 | }
113 |
114 | public List getIssues(String stmt) {
115 | final XtextResource resource = parse(stmt);
116 | final EList errors = resource.getErrors();
117 | if (errors.size() > 0) {
118 | final Resource.Diagnostic firstError = errors.get(0);
119 | throw new RuntimeException(
120 | "Syntax error: " + firstError.getMessage() + " at line " + firstError.getLine() + ".");
121 | }
122 | return resource.getResourceServiceProvider().getResourceValidator().validate(resource, CheckMode.ALL, null);
123 | }
124 |
125 | public PLSQLValidator getValidator() {
126 | return injector.getInstance(PLSQLValidator.class);
127 | }
128 | }
129 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/GLPTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.GLP;
20 |
21 | import org.junit.Assert;
22 | import org.junit.BeforeClass;
23 | import org.junit.Test;
24 |
25 | public class GLPTest extends AbstractValidatorTest {
26 |
27 | @BeforeClass
28 | public static void setupValidator() {
29 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(GLP.class);
30 | }
31 |
32 | @Test
33 | public void guidelines() {
34 | var guidelines = getValidator().getGuidelines();
35 | Assert.assertEquals(3, guidelines.values().stream().filter(it -> it.getId() >= 9000).count());
36 | }
37 |
38 | @Test
39 | public void procedureOk() {
40 | var stmt = """
41 | CREATE OR REPLACE PROCEDURE p (p_1 IN INTEGER, p_2 IN VARCHAR2) AS
42 | l_something INTEGER;
43 | BEGIN
44 | NULL;
45 | END p;
46 | """;
47 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().startsWith("G-9")).toList();
48 | Assert.assertEquals(0, issues.size());
49 | }
50 |
51 | @Test
52 | public void procedureNok() {
53 | var stmt = """
54 | CREATE OR REPLACE PROCEDURE p (a IN INTEGER, b IN VARCHAR2) AS
55 | c INTEGER;
56 | BEGIN
57 | NULL;
58 | END p;
59 | """;
60 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().startsWith("G-9")).toList();
61 | Assert.assertEquals(3, issues.size());
62 | // a
63 | var issue1 = issues.get(0);
64 | Assert.assertEquals(1, issue1.getLineNumber().intValue());
65 | Assert.assertEquals(32, issue1.getColumn().intValue());
66 | Assert.assertEquals(1, issue1.getLength().intValue());
67 | Assert.assertEquals("G-9003", issue1.getCode());
68 | Assert.assertEquals("G-9003: Always prefix parameters with 'p_'.", issue1.getMessage());
69 | Assert.assertEquals("a IN INTEGER", issue1.getData()[0]);
70 | // b
71 | var issue2 = issues.get(1);
72 | Assert.assertEquals(1, issue2.getLineNumber().intValue());
73 | Assert.assertEquals(46, issue2.getColumn().intValue());
74 | Assert.assertEquals(1, issue2.getLength().intValue());
75 | Assert.assertEquals("G-9003", issue2.getCode());
76 | Assert.assertEquals("G-9003: Always prefix parameters with 'p_'.", issue2.getMessage());
77 | Assert.assertEquals("b IN VARCHAR2", issue2.getData()[0]);
78 | // c
79 | var issue3 = issues.get(2);
80 | Assert.assertEquals(2, issue3.getLineNumber().intValue());
81 | Assert.assertEquals(4, issue3.getColumn().intValue());
82 | Assert.assertEquals(1, issue3.getLength().intValue());
83 | Assert.assertEquals("G-9002", issue3.getCode());
84 | Assert.assertEquals("G-9002: Always prefix local variables with 'l_'.", issue3.getMessage());
85 | Assert.assertEquals("c INTEGER;", issue3.getData()[0]);
86 | }
87 |
88 | @Test
89 | public void packageBodyOk() {
90 | var stmt = """
91 | CREATE OR REPLACE PACKAGE BODY pkg AS
92 | g_global_variable INTEGER;
93 |
94 | PROCEDURE p (
95 | p_parameter1 IN INTEGER,
96 | p_parameter2 IN VARCHAR2
97 | ) AS
98 | l_local_variable INTEGER;
99 | BEGIN
100 | NULL;
101 | END p;
102 |
103 | FUNCTION f (
104 | p_parameter1 IN INTEGER,
105 | p_parameter2 IN INTEGER
106 | ) RETURN INTEGER AS
107 | l_local_variable INTEGER;
108 | BEGIN
109 | RETURN p_parameter1 * p_parameter2;
110 | END f;
111 | END pkg;
112 | """;
113 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().startsWith("G-9")).toList();
114 | Assert.assertEquals(0, issues.size());
115 | }
116 |
117 | @Test
118 | public void packageBodyNok() {
119 | var stmt = """
120 | CREATE OR REPLACE PACKAGE BODY pkg AS
121 | global_variable INTEGER;
122 |
123 | PROCEDURE p (
124 | parameter1 IN INTEGER,
125 | parameter2 IN VARCHAR2
126 | ) AS
127 | local_variable INTEGER;
128 | BEGIN
129 | NULL;
130 | END p;
131 |
132 | FUNCTION f (
133 | parameter1 IN INTEGER,
134 | parameter2 IN INTEGER
135 | ) RETURN INTEGER AS
136 | local_variable INTEGER;
137 | BEGIN
138 | RETURN parameter1 * p_parameter2;
139 | END f;
140 | END pkg;
141 | """;
142 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().startsWith("G-9")).toList();
143 | Assert.assertEquals(7, issues.size());
144 | // global_variable
145 | var issue1 = issues.get(0);
146 | Assert.assertEquals(2, issue1.getLineNumber().intValue());
147 | Assert.assertEquals(4, issue1.getColumn().intValue());
148 | Assert.assertEquals(15, issue1.getLength().intValue());
149 | Assert.assertEquals("G-9001", issue1.getCode());
150 | Assert.assertEquals("G-9001: Always prefix global variables with 'g_'.", issue1.getMessage());
151 | Assert.assertEquals("global_variable INTEGER;", issue1.getData()[0]);
152 | }
153 | }
154 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/OverrideTrivadisGuidelinesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2019 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.OverrideTrivadisGuidelines;
20 | import org.junit.Assert;
21 | import org.junit.BeforeClass;
22 | import org.junit.Test;
23 |
24 | public class OverrideTrivadisGuidelinesTest extends AbstractValidatorTest {
25 |
26 | @BeforeClass
27 | public static void setupValidator() {
28 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(OverrideTrivadisGuidelines.class);
29 | }
30 |
31 | @Test
32 | public void literalInConstantDeclarationsIsOkay() {
33 | var stmt = """
34 | CREATE PACKAGE pkg AS
35 | co_templ CONSTANT VARCHAR2(4000 BYTE) := 'a text' || ' more text';
36 | END pkg;
37 | """;
38 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
39 | Assert.assertEquals(0, issues.size());
40 | }
41 |
42 | @Test
43 | public void literalInLoggerCallIsOkay() {
44 | var stmt = """
45 | BEGIN
46 | logger.log('Hello World');
47 | END;
48 | """;
49 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
50 | Assert.assertEquals(0, issues.size());
51 | }
52 |
53 | @Test
54 | public void literalInFunctionOfLoggerCallIsOkay() {
55 | var stmt = """
56 | BEGIN
57 | logger.log(upper('Hello World'));
58 | logger.log(upper('Hello World'));
59 | END;
60 | """;
61 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
62 | Assert.assertEquals(0, issues.size());
63 | }
64 |
65 | @Test
66 | public void literalInPackageFunctionOfLoggerCallIsOkay() {
67 | var stmt = """
68 | BEGIN
69 | logger.log(x.y('Hello World'));
70 | logger.log(x.y('Hello World'));
71 | END;
72 | """;
73 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
74 | Assert.assertEquals(0, issues.size());
75 | }
76 |
77 | @Test
78 | public void literalInDbmsOutputCallIsNotOkay() {
79 | var stmt = """
80 | BEGIN
81 | dbms_output.put_line('Hello World');
82 | dbms_output.put_line('Hello World');
83 | END;
84 | """;
85 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
86 | Assert.assertEquals(2, issues.size());
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/TrivadisGuidelines3PlusTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.TrivadisGuidelines3Plus;
20 | import org.junit.Assert;
21 | import org.junit.BeforeClass;
22 | import org.junit.Test;
23 |
24 | public class TrivadisGuidelines3PlusTest extends AbstractValidatorTest {
25 |
26 | @BeforeClass
27 | public static void setupValidator() {
28 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(TrivadisGuidelines3Plus.class);
29 | }
30 |
31 | @Test
32 | public void guidelines() {
33 | var guidelines = getValidator().getGuidelines();
34 | Assert.assertEquals(22, guidelines.values().stream().filter(it -> it.getId() >= 9100).toList().size()); // last guideline in v4.2 is G-9040
35 | Assert.assertEquals(125, guidelines.values().stream().filter(it -> it.getId() < 9100).toList().size()); // added G-3182, G-3183 in v4.3, added G-3330, G-4387 in v4.4
36 | Assert.assertEquals(79, guidelines.values().stream().filter(it -> it.getId() < 1000).toList().size());
37 | }
38 |
39 | @Test
40 | public void getGuidelineId_mapped_via_Trivadis2() {
41 | Assert.assertEquals("G-1010", getValidator().getGuidelineId(1));
42 | }
43 |
44 | @Test
45 | public void getGuidelineId_of_Trivadis3() {
46 | Assert.assertEquals("G-2130", getValidator().getGuidelineId(2130));
47 | }
48 |
49 | @Test
50 | public void getGuidelineMsg_mapped_via_Trivadis2() {
51 | Assert.assertEquals("G-1010: Try to label your sub blocks.", getValidator().getGuidelineMsg(1));
52 | }
53 |
54 | @Test
55 | public void getGuidelineMsg_mapped_via_Trivadis3() {
56 | Assert.assertEquals("G-2130: Try to use subtypes for constructs used often in your code.",
57 | getValidator().getGuidelineMsg(2130));
58 | }
59 |
60 | // issue avoided by OverrideTrivadisGuidelines (would throw an error via TrivadisGuidelines3)
61 | @Test
62 | public void literalInLoggerCallIsOkay() {
63 | var stmt = """
64 | BEGIN
65 | logger.log('Hello World');
66 | END;
67 | """;
68 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
69 | Assert.assertEquals(0, issues.size());
70 | }
71 |
72 | // issue thrown by OverrideTrivadisGuidelines (check in parent)
73 | @Test
74 | public void literalInDbmsOutputCallIsNotOkay() {
75 | var stmt = """
76 | BEGIN
77 | dbms_output.put_line('Hello World');
78 | dbms_output.put_line('Hello World');
79 | END;
80 | """;
81 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1050")).toList();
82 | Assert.assertEquals(2, issues.size());
83 | }
84 |
85 | // issue thrown by TrivadisGuidelines3
86 | @Test
87 | public void guideline2230_na() {
88 | var stmt = """
89 | CREATE OR REPLACE PACKAGE BODY constants_up IS
90 | co_big_increase CONSTANT NUMBER(5,0) := 1;
91 |
92 | FUNCTION big_increase RETURN NUMBER DETERMINISTIC IS
93 | BEGIN
94 | RETURN co_big_increase;
95 | END big_increase;
96 | END constants_up;
97 | /
98 | """;
99 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-2230")).toList();
100 | Assert.assertEquals(1, issues.size());
101 | }
102 |
103 | // issue thrown by TrivadisGuidelines2
104 | @Test
105 | public void guideline1010_10() {
106 | var stmt = """
107 | BEGIN
108 | BEGIN
109 | NULL;
110 | END;
111 | END;
112 | /
113 | """;
114 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-1010")).toList();
115 | Assert.assertEquals(1, issues.size());
116 | }
117 |
118 | // issue thrown by SQLInjection
119 | @Test
120 | public void executeImmediateNotAssertedVariable() {
121 | var stmt = """
122 | CREATE OR REPLACE PROCEDURE p (in_table_name IN VARCHAR2) AS
123 | co_templ CONSTANT VARCHAR2(4000 BYTE) := 'DROP TABLE #in_table_name# PURGE';
124 | l_table_name VARCHAR2(128 BYTE);
125 | l_sql VARCHAR2(4000 BYTE);
126 | BEGIN
127 | l_table_name := in_table_name;
128 | l_sql := replace(l_templ, '#in_table_name#', l_table_name);
129 | EXECUTE IMMEDIATE l_sql;
130 | END p;
131 | """;
132 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-9501")).toList();
133 | Assert.assertEquals(1, issues.size());
134 | }
135 |
136 | // issue thrown by TrivadisPlsqlNaming
137 | @Test
138 | public void globalVariableNok() {
139 | var stmt = """
140 | CREATE OR REPLACE PACKAGE example AS
141 | some_name INTEGER;
142 | END example;
143 | /
144 | """;
145 | var issues = getIssues(stmt);
146 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
147 | }
148 |
149 | // issue thrown by Hint
150 | @Test
151 | public void unknownHint() {
152 | var stmt = """
153 | INSERT /*+ NOLOGGING APPEND */ INTO sales_hist SELECT * FROM sales;
154 | """;
155 | var issues = getIssues(stmt);
156 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9601")).toList().size());
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/TrivadisPlsqlNamingPropertiesFileTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2020 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.TrivadisPlsqlNaming;
20 | import java.io.BufferedWriter;
21 | import java.io.File;
22 | import java.io.FileWriter;
23 | import java.io.IOException;
24 | import org.junit.Assert;
25 | import org.junit.BeforeClass;
26 | import org.junit.Test;
27 |
28 | public class TrivadisPlsqlNamingPropertiesFileTest extends AbstractValidatorTest {
29 |
30 | @BeforeClass
31 | public static void commonSetup() {
32 | stashPropertiesFile();
33 | createTestPropertiesFile();
34 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(TrivadisPlsqlNaming.class);
35 | }
36 |
37 | // create a simple properties file to test with
38 | public static void createTestPropertiesFile() {
39 | try {
40 | final File file = new File(FULL_PROPERTIES_FILE_NAME);
41 | final FileWriter fileWriter = new FileWriter(file, true);
42 | final BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
43 | bufferedWriter.write("REGEX_LOCAL_VARIABLE_NAME = ^loc_.+$");
44 | bufferedWriter.newLine();
45 | bufferedWriter.close();
46 | fileWriter.close();
47 | } catch (IOException e) {
48 | throw new RuntimeException(e);
49 | }
50 | }
51 |
52 | // check that old prefix is now not accepted
53 | @Test
54 | public void LocalVariableNok() {
55 | var stmt = """
56 | CREATE OR REPLACE PACKAGE BODY example AS
57 | PROCEDURE a IS
58 | l_some_name INTEGER;
59 | BEGIN
60 | NULL;
61 | END a;
62 | END example;
63 | """;
64 | var issues = getIssues(stmt);
65 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
66 | }
67 |
68 | // check that new prefix from file is accepted
69 | @Test
70 | public void LocalVariableOk() {
71 | var stmt = """
72 | CREATE OR REPLACE PACKAGE BODY example AS
73 | PROCEDURE a IS
74 | loc_some_name INTEGER;
75 | BEGIN
76 | NULL;
77 | END a;
78 | END example;
79 | """;
80 | var issues = getIssues(stmt);
81 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
82 | }
83 |
84 | // check that defaults are used if not specified in the properties-file
85 | @Test
86 | public void GlobalVariableNok() {
87 | var stmt = """
88 | CREATE OR REPLACE PACKAGE example AS
89 | some_name INTEGER;
90 | END example;
91 | /
92 | """;
93 | var issues = getIssues(stmt);
94 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
95 | }
96 |
97 | // check that defaults are used if not specified in the properties-file
98 | @Test
99 | public void GlobalVariableOk() {
100 | var stmt = """
101 | CREATE OR REPLACE PACKAGE example AS
102 | g_some_name INTEGER;
103 | END example;
104 | """;
105 | var issues = getIssues(stmt);
106 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/TrivadisPlsqlNamingSystemPropertiesTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2024 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.TrivadisPlsqlNaming;
20 | import java.io.File;
21 | import org.junit.Assert;
22 | import org.junit.BeforeClass;
23 | import org.junit.Test;
24 |
25 | public class TrivadisPlsqlNamingSystemPropertiesTest extends AbstractValidatorTest {
26 |
27 | @BeforeClass
28 | public static void commonSetup() {
29 | stashPropertiesFile();
30 | removePropertiesFile();
31 | System.getProperties().setProperty("REGEX_LOCAL_VARIABLE_NAME", "^local_.+$");
32 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(TrivadisPlsqlNaming.class);
33 | }
34 |
35 | // remove property file to ensure it cannot be read from the validator
36 | public static void removePropertiesFile() {
37 | final File file = new File(FULL_PROPERTIES_FILE_NAME);
38 | file.delete();
39 | }
40 |
41 | // check that old prefix is now not accepted
42 | @Test
43 | public void LocalVariableNok() {
44 | var stmt = """
45 | CREATE OR REPLACE PACKAGE BODY example AS
46 | PROCEDURE a IS
47 | l_some_name INTEGER;
48 | BEGIN
49 | NULL;
50 | END a;
51 | END example;
52 | """;
53 | var issues = getIssues(stmt);
54 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
55 | }
56 |
57 | // check that new prefix from file is accepted
58 | @Test
59 | public void LocalVariableOk() {
60 | var stmt = """
61 | CREATE OR REPLACE PACKAGE BODY example AS
62 | PROCEDURE a IS
63 | local_some_name INTEGER;
64 | BEGIN
65 | NULL;
66 | END a;
67 | END example;
68 | """;
69 | var issues = getIssues(stmt);
70 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
71 | }
72 |
73 | // check that defaults are used if not specified in the properties-file
74 | @Test
75 | public void GlobalVariableNok() {
76 | var stmt = """
77 | CREATE OR REPLACE PACKAGE example AS
78 | some_name INTEGER;
79 | END example;
80 | /
81 | """;
82 | var issues = getIssues(stmt);
83 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
84 | }
85 |
86 | // check that defaults are used if not specified in the properties-file
87 | @Test
88 | public void GlobalVariableOk() {
89 | var stmt = """
90 | CREATE OR REPLACE PACKAGE example AS
91 | g_some_name INTEGER;
92 | END example;
93 | """;
94 | var issues = getIssues(stmt);
95 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/test/java/com/trivadis/tvdcc/validators/tests/TrivadisPlsqlNamingTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2017 Philipp Salvisberg
3 | *
4 | * Licensed under the Creative Commons Attribution-NonCommercial-NoDerivs 3.0
5 | * Unported License (the "License"); you may not use this file except
6 | * in compliance with the License. You may obtain a copy of the License at
7 | *
8 | * https://creativecommons.org/licenses/by-nc-nd/3.0/
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package com.trivadis.tvdcc.validators.tests;
17 |
18 | import com.trivadis.oracle.plsql.validation.PLSQLValidatorPreferences;
19 | import com.trivadis.tvdcc.validators.TrivadisPlsqlNaming;
20 | import org.junit.Assert;
21 | import org.junit.BeforeClass;
22 | import org.junit.Test;
23 |
24 | public class TrivadisPlsqlNamingTest extends AbstractValidatorTest {
25 |
26 | @BeforeClass
27 | public static void setupValidator() {
28 | PLSQLValidatorPreferences.INSTANCE.setValidatorClass(TrivadisPlsqlNaming.class);
29 | }
30 |
31 | @Test
32 | public void globalVariableNok() {
33 | var stmt = """
34 | CREATE OR REPLACE PACKAGE example AS
35 | some_name INTEGER;
36 | END example;
37 | /
38 | """;
39 | var issues = getIssues(stmt);
40 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
41 | }
42 |
43 | @Test
44 | public void globalVariableOk() {
45 | var stmt = """
46 | CREATE OR REPLACE PACKAGE example AS
47 | g_some_name INTEGER;
48 | END example;
49 | """;
50 | var issues = getIssues(stmt);
51 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9101")).toList().size());
52 | }
53 |
54 | @Test
55 | public void localVariableNok() {
56 | var stmt = """
57 | CREATE OR REPLACE PACKAGE BODY example AS
58 | PROCEDURE a IS
59 | some_name INTEGER;
60 | BEGIN
61 | NULL;
62 | END a;
63 | END example;
64 | """;
65 | var issues = getIssues(stmt);
66 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
67 | }
68 |
69 | @Test
70 | public void localVariableOk() {
71 | var stmt = """
72 | CREATE OR REPLACE PACKAGE BODY example AS
73 | PROCEDURE a IS
74 | l_some_name INTEGER;
75 | BEGIN
76 | NULL;
77 | END a;
78 | END example;
79 | """;
80 | var issues = getIssues(stmt);
81 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
82 | }
83 |
84 | @Test
85 | public void localVariableForStrongCursorOk() {
86 | var stmt = """
87 | declare
88 | type c_emp_type is ref cursor return employees%rowtype;
89 | c_emp c_emp_type;
90 | r_emp employees%rowtype;
91 | begin
92 | open c_emp for select * from employees where employee_id = 100;
93 | fetch c_emp into r_emp;
94 | close c_emp;
95 | sys.dbms_output.put_line('first_name: ' || r_emp.first_name);
96 | end;
97 | """;
98 | var issues = getIssues(stmt);
99 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
100 | }
101 |
102 | @Test
103 | public void localVariableForObjectOk() {
104 | var stmt = """
105 | declare
106 | o_game game_ot;
107 | begin
108 | o_game := game_ot();
109 | pkg.proc(o_game);
110 | end;
111 | """;
112 | var issues = getIssues(stmt);
113 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
114 | }
115 |
116 | @Test
117 | public void localVariableForArrayOk() {
118 | var stmt = """
119 | declare
120 | t_words word_ct;
121 | begin
122 | t_words := word_ct();
123 | pkg.proc(t_words);
124 | end;
125 | """;
126 | var issues = getIssues(stmt);
127 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
128 | }
129 |
130 | @Test
131 | public void localVariableSingleLetterIOk() {
132 | // use as common index "i" is accepted
133 | var stmt = """
134 | declare
135 | i pls_integer := 0;
136 | begin
137 | while i < 10
138 | loop
139 | dbms_output.put_line(i);
140 | i := i + 1;
141 | end loop;
142 | end;
143 | """;
144 | var issues = getIssues(stmt);
145 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
146 | }
147 |
148 | @Test
149 | public void localVariableSingleLetterJOk() {
150 | // use as common index "j" is accepted
151 | var stmt = """
152 | declare
153 | j pls_integer := 0;
154 | begin
155 | while j < 10
156 | loop
157 | dbms_output.put_line(j);
158 | j := j + 1;
159 | end loop;
160 | end;
161 | """;
162 | var issues = getIssues(stmt);
163 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9102")).toList().size());
164 | }
165 |
166 | @Test
167 | public void cursorNameNok() {
168 | var stmt = """
169 | DECLARE
170 | CURSOR some_name IS SELECT * FROM emp;
171 | BEGIN
172 | NULL;
173 | END;
174 | """;
175 | var issues = getIssues(stmt);
176 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9103")).toList().size());
177 | }
178 |
179 | @Test
180 | public void cursorNameOk() {
181 | var stmt = """
182 | DECLARE
183 | CURSOR c_some_name IS SELECT * FROM emp;
184 | BEGIN
185 | NULL;
186 | END;
187 | """;
188 | var issues = getIssues(stmt);
189 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9103")).toList().size());
190 | }
191 |
192 | @Test
193 | public void sysrefcursorNameNOk_bug5() {
194 | var stmt = """
195 | DECLARE
196 | l_dept SYS_REFCURSOR;
197 | BEGIN
198 | NULL;
199 | END;
200 | /
201 | """;
202 | var issues = getIssues(stmt);
203 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9103")).toList().size());
204 | }
205 |
206 | @Test
207 | public void sysrefcursorNameOk_bug5() {
208 | var stmt = """
209 | DECLARE
210 | c_dept SYS_REFCURSOR;
211 | BEGIN
212 | NULL;
213 | END;
214 | /
215 | """;
216 | var issues = getIssues(stmt);
217 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9103")).toList().size());
218 | }
219 |
220 | @Test
221 | public void recordNameNok() {
222 | var stmt = """
223 | DECLARE
224 | emp emp%ROWTYPE;
225 | TYPE r_dept_type IS RECORD (
226 | deptno NUMBER,
227 | dname VARCHAR2(14 CHAR),
228 | loc LOC(13 CHAR)
229 | );
230 | dept r_dept_type;
231 | BEGIN
232 | NULL;
233 | END;
234 | """;
235 | var issues = getIssues(stmt);
236 | Assert.assertEquals(2, issues.stream().filter(it -> it.getCode().equals("G-9104")).toList().size());
237 | }
238 |
239 | @Test
240 | public void recordNameOk() {
241 | var stmt = """
242 | DECLARE
243 | r_emp emp%ROWTYPE;
244 | TYPE r_dept_type IS RECORD (
245 | deptno NUMBER,
246 | dname VARCHAR2(14 CHAR),
247 | loc LOC(13 CHAR)
248 | );
249 | r_dept r_dept_type;
250 | BEGIN
251 | NULL;
252 | END;
253 | """;
254 | var issues = getIssues(stmt);
255 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9104")).toList().size());
256 | }
257 |
258 | @Test
259 | public void arrayNameNok() {
260 | var stmt = """
261 | DECLARE
262 | TYPE t_varray_type IS VARRAY(10) OF STRING;
263 | array1 t_varray_type;
264 | TYPE t_nested_table_type IS TABLE OF STRING;
265 | array2 t_nested_table_type;
266 | TYPE t_assoc_array_type IS TABLE OF STRING INDEX BY PLS_INTEGER;
267 | array3 t_assoc_array_type;
268 | BEGIN
269 | NULL;
270 | END;
271 | """;
272 | var issues = getIssues(stmt);
273 | Assert.assertEquals(3, issues.stream().filter(it -> it.getCode().equals("G-9105")).toList().size());
274 | }
275 |
276 | @Test
277 | public void arrayNameOk() {
278 | var stmt = """
279 | DECLARE
280 | TYPE t_varray_type IS VARRAY(10) OF STRING;
281 | t_array1 t_varray_type;
282 | TYPE t_nested_table_type IS TABLE OF STRING;
283 | t_array2 t_nested_table_type;
284 | TYPE t_assoc_array_type IS TABLE OF STRING INDEX BY PLS_INTEGER;
285 | t_array3 t_assoc_array_type;
286 | BEGIN
287 | NULL;
288 | END;
289 | """;
290 | var issues = getIssues(stmt);
291 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9105")).toList().size());
292 | }
293 |
294 | @Test
295 | public void objectNameNok() {
296 | var stmt = """
297 | CREATE OR REPLACE TYPE dept_type AS OBJECT (
298 | deptno INTEGER,
299 | dname VARCHAR2(14 CHAR),
300 | loc VARCHAR2(13 CHAR)
301 | );
302 |
303 | DECLARE
304 | dept dept_type;
305 | BEGIN
306 | NULL;
307 | END;
308 | """;
309 | var issues = getIssues(stmt);
310 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9106")).toList().size());
311 | }
312 |
313 | @Test
314 | public void objectNameOk() {
315 | var stmt = """
316 | CREATE OR REPLACE TYPE dept_type AS OBJECT (
317 | deptno INTEGER,
318 | dname VARCHAR2(14 CHAR),
319 | loc VARCHAR2(13 CHAR)
320 | );
321 |
322 | DECLARE
323 | o_dept dept_type;
324 | BEGIN
325 | NULL;
326 | END;
327 | """;
328 | var issues = getIssues(stmt);
329 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9106")).toList().size());
330 | }
331 |
332 | @Test
333 | public void cursorParameterNameNok() {
334 | var stmt = """
335 | DECLARE
336 | CURSOR c_emp (x_ename IN VARCHAR2) IS
337 | SELECT *
338 | FROM emp
339 | WHERE ename LIKE x_ename;
340 | BEGIN
341 | NULL;
342 | END;
343 | """;
344 | var issues = getIssues(stmt);
345 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9107")).toList().size());
346 | }
347 |
348 | @Test
349 | public void cursorParameterNameOk() {
350 | var stmt = """
351 | DECLARE
352 | CURSOR c_emp (p_ename IN VARCHAR2) IS
353 | SELECT *
354 | FROM emp
355 | WHERE ename LIKE p_ename;
356 | BEGIN
357 | NULL;
358 | END;
359 | """;
360 | var issues = getIssues(stmt);
361 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9107")).toList().size());
362 | }
363 |
364 | @Test
365 | public void inParameterNameNok() {
366 | var stmt = """
367 | CREATE PROCEDURE p1 (param INTEGER) IS
368 | BEGIN
369 | NULL;
370 | END p1;
371 |
372 | CREATE PACKAGE p IS
373 | PROCEDURE p2 (param IN INTEGER);
374 | END p;
375 | """;
376 | var issues = getIssues(stmt);
377 | Assert.assertEquals(2, issues.stream().filter(it -> it.getCode().equals("G-9108")).toList().size());
378 | }
379 |
380 | @Test
381 | public void inParameterNameOk() {
382 | var stmt = """
383 | CREATE PROCEDURE p1 (in_param INTEGER) IS
384 | BEGIN
385 | NULL;
386 | END p1;
387 |
388 | CREATE PACKAGE p IS
389 | PROCEDURE p2 (in_param IN INTEGER);
390 | END p;
391 | """;
392 | var issues = getIssues(stmt);
393 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9108")).toList().size());
394 | }
395 |
396 | @Test
397 | public void SelfInParameterNameOk() {
398 | var stmt = """
399 | CREATE OR REPLACE TYPE rectangle AUTHID definer AS OBJECT (
400 | rect_length NUMBER,
401 | rect_width NUMBER,
402 | member FUNCTION get_surface (
403 | self IN rectangle
404 | ) RETURN NUMBER
405 | );
406 | """;
407 | var issues = getIssues(stmt);
408 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9108")).toList().size());
409 | }
410 |
411 | @Test
412 | public void outParameterNameNok() {
413 | var stmt = """
414 | CREATE PROCEDURE p1 (param OUT INTEGER) IS
415 | BEGIN
416 | NULL;
417 | END p1;
418 |
419 | CREATE PACKAGE p IS
420 | PROCEDURE p2 (param OUT INTEGER);
421 | END p;
422 | """;
423 | var issues = getIssues(stmt);
424 | Assert.assertEquals(2, issues.stream().filter(it -> it.getCode().equals("G-9109")).toList().size());
425 | }
426 |
427 | @Test
428 | public void outParameterNameOk() {
429 | var stmt = """
430 | CREATE PROCEDURE p1 (out_param OUT INTEGER) IS
431 | BEGIN
432 | NULL;
433 | END p1;
434 |
435 | CREATE PACKAGE p IS
436 | PROCEDURE p2 (out_param OUT INTEGER);
437 | END p;
438 | """;
439 | var issues = getIssues(stmt);
440 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9109")).toList().size());
441 | }
442 |
443 | @Test
444 | public void inOutParameterNameNok() {
445 | var stmt = """
446 | CREATE PROCEDURE p1 (param IN OUT INTEGER) IS
447 | BEGIN
448 | NULL;
449 | END p1;
450 |
451 | CREATE PACKAGE p IS
452 | PROCEDURE p2 (param IN OUT INTEGER);
453 | END p;
454 | """;
455 | var issues = getIssues(stmt);
456 | Assert.assertEquals(2, issues.stream().filter(it -> it.getCode().equals("G-9110")).toList().size());
457 | }
458 |
459 | @Test
460 | public void inOutParameterNameOk() {
461 | var stmt = """
462 | CREATE PROCEDURE p1 (io_param IN OUT INTEGER) IS
463 | BEGIN
464 | NULL;
465 | END p1;
466 |
467 | CREATE PACKAGE p IS
468 | PROCEDURE p2 (io_param IN OUT INTEGER);
469 | END p;
470 | """;
471 | var issues = getIssues(stmt);
472 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9110")).toList().size());
473 | }
474 |
475 | @Test
476 | public void SelfInOutParameterNameOk() {
477 | var stmt = """
478 | CREATE OR REPLACE TYPE rectangle AUTHID definer AS OBJECT (
479 | rect_length NUMBER,
480 | rect_width NUMBER,
481 | CONSTRUCTOR FUNCTION rectangle (
482 | self IN OUT NOCOPY rectangle,
483 | in_length_and_width IN NUMBER
484 | ) RETURN SELF AS RESULT
485 | );
486 | """;
487 | var issues = getIssues(stmt);
488 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9110")).toList().size());
489 | }
490 |
491 | @Test
492 | public void recordTypeNameNok() {
493 | var stmt = """
494 | DECLARE
495 | TYPE dept_typ IS RECORD (
496 | deptno NUMBER,
497 | dname VARCHAR2(14 CHAR),
498 | loc LOC(13 CHAR)
499 | );
500 | BEGIN
501 | NULL;
502 | END;
503 | """;
504 | var issues = getIssues(stmt);
505 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9111")).toList().size());
506 | }
507 |
508 | @Test
509 | public void recordTypeNameOk() {
510 | var stmt = """
511 | DECLARE
512 | TYPE r_dept_type IS RECORD (
513 | deptno NUMBER,
514 | dname VARCHAR2(14 CHAR),
515 | loc LOC(13 CHAR)
516 | );
517 | BEGIN
518 | NULL;
519 | END;
520 | """;
521 | var issues = getIssues(stmt);
522 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9111")).toList().size());
523 | }
524 |
525 | @Test
526 | public void arrayTypeNameNok() {
527 | var stmt = """
528 | DECLARE
529 | TYPE t_varray IS VARRAY(10) OF STRING;
530 | TYPE nested_table_type IS TABLE OF STRING;
531 | TYPE x_assoc_array_y IS TABLE OF STRING INDEX BY PLS_INTEGER;
532 | BEGIN
533 | NULL;
534 | END;
535 | """;
536 | var issues = getIssues(stmt);
537 | Assert.assertEquals(3, issues.stream().filter(it -> it.getCode().equals("G-9112")).toList().size());
538 | }
539 |
540 | @Test
541 | public void arrayTypeNameOk() {
542 | var stmt = """
543 | DECLARE
544 | TYPE t_varray_type IS VARRAY(10) OF STRING;
545 | TYPE t_nested_table_type IS TABLE OF STRING;
546 | TYPE t_assoc_array_type IS TABLE OF STRING INDEX BY PLS_INTEGER;
547 | BEGIN
548 | NULL;
549 | END;
550 | """;
551 | var issues = getIssues(stmt);
552 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9112")).toList().size());
553 |
554 | }
555 |
556 | @Test
557 | public void exceptionNameNok() {
558 | var stmt = """
559 | DECLARE
560 | some_name EXCEPTION;
561 | BEGIN
562 | NULL;
563 | END;
564 | """;
565 | var issues = getIssues(stmt);
566 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9113")).toList().size());
567 | }
568 |
569 | @Test
570 | public void exceptionNameOk() {
571 | var stmt = """
572 | DECLARE
573 | e_some_name EXCEPTION;
574 | BEGIN
575 | NULL;
576 | END;
577 | """;
578 | var issues = getIssues(stmt);
579 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9113")).toList().size());
580 | }
581 |
582 | @Test
583 | public void constantNameNok() {
584 | var stmt = """
585 | DECLARE
586 | maximum CONSTANT INTEGER := 1000;
587 | BEGIN
588 | NULL;
589 | END;
590 | """;
591 | var issues = getIssues(stmt);
592 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9114")).toList().size());
593 | }
594 |
595 | @Test
596 | public void constantNameOk() {
597 | var stmt = """
598 | DECLARE
599 | co_maximum CONSTANT INTEGER := 1000;
600 | BEGIN
601 | NULL;
602 | END;
603 | """;
604 | var issues = getIssues(stmt);
605 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9114")).toList().size());
606 | }
607 |
608 | @Test
609 | public void subtypeNameNok() {
610 | var stmt = """
611 | DECLARE
612 | SUBTYPE short_text IS VARCHAR2(100 CHAR);
613 | BEGIN
614 | NULL;
615 | END;
616 | """;
617 | var issues = getIssues(stmt);
618 | Assert.assertEquals(1, issues.stream().filter(it -> it.getCode().equals("G-9115")).toList().size());
619 | }
620 |
621 | @Test
622 | public void subtypeNameOk() {
623 | var stmt = """
624 | DECLARE
625 | SUBTYPE short_text_type IS VARCHAR2(100 CHAR);
626 | BEGIN
627 | NULL;
628 | END;
629 | """;
630 | var issues = getIssues(stmt);
631 | Assert.assertEquals(0, issues.stream().filter(it -> it.getCode().equals("G-9115")).toList().size());
632 | }
633 |
634 | // issue 62 https://github.com/Trivadis/plsql-cop-validators/issues/62
635 |
636 | @Test
637 | public void ignorelocalVariableInBasicLoopExitCondition() {
638 | var stmt = """
639 | declare
640 | a integer := 0; -- violates G-2185, not used in while loop condition nor exit condition, violates G-9102
641 | b integer; -- does not violate G-2185, used in exit condition, violates G-9102
642 | begin
643 | <>
644 | loop
645 | b := a;
646 | exit demo when b = 10;
647 | a := a + 1;
648 | end loop demo;
649 | end;
650 | /
651 | """;
652 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-9102")).toList();
653 | Assert.assertEquals(1, issues.size());
654 | Assert.assertEquals(2, issues.get(0).getLineNumber().intValue());
655 | }
656 |
657 | @Test
658 | public void ignorelocalVariableInWhileLoopCondition() {
659 | var stmt = """
660 | declare
661 | a pls_integer := 0;
662 | b integer;
663 | begin
664 | while a < 10
665 | loop
666 | b := a;
667 | dbms_output.put_line(b);
668 | a := a + 1;
669 | end loop;
670 | end;
671 | """;
672 | var issues = getIssues(stmt).stream().filter(it -> it.getCode().equals("G-9102")).toList();
673 | Assert.assertEquals(1, issues.size());
674 | Assert.assertEquals(3, issues.get(0).getLineNumber().intValue());
675 | }
676 |
677 | }
678 |
--------------------------------------------------------------------------------