|
1 | 1 | /* |
2 | | - * Copyright (c) 2015-2023 Tada AB and other contributors, as listed below. |
| 2 | + * Copyright (c) 2015-2025 Tada AB and other contributors, as listed below. |
3 | 3 | * |
4 | 4 | * All rights reserved. This program and the accompanying materials |
5 | 5 | * are made available under the terms of the The BSD 3-Clause License |
|
13 | 13 | /** |
14 | 14 | * Annotations for use in Java code to generate the SQLJ Deployment Descriptor |
15 | 15 | * automatically. |
| 16 | + * <h2>Eliminating error-prone hand-maintained SQL scripts</h2> |
16 | 17 | * <p> |
17 | 18 | * To define functions or types in PL/Java requires more than one step. The |
18 | 19 | * Java code must be written, compiled to a jar, and made available to the |
|
22 | 23 | * version that undoes it when uninstalling the jar) can be written in a |
23 | 24 | * prescribed form and stored inside the jar itself as an "SQLJ Deployment |
24 | 25 | * Descriptor", and processed automatically when the jar is installed in or |
25 | | - * removed from the backend. |
| 26 | + * removed from the DBMS. |
26 | 27 | * <p> |
27 | 28 | * To write the deployment descriptor by hand can be tedious and error-prone, |
28 | 29 | * as it must largely duplicate the method and type declarations in the |
29 | 30 | * Java code, but using SQL's syntax and types in place of Java's. Instead, |
30 | 31 | * when the annotations in this package are used in the Java code, the Java |
31 | | - * compiler itself will generate a deployment descriptor file, ready to include |
32 | | - * with the compiled classes to make a complete SQLJ jar. |
| 32 | + * compiler itself will generate a deployment descriptor (DDR) file, ready to |
| 33 | + * include with the compiled classes to make a complete SQLJ jar. |
33 | 34 | * <p> |
34 | 35 | * Automatic descriptor generation requires attention to a few things. |
35 | 36 | * <ul> |
36 | 37 | * <li>The {@code pljava-api} jar must be on the Java compiler's class path. |
37 | 38 | * (All but the simplest PL/Java functions probably refer to some class in |
38 | 39 | * PL/Java's API anyway, in which case the jar would already have to be on |
39 | 40 | * the class path.) |
| 41 | + * <li>Java compilers older than Java 23 will automatically find and use |
| 42 | + * PL/Java's DDR processor as long as the {@code pljava-api} jar is on the class |
| 43 | + * path. Starting in Java 23, the compiler will not do so automatically, and a |
| 44 | + * {@code -processor org.postgresql.pljava.annotation.processing.DDRProcessor} |
| 45 | + * option is also needed on the {@code javac} command line. (Warnings about this |
| 46 | + * are issued starting in Java 21, though the processor is still used |
| 47 | + * automatically, with the warnings, until Java 23.) |
40 | 48 | * <li>When recompiling after changing only a few sources, it is possible the |
41 | 49 | * Java compiler will only process a subset of the source files containing |
42 | 50 | * annotations. If so, it may generate an incomplete deployment descriptor, |
43 | 51 | * and a clean build may be required to ensure the complete descriptor is |
44 | 52 | * written. |
45 | | - * <li>Additional options are available when invoking the Java compiler, and |
46 | | - * can be specified with <code>-Aoption=value</code> on the command line: |
| 53 | + * </ul> |
| 54 | + * <h2>New compiler options when generating the deployment descriptor</h2> |
| 55 | + * <p>Additional options are available when invoking the Java compiler, and |
| 56 | + * can be specified with {@code -Aoption=value} on the command line: |
47 | 57 | * <dl> |
48 | | - * <dt><code>ddr.output</code> |
| 58 | + * <dt>{@code ddr.output} |
49 | 59 | * <dd>The file name to be used for the generated deployment descriptor. |
50 | 60 | * If not specified, the file will be named <code>pljava.ddr</code> and found |
51 | 61 | * in the top directory of the tree where the compiled class files are written. |
52 | | - * <dt><code>ddr.name.trusted</code> |
| 62 | + * <dt>{@code ddr.name.trusted} |
53 | 63 | * <dd>The language name that will be used to declare methods that are |
54 | 64 | * annotated to have {@link org.postgresql.pljava.annotation.Function.Trust#SANDBOXED} behavior. If not |
55 | | - * specified, the name <code>java</code> will be used. It must match the name |
| 65 | + * specified, the name {@code java} will be used. It must match the name |
56 | 66 | * used for the "trusted" language declaration when PL/Java was installed. |
57 | | - * <dt><code>ddr.name.untrusted</code> |
| 67 | + * <dt>{@code ddr.name.untrusted} |
58 | 68 | * <dd>The language name that will be used to declare methods that are |
59 | 69 | * annotated to have {@link org.postgresql.pljava.annotation.Function.Trust#UNSANDBOXED} behavior. If not |
60 | | - * specified, the name <code>javaU</code> will be used. It must match the name |
| 70 | + * specified, the name {@code javaU} will be used. It must match the name |
61 | 71 | * used for the "untrusted" language declaration when PL/Java was installed. |
62 | | - * <dt><code>ddr.implementor</code> |
| 72 | + * <dt>{@code ddr.implementor} |
63 | 73 | * <dd>The identifier (defaulting to {@code PostgreSQL} if not specified here) |
64 | 74 | * that will be used in the {@code <implementor block>}s wrapping any SQL |
65 | 75 | * generated from elements that do not specify their own. If this is set to a |
66 | 76 | * single hyphen (-), elements that specify no implementor will produce plain |
67 | 77 | * {@code <SQL statement>}s not wrapped in {@code <implementor block>}s. |
68 | | - * <dt><code>ddr.reproducible</code> |
| 78 | + * <dt>{@code ddr.reproducible} |
69 | 79 | * <dd>When {@code true} (the default), SQL statements are written to the |
70 | 80 | * deployment descriptor in an order meant to be consistent across successive |
71 | 81 | * compilations of the same sources. This option is further discussed below. |
72 | 82 | * </dl> |
73 | | - * <li>The deployment descriptor may contain statements that cannot succeed if |
| 83 | + * <h2>Controlling order of statements in the deployment descriptor</h2> |
| 84 | + * <p>The deployment descriptor may contain statements that cannot succeed if |
74 | 85 | * placed in the wrong order, and to keep a manually-edited script in a workable |
75 | 86 | * order while adding and modifying code can be difficult. Most of the |
76 | 87 | * annotations in this package accept arbitrary {@code requires} and |
|
80 | 91 | * compiler, except that it will make sure not to write anything that |
81 | 92 | * {@code requires} some string <em>X</em> into the generated script |
82 | 93 | * before whatever {@code provides} it. |
83 | | - * <li>There can be multiple ways to order the statements in the deployment |
| 94 | + * <h3>Effect of {@code ddr.reproducible}</h3> |
| 95 | + * <p>There can be multiple ways to order the statements in the deployment |
84 | 96 | * descriptor to satisfy the given {@code provides} and {@code requires} |
85 | 97 | * relationships. While the compiler will always write the descriptor in an |
86 | 98 | * order that satisfies those relationships, when the {@code ddr.reproducible} |
87 | 99 | * option is {@code false}, the precise order may differ between successive |
88 | | - * compilations of the same sources, which <em>should</em> not affect successful |
| 100 | + * compilations of the same sources, which <em>should not</em> affect successful |
89 | 101 | * loading and unloading of the jar with {@code install_jar} and |
90 | 102 | * {@code remove_jar}. In testing, this can help to confirm that all of the |
91 | 103 | * needed {@code provides} and {@code requires} relationships have been |
|
94 | 106 | * orders, chosen arbitrarily but consistently between multiple compilations as |
95 | 107 | * long as the sources are unchanged. This can be helpful in software |
96 | 108 | * distribution when reproducible output is wanted. |
| 109 | + * <h2>Conditional execution in the deployment descriptor</h2> |
| 110 | + * <p>The deployment-descriptor syntax fixed by the ISO SQL/JRT standard has |
| 111 | + * a rudimentary conditional-inclusion feature based on |
| 112 | + * {@code <implementor block>}s. |
| 113 | + * SQL statements wrapped in {@code BEGIN}/{@code END} with an |
| 114 | + * {@code <implementor name>} are executed only if that name is recognized |
| 115 | + * by the DBMS when installing or removing the jar. Statements in the deployment |
| 116 | + * descriptor that are not wrapped in an {@code <implementor block>} are |
| 117 | + * executed unconditionally. |
| 118 | + * <p>PL/Java's descriptor generator normally emits statements |
| 119 | + * as {@code <implementor block>}s, using the name {@code PostgreSQL} |
| 120 | + * (or the value of the {@code ddr.implementor} option if present on |
| 121 | + * the compiler command line) by default, or a specific name supplied |
| 122 | + * with {@code implementor=} to one of the annotations in this package. |
| 123 | + * <p>When loading or unloading a jar file and processing its deployment |
| 124 | + * descriptor, PL/Java 'recognizes' any implementor name listed in the runtime |
| 125 | + * setting {@code pljava.implementors}, which contains only {@code PostgreSQL} |
| 126 | + * by default. |
| 127 | + * <p>The {@code pljava.implementors} setting can be changed, even by SQL |
| 128 | + * statements within a deployment descriptor, to affect which subsequent |
| 129 | + * statements will be executed. An SQL statement may test some condition and |
| 130 | + * set {@code pljava.implementors} accordingly. In PL/Java's supplied examples, |
| 131 | + * <a href= |
| 132 | + "https://github.com/tada/pljava/blob/REL1_6_STABLE/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/ConditionalDDR.java" |
| 133 | + >ConditionalDDR</a> illustrates this approach to conditional execution. |
| 134 | + * <p>Naturally, this scheme requires the SQL generator to emit the statement |
| 135 | + * that tests the condition earlier in the deployment descriptor than |
| 136 | + * the statements relying on the {@code <implementor name>} being set. |
| 137 | + * Building on the existing ability to control the order of statements |
| 138 | + * using {@code provides} and {@code requires} elements, an {@code implementor} |
| 139 | + * element specified in the annotation for a statement is treated also as |
| 140 | + * an implicit {@code requires} for that name, so the programmer only needs |
| 141 | + * to place an explicit {@code provides} element on whatever |
| 142 | + * {@link SQLAction SQLAction} tests the condition and determines if the name |
| 143 | + * will be recognized. |
| 144 | + * <p>The {@code provides}/{@code requires} relationship so created differs |
| 145 | + * in three ways from other {@code provides}/{@code requires} relationships: |
| 146 | + * <ul> |
| 147 | + * <li>It does not reverse for generating {@code remove} actions. |
| 148 | + * Normal dependencies must be reversed for that case, so dependent objects |
| 149 | + * are removed before those they depend on. By contrast, a condition determining |
| 150 | + * the setting of an implementor name must be evaluated before the name |
| 151 | + * is needed, whether the jar is being installed or removed. |
| 152 | + * <li>If it does not have an explicit {@code remove} action (the usual case), |
| 153 | + * its {@code install} action (the condition test and setting of the name) |
| 154 | + * is used both when installing and removing. |
| 155 | + * <li>It is weak. The SQL generator does not flag an error if the implicit |
| 156 | + * {@code requires} for an implementor name is not satisfied by any annotation's |
| 157 | + * {@code provides} in the visible Java sources. It is possible the name may be |
| 158 | + * set some other way in the DBMS environment where the jar is to be deployed. |
| 159 | + * Faced with statements that require such 'unprovided' implementor names, |
| 160 | + * the SQL generator just falls back to emitting them as late in the deployment |
| 161 | + * descriptor as possible, after all other statements that do not depend |
| 162 | + * on them. |
97 | 163 | * </ul> |
| 164 | + * <h3>Matching {@code implementor} and {@code provides}</h3> |
| 165 | + * <p>Given the 'weak' nature of the {@code implementor}/{@code provides} |
| 166 | + * relationship, an error will not be reported if a spelling or upper/lower case |
| 167 | + * difference prevents identifying an {@code <implementor name>} with the |
| 168 | + * {@code provides} string of an annotated statement intended to match it. |
| 169 | + * The resulting deployment descriptor may have a workable order |
| 170 | + * as a result of the fallback ordering rules, or may have a mysteriously |
| 171 | + * unworkable order, particularly of the {@code remove} actions. |
| 172 | + * <p>According to the ISO SQL/JRT standard, an {@code <implementor name>} is |
| 173 | + * an SQL identifier, having a case-insensitive matching behavior unless quoted. |
| 174 | + * PL/Java, however, treats a {@code provides} value as an arbitrary Java string |
| 175 | + * that can only match exactly, and so PL/Java's SQL generator will successfully |
| 176 | + * match up {@code implementor} and {@code provides} strings <em>only when |
| 177 | + * they are identical in spelling and case</em>. |
98 | 178 | */ |
99 | 179 | package org.postgresql.pljava.annotation; |
0 commit comments