diff --git a/.travis.yml b/.travis.yml
index ab9964768..c6403a367 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -250,6 +250,22 @@ script: |
// state 9: must be end of input
(o,p,q) -> null == o
);
+
+ /*
+ * Also confirm that the generated undeploy actions work.
+ */
+ succeeding &= stateMachine(
+ "remove jar void result",
+ null,
+
+ q(c, "SELECT sqlj.remove_jar('examples', true)")
+ .flatMap(Node::semiFlattenDiagnostics)
+ .peek(Node::peek),
+
+ (o,p,q) -> isDiagnostic(o, Set.of("error")) ? 1 : -2,
+ (o,p,q) -> isVoidResultSet(o, 1, 1) ? 3 : false,
+ (o,p,q) -> null == o
+ );
}
} catch ( Throwable t )
{
diff --git a/appveyor.yml b/appveyor.yml
index 8fab11664..ca13103dd 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -188,6 +188,22 @@ test_script:
// state 9: must be end of input
(o,p,q) -> null == o
);
+
+ /*
+ * Also confirm that the generated undeploy actions work.
+ */
+ succeeding &= stateMachine(
+ "remove jar void result",
+ null,
+
+ q(c, "SELECT sqlj.remove_jar('examples', true)")
+ .flatMap(Node::semiFlattenDiagnostics)
+ .peek(Node::peek),
+
+ (o,p,q) -> isDiagnostic(o, Set.of("error")) ? 1 : -2,
+ (o,p,q) -> isVoidResultSet(o, 1, 1) ? 3 : false,
+ (o,p,q) -> null == o
+ );
}
} catch ( Throwable t )
{
diff --git a/pljava-api/src/main/java/org/postgresql/pljava/annotation/Cast.java b/pljava-api/src/main/java/org/postgresql/pljava/annotation/Cast.java
new file mode 100644
index 000000000..140993f85
--- /dev/null
+++ b/pljava-api/src/main/java/org/postgresql/pljava/annotation/Cast.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2020 Tada AB and other contributors, as listed below.
+ *
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the The BSD 3-Clause License
+ * which accompanies this distribution, and is available at
+ * http://opensource.org/licenses/BSD-3-Clause
+ *
+ * Contributors:
+ * Chapman Flack
+ */
+package org.postgresql.pljava.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Declares a PostgreSQL {@code CAST}.
+ *
+ * May annotate a Java method (which should also carry a
+ * {@link Function @Function} annotation, making it a PostgreSQL function),
+ * or a class or interface (just to have a place to put it when not directly
+ * associated with a method).
+ *
+ * If not applied to a method, must supply {@code path=} specifying
+ * {@code BINARY} or {@code INOUT}.
+ *
+ * The source and target types must be specified with {@code from} and
+ * {@code to}, unless the annotation appears on a method, in which case these
+ * default to the first parameter and return types of the function,
+ * respectively.
+ *
+ * The cast will, by default, have to be applied explicitly, unless
+ * {@code application=ASSIGNMENT} or {@code application=IMPLICIT} is given.
+ *
+ * @author Chapman Flack
+ */
+@Documented
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Repeatable(Cast.Container.class)
+@Retention(RetentionPolicy.CLASS)
+public @interface Cast
+{
+ /**
+ * When this cast can be applied: only in explicit form, when used in
+ * assignment context, or implicitly whenever needed.
+ */
+ enum Application { EXPLICIT, ASSIGNMENT, IMPLICIT };
+
+ /**
+ * A known conversion path when a dedicated function is not supplied:
+ * {@code BINARY} for two types that are known to have the same internal
+ * representation, or {@code INOUT} to invoke the first type's text-output
+ * function followed by the second type's text-input function.
+ */
+ enum Path { BINARY, INOUT };
+
+ /**
+ * The source type to be cast. Will default to the first parameter type of
+ * the associated function, if known.
+ *
+ * PostgreSQL will allow this type and the function's first parameter type
+ * to differ, if there is an existing binary cast between them. That cannot
+ * be checked at compile time, so a cast with a different type given here
+ * might successfully compile but fail to deploy in PostgreSQL.
+ */
+ String from() default "";
+
+ /**
+ * The target type to cast to. Will default to the return type of
+ * the associated function, if known.
+ *
+ * PostgreSQL will allow this type and the function's return type
+ * to differ, if there is an existing binary cast between them. That cannot
+ * be checked at compile time, so a cast with a different type given here
+ * might successfully compile but fail to deploy in PostgreSQL.
+ */
+ String to() default "";
+
+ /**
+ * A stock conversion path when a dedicated function is not supplied:
+ * {@code BINARY} for two types that are known to have the same internal
+ * representation, or {@code INOUT} to invoke the first type's text-output
+ * function followed by the second type's text-input function.
+ *
+ * To declare an {@code INOUT} cast, {@code with=INOUT} must appear
+ * explicitly; the default value is treated as unspecified.
+ */
+ Path path() default Path.INOUT;
+
+ /**
+ * When this cast can be applied: only in explicit form, when used in
+ * assignment context, or implicitly whenever needed.
+ */
+ Application application() default Application.EXPLICIT;
+
+ /**
+ * One or more arbitrary labels that will be considered 'provided' by the
+ * object carrying this annotation. The deployment descriptor will be
+ * generated in such an order that other objects that 'require' labels
+ * 'provided' by this come later in the output for install actions, and
+ * earlier for remove actions.
+ */
+ String[] provides() default {};
+
+ /**
+ * One or more arbitrary labels that will be considered 'required' by the
+ * object carrying this annotation. The deployment descriptor will be
+ * generated in such an order that other objects that 'provide' labels
+ * 'required' by this come earlier in the output for install actions, and
+ * later for remove actions.
+ */
+ String[] requires() default {};
+
+ /**
+ * The {@code } to be used around SQL code generated
+ * for this cast. Defaults to {@code PostgreSQL}. Set explicitly to
+ * {@code ""} to emit code not wrapped in an {@code }.
+ */
+ String implementor() default "";
+
+ /**
+ * A comment to be associated with the cast. If left to default, and the
+ * annotated Java construct has a doc comment, its first sentence will be
+ * used. If an empty string is explicitly given, no comment will be set.
+ */
+ String comment() default "";
+
+ /**
+ * @hidden container type allowing Cast to be repeatable.
+ */
+ @Documented
+ @Target({ElementType.METHOD, ElementType.TYPE})
+ @Retention(RetentionPolicy.CLASS)
+ @interface Container
+ {
+ Cast[] value();
+ }
+}
diff --git a/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLAction.java b/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLAction.java
index edbf63feb..face77719 100644
--- a/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLAction.java
+++ b/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLAction.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2013 Tada AB and other contributors, as listed below.
+ * Copyright (c) 2004-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -14,6 +14,7 @@
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
+import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@@ -35,6 +36,7 @@
*/
@Documented
@Target({ElementType.PACKAGE,ElementType.TYPE})
+@Repeatable(SQLActions.class)
@Retention(RetentionPolicy.CLASS)
public @interface SQLAction
{
diff --git a/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLActions.java b/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLActions.java
index bc618b4a8..753e1df25 100644
--- a/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLActions.java
+++ b/pljava-api/src/main/java/org/postgresql/pljava/annotation/SQLActions.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2013 Tada AB and other contributors, as listed below.
+ * Copyright (c) 2004-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -21,7 +21,11 @@
/**
* Container for multiple {@link SQLAction} annotations (in case it is
* convenient to hang more than one on a given program element).
- *
+ *
+ * This container annotation is documented for historical reasons (it existed
+ * in PL/Java versions targeting earlier Java versions than 8). In new code, it
+ * would be more natural to simply hang more than one {@code SQLAction}
+ * annotation directly on a program element.
* @author Thomas Hallgren - pre-Java6 version
* @author Chapman Flack (Purdue Mathematics) - updated to Java6,
* added SQLActions
diff --git a/pljava-api/src/main/java/org/postgresql/pljava/annotation/processing/DDRProcessor.java b/pljava-api/src/main/java/org/postgresql/pljava/annotation/processing/DDRProcessor.java
index 63c716702..07805d519 100644
--- a/pljava-api/src/main/java/org/postgresql/pljava/annotation/processing/DDRProcessor.java
+++ b/pljava-api/src/main/java/org/postgresql/pljava/annotation/processing/DDRProcessor.java
@@ -49,6 +49,7 @@
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
@@ -104,6 +105,7 @@
import org.postgresql.pljava.ResultSetProvider;
import org.postgresql.pljava.TriggerData;
+import org.postgresql.pljava.annotation.Cast;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
import org.postgresql.pljava.annotation.SQLActions;
@@ -214,15 +216,19 @@ class DDRProcessorImpl
// Our own annotations
//
final TypeElement AN_FUNCTION;
- final TypeElement AN_SQLACTION;
- final TypeElement AN_SQLACTIONS;
final TypeElement AN_SQLTYPE;
final TypeElement AN_TRIGGER;
final TypeElement AN_BASEUDT;
final TypeElement AN_MAPPEDUDT;
+ final TypeElement AN_SQLACTION;
+ final TypeElement AN_SQLACTIONS;
+ final TypeElement AN_CAST;
+ final TypeElement AN_CASTS;
// Certain familiar DBTypes (capitalized as this file historically has)
//
+ final DBType DT_BOOLEAN = new DBType.Reserved("boolean");
+ final DBType DT_INTEGER = new DBType.Reserved("integer");
final DBType DT_RECORD = new DBType.Named(
Identifier.Qualified.nameFromJava("pg_catalog.RECORD"));
final DBType DT_TRIGGER = new DBType.Named(
@@ -234,8 +240,7 @@ class DDRProcessorImpl
//
final DBType[] SIG_TYPMODIN =
{ DBType.fromSQLTypeAnnotation("pg_catalog.cstring[]") };
- final DBType[] SIG_TYPMODOUT =
- { DBType.fromSQLTypeAnnotation("integer") };
+ final DBType[] SIG_TYPMODOUT = { DT_INTEGER };
final DBType[] SIG_ANALYZE =
{ DBType.fromSQLTypeAnnotation("pg_catalog.internal") };
@@ -309,12 +314,18 @@ class DDRProcessorImpl
TY_VOID = typu.getNoType( TypeKind.VOID);
AN_FUNCTION = elmu.getTypeElement( Function.class.getName());
- AN_SQLACTION = elmu.getTypeElement( SQLAction.class.getName());
- AN_SQLACTIONS = elmu.getTypeElement( SQLActions.class.getName());
AN_SQLTYPE = elmu.getTypeElement( SQLType.class.getName());
AN_TRIGGER = elmu.getTypeElement( Trigger.class.getName());
AN_BASEUDT = elmu.getTypeElement( BaseUDT.class.getName());
AN_MAPPEDUDT = elmu.getTypeElement( MappedUDT.class.getName());
+
+ // Repeatable annotations and their containers.
+ //
+ AN_SQLACTION = elmu.getTypeElement( SQLAction.class.getName());
+ AN_SQLACTIONS = elmu.getTypeElement( SQLActions.class.getName());
+ AN_CAST = elmu.getTypeElement( Cast.class.getName());
+ AN_CASTS = elmu.getTypeElement(
+ Cast.Container.class.getCanonicalName());
}
void msg( Kind kind, String fmt, Object... args)
@@ -377,7 +388,13 @@ public int hashCode()
* one round), keyed by the object for which each snippet has been
* generated.
*/
- Map snippets = new HashMap<>();
+ /*
+ * This is a LinkedHashMap so that the order of handling annotation types
+ * in process() below will be preserved in calling their characterize()
+ * methods at end-of-round, and so, for example, characterize() on a Cast
+ * can use values set by characterize() on an associated Function.
+ */
+ Map snippets = new LinkedHashMap<>();
S getSnippet(Object o, Class c, Supplier ctor)
{
@@ -419,9 +436,9 @@ boolean process( Set extends TypeElement> tes, RoundEnvironment re)
{
boolean functionPresent = false;
boolean sqlActionPresent = false;
- boolean sqlActionsPresent = false;
boolean baseUDTPresent = false;
boolean mappedUDTPresent = false;
+ boolean castPresent = false;
boolean willClaim = true;
@@ -429,16 +446,16 @@ boolean process( Set extends TypeElement> tes, RoundEnvironment re)
{
if ( AN_FUNCTION.equals( te) )
functionPresent = true;
- else if ( AN_SQLACTION.equals( te) )
- sqlActionPresent = true;
- else if ( AN_SQLACTIONS.equals( te) )
- sqlActionsPresent = true;
else if ( AN_BASEUDT.equals( te) )
baseUDTPresent = true;
else if ( AN_MAPPEDUDT.equals( te) )
mappedUDTPresent = true;
else if ( AN_SQLTYPE.equals( te) )
; // these are handled within FunctionImpl
+ else if ( AN_SQLACTION.equals( te) || AN_SQLACTIONS.equals( te) )
+ sqlActionPresent = true;
+ else if ( AN_CAST.equals( te) || AN_CASTS.equals( te) )
+ castPresent = true;
else
{
msg( Kind.WARNING, te,
@@ -461,14 +478,18 @@ else if ( AN_SQLTYPE.equals( te) )
processFunction( e);
if ( sqlActionPresent )
- for ( Element e : re.getElementsAnnotatedWith( AN_SQLACTION) )
- processSQLAction( e);
-
- if ( sqlActionsPresent )
- for ( Element e : re.getElementsAnnotatedWith( AN_SQLACTIONS) )
- processSQLActions( e);
+ for ( Element e
+ : re.getElementsAnnotatedWithAny( AN_SQLACTION, AN_SQLACTIONS) )
+ processRepeatable(
+ e, AN_SQLACTION, AN_SQLACTIONS, SQLActionImpl.class);
+
+ if ( castPresent )
+ for ( Element e
+ : re.getElementsAnnotatedWithAny( AN_CAST, AN_CASTS) )
+ processRepeatable(
+ e, AN_CAST, AN_CASTS, CastImpl.class);
- tmpr.workAroundJava7Breakage(); // perhaps it will be fixed in Java 9?
+ tmpr.workAroundJava7Breakage(); // perhaps to be fixed in Java 9? nope.
if ( ! re.processingOver() )
defensiveEarlyCharacterize();
@@ -739,34 +760,44 @@ Snippet[] order(
}
/**
- * Process a single element annotated with @SQLAction.
- */
- void processSQLAction( Element e)
- {
- SQLActionImpl sa =
- getSnippet( e, SQLActionImpl.class, SQLActionImpl::new);
- for ( AnnotationMirror am : elmu.getAllAnnotationMirrors( e) )
- {
- if ( am.getAnnotationType().asElement().equals( AN_SQLACTION) )
- populateAnnotationImpl( sa, e, am);
- }
- }
-
- /**
- * Process a single element annotated with @SQLActions (which simply takes
- * an array of @SQLAction as a way to associate more than one SQLAction with
- * a single program element)..
+ * Process an element carrying a repeatable annotation, the container
+ * of that repeatable annotation, or both.
+ *
+ * Snippets corresponding to repeatable annotations are not entered in the
+ * {@code snippets} map keyed by the target element, as that might not be
+ * unique. Each snippet is entered with a key made from its class and
+ * itself. They are not expected to be looked up, only processed when all of
+ * the map entries are enumerated.
*/
- void processSQLActions( Element e)
+ void processRepeatable(
+ Element e, TypeElement annot, TypeElement container, Class clazz)
{
for ( AnnotationMirror am : elmu.getAllAnnotationMirrors( e) )
{
- if ( am.getAnnotationType().asElement().equals( AN_SQLACTIONS) )
+ Element asElement = am.getAnnotationType().asElement();
+ if ( asElement.equals( annot) )
{
- SQLActionsImpl sas = new SQLActionsImpl();
- populateAnnotationImpl( sas, e, am);
- for ( SQLAction sa : sas.value() )
- putSnippet( sa, (Snippet)sa);
+ T snip;
+ try
+ {
+ snip = clazz.getDeclaredConstructor( DDRProcessorImpl.class,
+ Element.class, AnnotationMirror.class)
+ .newInstance( DDRProcessorImpl.this, e, am);
+ }
+ catch ( ReflectiveOperationException re )
+ {
+ throw new RuntimeException(
+ "Incorrect implementation of annotation processor", re);
+ }
+ populateAnnotationImpl( snip, e, am);
+ putSnippet( snip, (Snippet)snip);
+ }
+ else if ( asElement.equals( container) )
+ {
+ Container c = new Container<>(clazz);
+ populateAnnotationImpl( c, e, am);
+ for ( T snip : c.value() )
+ putSnippet( snip, (Snippet)snip);
}
}
}
@@ -1098,6 +1129,18 @@ public Set requireTags()
}
}
+ class Repeatable extends AbstractAnnotationImpl
+ {
+ final Element m_targetElement;
+ final AnnotationMirror m_origin;
+
+ Repeatable(Element e, AnnotationMirror am)
+ {
+ m_targetElement = e;
+ m_origin = am;
+ }
+ }
+
/**
* Populate an AbstractAnnotationImpl-derived Annotation implementation
* from the element-value pairs in an AnnotationMirror. For each element
@@ -1265,30 +1308,56 @@ public void setName( Object o, boolean explicit, Element e)
}
}
- class SQLActionsImpl extends AbstractAnnotationImpl implements SQLActions
+ class Container
+ extends AbstractAnnotationImpl
{
- public SQLAction[] value() { return _value; }
+ public T[] value() { return _value; }
- SQLAction[] _value;
+ T[] _value;
+ final Class _clazz;
+
+ Container(Class clazz)
+ {
+ _clazz = clazz;
+ }
public void setValue( Object o, boolean explicit, Element e)
{
AnnotationMirror[] ams = avToArray( o, AnnotationMirror.class);
- _value = new SQLAction [ ams.length ];
+
+ @SuppressWarnings("unchecked")
+ T[] t = (T[])Array.newInstance( _clazz, ams.length);
+ _value = t;
+
int i = 0;
for ( AnnotationMirror am : ams )
{
- SQLActionImpl a = new SQLActionImpl();
- populateAnnotationImpl( a, e, am);
- _value [ i++ ] = a;
+ try
+ {
+ T a = _clazz.getDeclaredConstructor(DDRProcessorImpl.class,
+ Element.class, AnnotationMirror.class)
+ .newInstance(DDRProcessorImpl.this, e, am);
+ populateAnnotationImpl( a, e, am);
+ _value [ i++ ] = a;
+ }
+ catch ( ReflectiveOperationException re )
+ {
+ throw new RuntimeException(
+ "Incorrect implementation of annotation processor", re);
+ }
}
}
}
class SQLActionImpl
- extends AbstractAnnotationImpl
+ extends Repeatable
implements SQLAction, Snippet
{
+ SQLActionImpl(Element e, AnnotationMirror am)
+ {
+ super(e, am);
+ }
+
public String[] install() { return _install; }
public String[] remove() { return _remove; }
public String[] provides() { return _provides; }
@@ -1528,7 +1597,7 @@ public String[] deployStrings()
if ( ! "".equals( _when) )
sb.append( "\n\tWHEN ").append( _when);
sb.append( "\n\tEXECUTE PROCEDURE ");
- func.appendNameAndParams( sb, false);
+ func.appendNameAndParams( sb, true, false);
sb.setLength( sb.length() - 1); // drop closing )
s = _arguments.length;
for ( String a : _arguments )
@@ -1916,15 +1985,15 @@ public void subsume()
*
* @param dflts Whether to include the defaults, if any.
*/
- void appendNameAndParams( StringBuilder sb, boolean dflts)
+ void appendNameAndParams(StringBuilder sb, boolean names, boolean dflts)
{
sb.append(qnameFrom(name(), schema())).append( '(');
- appendParams( sb, dflts);
+ appendParams( sb, names, dflts);
// TriggerImpl relies on ) being the very last character
sb.append( ')');
}
- void appendParams( StringBuilder sb, boolean dflts)
+ void appendParams( StringBuilder sb, boolean names, boolean dflts)
{
int count = parameterTypes.length;
for ( ParameterInfo i
@@ -1941,7 +2010,10 @@ void appendParams( StringBuilder sb, boolean dflts)
if ( _variadic && 0 == count )
sb.append("VARIADIC ");
- sb.append(name).append(' ').append(i.dt.toString(dflts));
+ if ( names )
+ sb.append(name).append(' ');
+
+ sb.append(i.dt.toString(dflts));
if ( 0 < count )
sb.append(',');
@@ -1966,7 +2038,7 @@ public String[] deployStrings()
ArrayList al = new ArrayList<>();
StringBuilder sb = new StringBuilder();
sb.append( "CREATE OR REPLACE FUNCTION ");
- appendNameAndParams( sb, true);
+ appendNameAndParams( sb, true, true);
sb.append( "\n\tRETURNS ");
if ( trigger )
sb.append( DT_TRIGGER.toString());
@@ -2004,7 +2076,7 @@ public String[] deployStrings()
{
sb.setLength( 0);
sb.append( "COMMENT ON FUNCTION ");
- appendNameAndParams( sb, false);
+ appendNameAndParams( sb, true, false);
sb.append( "\nIS ");
sb.append( DDRWriter.eQuote( comm));
al.add( sb.toString());
@@ -2029,7 +2101,7 @@ public String[] undeployStrings()
StringBuilder sb = new StringBuilder();
sb.append( "DROP FUNCTION ");
- appendNameAndParams( sb, false);
+ appendNameAndParams( sb, true, false);
rslt [ rslt.length - 1 ] = sb.toString();
return rslt;
}
@@ -2138,7 +2210,7 @@ class BaseUDTFunctionImpl extends FunctionImpl
BaseUDTFunctionID id;
@Override
- void appendParams( StringBuilder sb, boolean dflts)
+ void appendParams( StringBuilder sb, boolean names, boolean dflts)
{
sb.append(
Arrays.stream(id.getParam( ui))
@@ -2700,6 +2772,216 @@ public Vertex breakCycle(Vertex v, boolean deploy)
}
}
+ class CastImpl
+ extends Repeatable
+ implements Cast, Snippet, Commentable
+ {
+ CastImpl(Element e, AnnotationMirror am)
+ {
+ super(e, am);
+ }
+
+ public String from() { return _from; }
+ public String to() { return _to; }
+ public Cast.Path path() { return _path; }
+ public Cast.Application application() { return _application; }
+ public String[] provides() { return _provides; }
+ public String[] requires() { return _requires; }
+
+ public String _from;
+ public String _to;
+ public Cast.Path _path;
+ public Cast.Application _application;
+ public String[] _provides;
+ public String[] _requires;
+
+ FunctionImpl func;
+ DBType fromType;
+ DBType toType;
+
+ public void setPath( Object o, boolean explicit, Element e)
+ {
+ if ( explicit )
+ _path = Path.valueOf(
+ ((VariableElement)o).getSimpleName().toString());
+ }
+
+ public boolean characterize()
+ {
+ boolean ok = true;
+
+ if ( ElementKind.METHOD.equals(m_targetElement.getKind()) )
+ {
+ func = getSnippet(m_targetElement, FunctionImpl.class,
+ () -> (FunctionImpl)null);
+ if ( null == func )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "A method annotated with @Cast must also have @Function"
+ );
+ ok = false;
+ }
+ }
+
+ if ( null == func && "".equals(_from) )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "@Cast not annotating a method must specify from="
+ );
+ ok = false;
+ }
+
+ if ( null == func && "".equals(_to) )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "@Cast not annotating a method must specify to="
+ );
+ ok = false;
+ }
+
+ if ( null == func && null == _path )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "@Cast not annotating a method, and without path=, " +
+ "is not yet supported"
+ );
+ ok = false;
+ }
+
+ if ( ok )
+ {
+ fromType = ("".equals(_from))
+ ? func.parameterTypes[0]
+ : DBType.fromSQLTypeAnnotation(_from);
+
+ toType = ("".equals(_to))
+ ? func.returnType
+ : DBType.fromSQLTypeAnnotation(_to);
+ }
+
+ if ( null != _path )
+ {
+ if ( ok && Path.BINARY == _path && fromType.equals(toType) )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "A cast with from and to types the same can only " +
+ "apply a type modifier; path=BINARY will have " +
+ "no effect");
+ ok = false;
+ }
+ }
+ else if ( null != func )
+ {
+ int nparams = func.parameterTypes.length;
+
+ if ( ok && 2 > nparams && fromType.equals(toType) )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "A cast with from and to types the same can only " +
+ "apply a type modifier, therefore must have at least " +
+ "two parameters");
+ ok = false;
+ }
+
+ if ( 1 > nparams || nparams > 3 )
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "A cast function must have 1, 2, or 3 parameters");
+ ok = false;
+ }
+
+ if (1 < nparams && ! DT_INTEGER.equals(func.parameterTypes[1]))
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "Parameter 2 of a cast function must have integer type"
+ );
+ ok = false;
+ }
+
+ if (3 == nparams && ! DT_BOOLEAN.equals(func.parameterTypes[2]))
+ {
+ msg(Kind.ERROR, m_targetElement, m_origin,
+ "Parameter 3 of a cast function must have boolean type"
+ );
+ ok = false;
+ }
+ }
+
+ if ( ! ok )
+ return false;
+
+ recordImplicitTags();
+ recordExplicitTags(_provides, _requires);
+ return true;
+ }
+
+ void recordImplicitTags()
+ {
+ Set requires = requireTags();
+
+ DependTag> dt = fromType.dependTag();
+ if ( null != dt )
+ requires.add(dt);
+
+ dt = toType.dependTag();
+ if ( null != dt )
+ requires.add(dt);
+
+ if ( null == _path )
+ {
+ dt = func.provideTags().stream()
+ .filter(DependTag.Function.class::isInstance)
+ .findAny().get();
+ requires.add(dt);
+ }
+ }
+
+ public String[] deployStrings()
+ {
+ List al = new ArrayList<>();
+
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("CREATE CAST (")
+ .append(fromType).append(" AS ").append(toType).append(")\n\t");
+
+ if ( Path.BINARY == _path )
+ sb.append("WITHOUT FUNCTION");
+ else if ( Path.INOUT == _path )
+ sb.append("WITH INOUT");
+ else
+ {
+ sb.append("WITH FUNCTION ");
+ func.appendNameAndParams(sb, false, false);
+ }
+
+ switch ( _application )
+ {
+ case ASSIGNMENT: sb.append("\n\tAS ASSIGNMENT"); break;
+ case EXPLICIT: break;
+ case IMPLICIT: sb.append("\n\tAS IMPLICIT");
+ }
+
+ al.add(sb.toString());
+
+ if ( null != comment() )
+ al.add(
+ "COMMENT ON CAST (" +
+ fromType + " AS " + toType + ") IS " +
+ DDRWriter.eQuote(comment()));
+
+ return al.toArray( new String [ al.size() ]);
+ }
+
+ public String[] undeployStrings()
+ {
+ return new String[]
+ {
+ "DROP CAST (" + fromType + " AS " + toType + ")"
+ };
+ }
+ }
+
/**
* Provides the default mappings from Java types to SQL types.
*/
diff --git a/pljava-api/src/test/java/LexicalsTest.java b/pljava-api/src/test/java/LexicalsTest.java
index ec58a2a45..e12ca9674 100644
--- a/pljava-api/src/test/java/LexicalsTest.java
+++ b/pljava-api/src/test/java/LexicalsTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
+import static org.hamcrest.MatcherAssert.assertThat;
import static
org.postgresql.pljava.sqlgen.Lexicals.ISO_AND_PG_IDENTIFIER_CAPTURING;
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/ConditionalDDR.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/ConditionalDDR.java
index ac26d8a95..0140f4372 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/ConditionalDDR.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/ConditionalDDR.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015- Tada AB and other contributors, as listed below.
+ * Copyright (c) 2015-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -12,7 +12,6 @@
package org.postgresql.pljava.example.annotation;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
/**
* Test of a very simple form of conditional execution in the deployment
@@ -68,71 +67,69 @@
* several statements setting PostgreSQL-version-based implementor tags that
* are relied on by various other examples in this directory.
*/
-@SQLActions({
- @SQLAction(provides={"LifeIsGood","LifeIsNotGood"}, install=
- "SELECT CASE 42 WHEN 42 THEN " +
- " set_config('pljava.implementors', 'LifeIsGood,' || " +
- " current_setting('pljava.implementors'), true) " +
- "ELSE " +
- " set_config('pljava.implementors', 'LifeIsNotGood,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides={"LifeIsGood","LifeIsNotGood"}, install=
+ "SELECT CASE 42 WHEN 42 THEN " +
+ " set_config('pljava.implementors', 'LifeIsGood,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "ELSE " +
+ " set_config('pljava.implementors', 'LifeIsNotGood,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(implementor="LifeIsGood", install=
- "SELECT javatest.logmessage('INFO', 'Looking good!')"
- ),
+@SQLAction(implementor="LifeIsGood", install=
+ "SELECT javatest.logmessage('INFO', 'Looking good!')"
+)
- @SQLAction(implementor="LifeIsNotGood", install=
- "SELECT javatest.logmessage('WARNING', 'This should not be executed')"
- ),
+@SQLAction(implementor="LifeIsNotGood", install=
+ "SELECT javatest.logmessage('WARNING', 'This should not be executed')"
+)
- @SQLAction(provides="postgresql_ge_80300", install=
- "SELECT CASE WHEN" +
- " 80300 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_80300,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides="postgresql_ge_80300", install=
+ "SELECT CASE WHEN" +
+ " 80300 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_80300,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(provides="postgresql_ge_80400", install=
- "SELECT CASE WHEN" +
- " 80400 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_80400,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides="postgresql_ge_80400", install=
+ "SELECT CASE WHEN" +
+ " 80400 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_80400,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(provides="postgresql_ge_90000", install=
- "SELECT CASE WHEN" +
- " 90000 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_90000,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides="postgresql_ge_90000", install=
+ "SELECT CASE WHEN" +
+ " 90000 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_90000,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(provides="postgresql_ge_90100", install=
- "SELECT CASE WHEN" +
- " 90100 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_90100,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides="postgresql_ge_90100", install=
+ "SELECT CASE WHEN" +
+ " 90100 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_90100,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(provides="postgresql_ge_90300", install=
- "SELECT CASE WHEN" +
- " 90300 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_90300,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
+@SQLAction(provides="postgresql_ge_90300", install=
+ "SELECT CASE WHEN" +
+ " 90300 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_90300,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
- @SQLAction(provides="postgresql_ge_100000", install=
- "SELECT CASE WHEN" +
- " 100000 <= CAST(current_setting('server_version_num') AS integer)" +
- " THEN set_config('pljava.implementors', 'postgresql_ge_100000,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
-})
+@SQLAction(provides="postgresql_ge_100000", install=
+ "SELECT CASE WHEN" +
+ " 100000 <= CAST(current_setting('server_version_num') AS integer)" +
+ " THEN set_config('pljava.implementors', 'postgresql_ge_100000,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
public class ConditionalDDR { }
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Enumeration.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Enumeration.java
index 298050537..2fcee7df1 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Enumeration.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Enumeration.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015- Tada AB and other contributors, as listed below.
+ * Copyright (c) 2015-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -15,7 +15,6 @@
import java.util.Arrays;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.SQLType;
import org.postgresql.pljava.annotation.Function;
@@ -27,21 +26,19 @@
* version, set up in the {@link ConditionalDDR} example. PostgreSQL before 8.3
* did not have enum types.
*/
-@SQLActions({
- @SQLAction(provides="mood type", implementor="postgresql_ge_80300",
- install="CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy')",
- remove="DROP TYPE mood"
- ),
- @SQLAction(implementor="postgresql_ge_80300",
- requires={"textToMood", "moodToText", "textsToMoods", "moodsToTexts"},
- install={
- "SELECT textToMood('happy')",
- "SELECT moodToText('happy'::mood)",
- "SELECT textsToMoods(array['happy','happy','sad','ok'])",
- "SELECT moodsToTexts(array['happy','happy','sad','ok']::mood[])"
- }
- )
-})
+@SQLAction(provides="mood type", implementor="postgresql_ge_80300",
+ install="CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy')",
+ remove="DROP TYPE mood"
+)
+@SQLAction(implementor="postgresql_ge_80300",
+ requires={"textToMood", "moodToText", "textsToMoods", "moodsToTexts"},
+ install={
+ "SELECT textToMood('happy')",
+ "SELECT moodToText('happy'::mood)",
+ "SELECT textsToMoods(array['happy','happy','sad','ok'])",
+ "SELECT moodsToTexts(array['happy','happy','sad','ok']::mood[])"
+ }
+)
public class Enumeration
{
@Function(requires="mood type", provides="textToMood", type="mood",
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/IntWithMod.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/IntWithMod.java
index c28215616..a31928a62 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/IntWithMod.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/IntWithMod.java
@@ -21,6 +21,7 @@
import java.sql.SQLOutput;
import java.sql.Statement;
+import org.postgresql.pljava.annotation.Cast;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
import org.postgresql.pljava.annotation.SQLType;
@@ -51,32 +52,13 @@
*
* Of course this example more or less duplicates what you could do in two lines
* with CREATE DOMAIN. But it is enough to illustrate the process.
- *
- * Certainly, it would be less tedious with some more annotation support and
- * autogeneration of the ordering dependencies that are now added by hand here.
- *
- * Most of this must be suppressed (using conditional implementor tags) if the
- * PostgreSQL instance is older than 8.3, because it won't have the cstring[]
- * type, so the typeModifierInput function can't be declared, and so neither
- * can the type, or functions that accept or return it. See the
- * {@link ConditionalDDR} example for where the implementor tag is set up.
*/
-@SQLAction(requires={"IntWithMod type", "IntWithMod modApply"},
- implementor="postgresql_ge_80300",
- remove="DROP CAST (javatest.IntWithMod AS javatest.IntWithMod)",
+@SQLAction(requires="IntWithMod modCast",
install={
- "CREATE CAST (javatest.IntWithMod AS javatest.IntWithMod)" +
- " WITH FUNCTION javatest.intwithmod_typmodapply(" +
- " javatest.IntWithMod, integer, boolean)",
-
- "COMMENT ON CAST (javatest.IntWithMod AS javatest.IntWithMod) IS '" +
- "Cast that applies/verifies the type modifier on an IntWithMod.'",
-
"SELECT CAST('42' AS javatest.IntWithMod(even))"
}
)
@BaseUDT(schema="javatest", provides="IntWithMod type",
- implementor="postgresql_ge_80300",
typeModifierInput="javatest.intwithmod_typmodin",
typeModifierOutput="javatest.intwithmod_typmodout",
like="pg_catalog.int4")
@@ -146,7 +128,6 @@ public void writeSQL(SQLOutput stream) throws SQLException {
* "even" or "odd". The modifier value is 0 for even or 1 for odd.
*/
@Function(schema="javatest", name="intwithmod_typmodin",
- implementor="postgresql_ge_80300",
effects=IMMUTABLE, onNullInput=RETURNS_NULL)
public static int modIn(@SQLType("pg_catalog.cstring[]") String[] toks)
throws SQLException {
@@ -180,9 +161,10 @@ public static String modOut(int mod) throws SQLException {
* Function backing the type-modifier application cast for IntWithMod type.
*/
@Function(schema="javatest", name="intwithmod_typmodapply",
- implementor="postgresql_ge_80300",
- provides="IntWithMod modApply",
effects=IMMUTABLE, onNullInput=RETURNS_NULL)
+ @Cast(comment=
+ "Cast that applies/verifies the type modifier on an IntWithMod.",
+ provides="IntWithMod modCast")
public static IntWithMod modApply(IntWithMod iwm, int mod, boolean explicit)
throws SQLException
{
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/JDBC42_21.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/JDBC42_21.java
index 768726173..212cb13ba 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/JDBC42_21.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/JDBC42_21.java
@@ -13,7 +13,6 @@
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.example.annotation.ConditionalDDR; // for javadoc
@@ -27,102 +26,100 @@
* Relies on PostgreSQL-version-specific implementor tags set up in the
* {@link ConditionalDDR} example.
*/
-@SQLActions({
- @SQLAction(
- implementor="postgresql_ge_90300",requires="TypeRoundTripper.roundTrip",
- install={
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'java.time.LocalDate passes')" +
- " ELSE javatest.logmessage('WARNING', 'java.time.LocalDate fails')" +
- " END" +
- " FROM" +
- " (VALUES" +
- " (date '2017-08-21')," +
- " (date '1970-03-07')," +
- " (date '1919-05-29')" +
- " ) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.LocalDate')" +
- " AS r(roundtripped date)",
+@SQLAction(
+ implementor="postgresql_ge_90300",requires="TypeRoundTripper.roundTrip",
+ install={
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'java.time.LocalDate passes')" +
+ " ELSE javatest.logmessage('WARNING', 'java.time.LocalDate fails')" +
+ " END" +
+ " FROM" +
+ " (VALUES" +
+ " (date '2017-08-21')," +
+ " (date '1970-03-07')," +
+ " (date '1919-05-29')" +
+ " ) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.LocalDate')" +
+ " AS r(roundtripped date)",
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'java.time.LocalTime passes')" +
- " ELSE javatest.logmessage('WARNING', 'java.time.LocalTime fails')" +
- " END" +
- " FROM" +
- " (SELECT current_time::time) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.LocalTime')" +
- " AS r(roundtripped time)",
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'java.time.LocalTime passes')" +
+ " ELSE javatest.logmessage('WARNING', 'java.time.LocalTime fails')" +
+ " END" +
+ " FROM" +
+ " (SELECT current_time::time) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.LocalTime')" +
+ " AS r(roundtripped time)",
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'java.time.OffsetTime passes')" +
- " ELSE javatest.logmessage('WARNING', 'java.time.OffsetTime fails')" +
- " END" +
- " FROM" +
- " (SELECT current_time::timetz) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.OffsetTime')" +
- " AS r(roundtripped timetz)",
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'java.time.OffsetTime passes')" +
+ " ELSE javatest.logmessage('WARNING', 'java.time.OffsetTime fails')" +
+ " END" +
+ " FROM" +
+ " (SELECT current_time::timetz) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.OffsetTime')" +
+ " AS r(roundtripped timetz)",
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'java.time.LocalDateTime passes')" +
- " ELSE javatest.logmessage('WARNING','java.time.LocalDateTime fails')"+
- " END" +
- " FROM" +
- " (SELECT 'on' = current_setting('integer_datetimes')) AS ck(idt)," +
- " LATERAL (" +
- " SELECT" +
- " value" +
- " FROM" +
- " (VALUES" +
- " (true, timestamp '2017-08-21 18:25:29.900005')," +
- " (true, timestamp '1970-03-07 17:37:49.300009')," +
- " (true, timestamp '1919-05-29 13:08:33.600001')," +
- " (idt, timestamp 'infinity')," +
- " (idt, timestamp '-infinity')" +
- " ) AS vs(cond, value)" +
- " WHERE cond" +
- " ) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.LocalDateTime')" +
- " AS r(roundtripped timestamp)",
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'java.time.LocalDateTime passes')" +
+ " ELSE javatest.logmessage('WARNING','java.time.LocalDateTime fails')"+
+ " END" +
+ " FROM" +
+ " (SELECT 'on' = current_setting('integer_datetimes')) AS ck(idt)," +
+ " LATERAL (" +
+ " SELECT" +
+ " value" +
+ " FROM" +
+ " (VALUES" +
+ " (true, timestamp '2017-08-21 18:25:29.900005')," +
+ " (true, timestamp '1970-03-07 17:37:49.300009')," +
+ " (true, timestamp '1919-05-29 13:08:33.600001')," +
+ " (idt, timestamp 'infinity')," +
+ " (idt, timestamp '-infinity')" +
+ " ) AS vs(cond, value)" +
+ " WHERE cond" +
+ " ) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.LocalDateTime')" +
+ " AS r(roundtripped timestamp)",
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'java.time.OffsetDateTime passes')"+
- " ELSE javatest.logmessage(" +
- " 'WARNING','java.time.OffsetDateTime fails')"+
- " END" +
- " FROM" +
- " (SELECT 'on' = current_setting('integer_datetimes')) AS ck(idt)," +
- " LATERAL (" +
- " SELECT" +
- " value" +
- " FROM" +
- " (VALUES" +
- " (true, timestamptz '2017-08-21 18:25:29.900005Z')," +
- " (true, timestamptz '1970-03-07 17:37:49.300009Z')," +
- " (true, timestamptz '1919-05-29 13:08:33.600001Z')," +
- " (idt, timestamptz 'infinity')," +
- " (idt, timestamptz '-infinity')" +
- " ) AS vs(cond, value)" +
- " WHERE cond" +
- " ) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.OffsetDateTime')" +
- " AS r(roundtripped timestamptz)",
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'java.time.OffsetDateTime passes')"+
+ " ELSE javatest.logmessage(" +
+ " 'WARNING','java.time.OffsetDateTime fails')"+
+ " END" +
+ " FROM" +
+ " (SELECT 'on' = current_setting('integer_datetimes')) AS ck(idt)," +
+ " LATERAL (" +
+ " SELECT" +
+ " value" +
+ " FROM" +
+ " (VALUES" +
+ " (true, timestamptz '2017-08-21 18:25:29.900005Z')," +
+ " (true, timestamptz '1970-03-07 17:37:49.300009Z')," +
+ " (true, timestamptz '1919-05-29 13:08:33.600001Z')," +
+ " (idt, timestamptz 'infinity')," +
+ " (idt, timestamptz '-infinity')" +
+ " ) AS vs(cond, value)" +
+ " WHERE cond" +
+ " ) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.OffsetDateTime')" +
+ " AS r(roundtripped timestamptz)",
- " SELECT" +
- " CASE WHEN every(orig = roundtripped)" +
- " THEN javatest.logmessage('INFO', 'OffsetTime as stmt param passes')"+
- " ELSE javatest.logmessage(" +
- " 'WARNING','java.time.OffsetTime as stmt param fails')"+
- " END" +
- " FROM" +
- " (SELECT current_time::timetz) AS p(orig)," +
- " javatest.roundtrip(p, 'java.time.OffsetTime', true)" +
- " AS r(roundtripped timetz)"
- })
+ " SELECT" +
+ " CASE WHEN every(orig = roundtripped)" +
+ " THEN javatest.logmessage('INFO', 'OffsetTime as stmt param passes')"+
+ " ELSE javatest.logmessage(" +
+ " 'WARNING','java.time.OffsetTime as stmt param fails')"+
+ " END" +
+ " FROM" +
+ " (SELECT current_time::timetz) AS p(orig)," +
+ " javatest.roundtrip(p, 'java.time.OffsetTime', true)" +
+ " AS r(roundtripped timetz)"
})
public class JDBC42_21
{
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PassXML.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PassXML.java
index e5614933b..bd22169e3 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PassXML.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PassXML.java
@@ -67,7 +67,6 @@
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.MappedUDT;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.SQLType;
import static org.postgresql.pljava.example.LoggerTest.logMessage;
@@ -105,152 +104,150 @@
* Everything mentioning the type XML here needs a conditional implementor tag
* in case of being loaded into a PostgreSQL instance built without that type.
*/
-@SQLActions({
- @SQLAction(provides="postgresql_xml", install=
- "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
- " THEN set_config('pljava.implementors', 'postgresql_xml,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
-
- @SQLAction(implementor="postgresql_ge_80400",
- provides="postgresql_xml_ge84",
- install=
- "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
- " THEN set_config('pljava.implementors', 'postgresql_xml_ge84,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
-
- @SQLAction(implementor="postgresql_xml_ge84", requires="echoXMLParameter",
- install=
- "WITH" +
- " s(how) AS (SELECT generate_series(1, 7))," +
- " t(x) AS (" +
- " SELECT table_to_xml('pg_catalog.pg_operator', true, false, '')" +
- " )," +
- " r(howin, howout, isdoc) AS (" +
- " SELECT" +
- " i.how, o.how," +
- " javatest.echoxmlparameter(x, i.how, o.how) IS DOCUMENT" +
- " FROM" +
- " t, s AS i, s AS o" +
- " WHERE" +
- " NOT (i.how = 6 and o.how = 7)" + // 6->7 unreliable in some JREs
- " ) " +
- "SELECT" +
- " CASE WHEN every(isdoc)" +
- " THEN javatest.logmessage('INFO', 'SQLXML echos succeeded')" +
- " ELSE javatest.logmessage('WARNING', 'SQLXML echos had problems')" +
- " END " +
- "FROM" +
- " r"
- ),
-
- @SQLAction(implementor="postgresql_xml_ge84", requires="proxiedXMLEcho",
- install=
- "WITH" +
- " s(how) AS (SELECT unnest('{1,2,4,5,6,7}'::int[]))," +
- " t(x) AS (" +
- " SELECT table_to_xml('pg_catalog.pg_operator', true, false, '')" +
- " )," +
- " r(how, isdoc) AS (" +
- " SELECT" +
- " how," +
- " javatest.proxiedxmlecho(x, how) IS DOCUMENT" +
- " FROM" +
- " t, s" +
- " )" +
- "SELECT" +
- " CASE WHEN every(isdoc)" +
- " THEN javatest.logmessage('INFO', 'proxied SQLXML echos succeeded')" +
- " ELSE javatest.logmessage('WARNING'," +
- " 'proxied SQLXML echos had problems')" +
- " END " +
- "FROM" +
- " r"
- ),
-
- @SQLAction(implementor="postgresql_xml_ge84", requires="lowLevelXMLEcho",
- install={
+@SQLAction(provides="postgresql_xml", install=
+ "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
+ " THEN set_config('pljava.implementors', 'postgresql_xml,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
+
+@SQLAction(implementor="postgresql_ge_80400",
+ provides="postgresql_xml_ge84",
+ install=
+ "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
+ " THEN set_config('pljava.implementors', 'postgresql_xml_ge84,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
+
+@SQLAction(implementor="postgresql_xml_ge84", requires="echoXMLParameter",
+ install=
+ "WITH" +
+ " s(how) AS (SELECT generate_series(1, 7))," +
+ " t(x) AS (" +
+ " SELECT table_to_xml('pg_catalog.pg_operator', true, false, '')" +
+ " )," +
+ " r(howin, howout, isdoc) AS (" +
+ " SELECT" +
+ " i.how, o.how," +
+ " javatest.echoxmlparameter(x, i.how, o.how) IS DOCUMENT" +
+ " FROM" +
+ " t, s AS i, s AS o" +
+ " WHERE" +
+ " NOT (i.how = 6 and o.how = 7)" + // 6->7 unreliable in some JREs
+ " ) " +
+ "SELECT" +
+ " CASE WHEN every(isdoc)" +
+ " THEN javatest.logmessage('INFO', 'SQLXML echos succeeded')" +
+ " ELSE javatest.logmessage('WARNING', 'SQLXML echos had problems')" +
+ " END " +
+ "FROM" +
+ " r"
+)
+
+@SQLAction(implementor="postgresql_xml_ge84", requires="proxiedXMLEcho",
+ install=
+ "WITH" +
+ " s(how) AS (SELECT unnest('{1,2,4,5,6,7}'::int[]))," +
+ " t(x) AS (" +
+ " SELECT table_to_xml('pg_catalog.pg_operator', true, false, '')" +
+ " )," +
+ " r(how, isdoc) AS (" +
+ " SELECT" +
+ " how," +
+ " javatest.proxiedxmlecho(x, how) IS DOCUMENT" +
+ " FROM" +
+ " t, s" +
+ " )" +
+ "SELECT" +
+ " CASE WHEN every(isdoc)" +
+ " THEN javatest.logmessage('INFO', 'proxied SQLXML echos succeeded')" +
+ " ELSE javatest.logmessage('WARNING'," +
+ " 'proxied SQLXML echos had problems')" +
+ " END " +
+ "FROM" +
+ " r"
+)
+
+@SQLAction(implementor="postgresql_xml_ge84", requires="lowLevelXMLEcho",
+ install={
+ "SELECT" +
+ " preparexmlschema('schematest', $$" +
+ "" +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ "" +
+ "$$, 'http://www.w3.org/2001/XMLSchema', 5)",
+
+ "WITH" +
+ " s(how) AS (SELECT unnest('{4,5,7}'::int[]))," +
+ " r(isdoc) AS (" +
+ " SELECT" +
+ " javatest.lowlevelxmlecho(" +
+ " query_to_xml(" +
+ " 'SELECT ''hi'' AS textcol, 1 AS intcol', true, true, 'urn:testme'"+
+ " ), how, params) IS DOCUMENT" +
+ " FROM" +
+ " s," +
+ " (SELECT 'schematest' AS schema) AS params" +
+ " )" +
+ "SELECT" +
+ " CASE WHEN every(isdoc)" +
+ " THEN javatest.logmessage('INFO', 'XML Schema tests succeeded')" +
+ " ELSE javatest.logmessage('WARNING'," +
+ " 'XML Schema tests had problems')" +
+ " END " +
+ "FROM" +
+ " r"
+ }
+)
+
+@SQLAction(implementor="postgresql_xml",
+ requires={"prepareXMLTransform", "transformXML"},
+ install={
"SELECT" +
- " preparexmlschema('schematest', $$" +
- "" +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- "" +
- "$$, 'http://www.w3.org/2001/XMLSchema', 5)",
-
- "WITH" +
- " s(how) AS (SELECT unnest('{4,5,7}'::int[]))," +
- " r(isdoc) AS (" +
- " SELECT" +
- " javatest.lowlevelxmlecho(" +
- " query_to_xml(" +
- " 'SELECT ''hi'' AS textcol, 1 AS intcol', true, true, 'urn:testme'"+
- " ), how, params) IS DOCUMENT" +
- " FROM" +
- " s," +
- " (SELECT 'schematest' AS schema) AS params" +
- " )" +
+ " javatest.prepareXMLTransform('distinctElementNames'," +
+ "'" +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ " " +
+ "', 5, true)",
+
"SELECT" +
- " CASE WHEN every(isdoc)" +
- " THEN javatest.logmessage('INFO', 'XML Schema tests succeeded')" +
- " ELSE javatest.logmessage('WARNING'," +
- " 'XML Schema tests had problems')" +
- " END " +
- "FROM" +
- " r"
- }
- ),
-
- @SQLAction(implementor="postgresql_xml",
- requires={"prepareXMLTransform", "transformXML"},
- install={
- "SELECT" +
- " javatest.prepareXMLTransform('distinctElementNames'," +
- "'" +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- " " +
- "', 5, true)",
-
- "SELECT" +
- " CASE WHEN" +
- " javatest.transformXML('distinctElementNames'," +
- " '', 5, 5)::text" +
- " =" +
- " 'abcde'"+
- " THEN javatest.logmessage('INFO', 'XSLT 1.0 test succeeded')" +
- " ELSE javatest.logmessage('WARNING', 'XSLT 1.0 test failed')" +
- " END"
- }
- )
-})
+ " CASE WHEN" +
+ " javatest.transformXML('distinctElementNames'," +
+ " '', 5, 5)::text" +
+ " =" +
+ " 'abcde'"+
+ " THEN javatest.logmessage('INFO', 'XSLT 1.0 test succeeded')" +
+ " ELSE javatest.logmessage('WARNING', 'XSLT 1.0 test failed')" +
+ " END"
+ }
+)
@MappedUDT(schema="javatest", name="onexml", structure="c1 xml",
implementor="postgresql_xml",
comment="A composite type mapped by the PassXML example class")
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PreJSR310.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PreJSR310.java
index b19f5ce43..c0409c0d7 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PreJSR310.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/PreJSR310.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018- Tada AB and other contributors, as listed below.
+ * Copyright (c) 2018-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -24,7 +24,6 @@
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
/**
* Some tests of pre-JSR 310 date/time/timestamp conversions.
@@ -34,17 +33,15 @@
* This example relies on {@code implementor} tags reflecting the PostgreSQL
* version, set up in the {@link ConditionalDDR} example.
*/
-@SQLActions({
- @SQLAction(provides="language java_tzset", install={
- "SELECT sqlj.alias_java_language('java_tzset', true)"
- }, remove={
- "DROP LANGUAGE java_tzset"
- }),
+@SQLAction(provides="language java_tzset", install={
+ "SELECT sqlj.alias_java_language('java_tzset', true)"
+}, remove={
+ "DROP LANGUAGE java_tzset"
+})
- @SQLAction(implementor="postgresql_ge_90300", // needs LATERAL
- requires="issue199", install={
- "SELECT javatest.issue199()"
- })
+@SQLAction(implementor="postgresql_ge_90300", // needs LATERAL
+ requires="issue199", install={
+ "SELECT javatest.issue199()"
})
public class PreJSR310
{
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/RecordParameterDefaults.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/RecordParameterDefaults.java
index d4f240cee..09d3dbbe8 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/RecordParameterDefaults.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/RecordParameterDefaults.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018- Tada AB and other contributors, as listed below.
+ * Copyright (c) 2018-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -20,7 +20,6 @@
import org.postgresql.pljava.ResultSetProvider;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.SQLType;
/**
@@ -33,19 +32,17 @@
* This example relies on {@code implementor} tags reflecting the PostgreSQL
* version, set up in the {@link ConditionalDDR} example.
*/
-@SQLActions({
- @SQLAction(
- provides = "paramtypeinfo type", // created in Triggers.java
- install = {
- "CREATE TYPE javatest.paramtypeinfo AS (" +
- " name text, pgtypename text, javaclass text, tostring text" +
- ")"
- },
- remove = {
- "DROP TYPE javatest.paramtypeinfo"
- }
- )
-})
+@SQLAction(
+ provides = "paramtypeinfo type", // created in Triggers.java
+ install = {
+ "CREATE TYPE javatest.paramtypeinfo AS (" +
+ " name text, pgtypename text, javaclass text, tostring text" +
+ ")"
+ },
+ remove = {
+ "DROP TYPE javatest.paramtypeinfo"
+ }
+)
public class RecordParameterDefaults implements ResultSetProvider
{
/**
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/SPIActions.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/SPIActions.java
index f2606c912..dca34e5c7 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/SPIActions.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/SPIActions.java
@@ -31,37 +31,34 @@
import org.postgresql.pljava.annotation.Function;
import static org.postgresql.pljava.annotation.Function.Effects.*;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
/**
* Some methods used for testing the SPI JDBC driver.
*
* @author Thomas Hallgren
*/
-@SQLActions({
- @SQLAction(provides = "employees tables", install = {
- "CREATE TABLE javatest.employees1" +
- " (" +
- " id int PRIMARY KEY," +
- " name varchar(200)," +
- " salary int" +
- " )",
-
- "CREATE TABLE javatest.employees2" +
- " (" +
- " id int PRIMARY KEY," +
- " name varchar(200)," +
- " salary int," +
- " transferDay date," +
- " transferTime time" +
- " )"
- }, remove = {
- "DROP TABLE javatest.employees2",
- "DROP TABLE javatest.employees1"
- }
- ),
- @SQLAction(requires = "issue228", install = "SELECT javatest.issue228()")
-})
+@SQLAction(provides = "employees tables", install = {
+ "CREATE TABLE javatest.employees1" +
+ " (" +
+ " id int PRIMARY KEY," +
+ " name varchar(200)," +
+ " salary int" +
+ " )",
+
+ "CREATE TABLE javatest.employees2" +
+ " (" +
+ " id int PRIMARY KEY," +
+ " name varchar(200)," +
+ " salary int," +
+ " transferDay date," +
+ " transferTime time" +
+ " )"
+ }, remove = {
+ "DROP TABLE javatest.employees2",
+ "DROP TABLE javatest.employees1"
+}
+)
+@SQLAction(requires = "issue228", install = "SELECT javatest.issue228()")
public class SPIActions {
private static final String SP_CHECKSTATE = "sp.checkState";
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Triggers.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Triggers.java
index f950a602c..804ef9d83 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Triggers.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/Triggers.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004-2013 Tada AB and other contributors, as listed below.
+ * Copyright (c) 2004-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -9,6 +9,7 @@
* Contributors:
* Tada AB
* Purdue University
+ * Chapman Flack
*/
package org.postgresql.pljava.example.annotation;
@@ -22,7 +23,6 @@
import org.postgresql.pljava.TriggerData;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.Trigger;
import static org.postgresql.pljava.annotation.Trigger.Called.*;
import static org.postgresql.pljava.annotation.Trigger.Constraint.*;
@@ -41,41 +41,39 @@
* version, set up in the {@link ConditionalDDR} example. Constraint triggers
* appear in PG 9.1, transition tables in PG 10.
*/
-@SQLActions({
- @SQLAction(
- provides = "foobar tables",
- install = {
- "CREATE TABLE javatest.foobar_1 ( username text, stuff text )",
- "CREATE TABLE javatest.foobar_2 ( username text, value numeric )"
- },
- remove = {
- "DROP TABLE javatest.foobar_2",
- "DROP TABLE javatest.foobar_1"
- }
- ),
- @SQLAction(
- requires = "constraint triggers",
- install = "INSERT INTO javatest.foobar_2(value) VALUES (45)"
- ),
- @SQLAction(
- requires = "foobar triggers",
- provides = "foobar2_42",
- install = "INSERT INTO javatest.foobar_2(value) VALUES (42)"
- ),
- @SQLAction(
- requires = { "transition triggers", "foobar2_42" },
- install = "UPDATE javatest.foobar_2 SET value = 43 WHERE value = 42"
- )
- /*
- * Note for another day: this would seem an excellent place to add a
- * regression test for github issue #134 (make sure invocations of a
- * trigger do not fail with SPI_ERROR_UNCONNECTED). However, any test
- * here that runs from the deployment descriptor will be running when
- * SPI is already connected, so a regression would not be caught.
- * A proper test for it will have to wait for a proper testing harness
- * invoking tests from outside PL/Java itself.
- */
-})
+@SQLAction(
+ provides = "foobar tables",
+ install = {
+ "CREATE TABLE javatest.foobar_1 ( username text, stuff text )",
+ "CREATE TABLE javatest.foobar_2 ( username text, value numeric )"
+ },
+ remove = {
+ "DROP TABLE javatest.foobar_2",
+ "DROP TABLE javatest.foobar_1"
+ }
+)
+@SQLAction(
+ requires = "constraint triggers",
+ install = "INSERT INTO javatest.foobar_2(value) VALUES (45)"
+)
+@SQLAction(
+ requires = "foobar triggers",
+ provides = "foobar2_42",
+ install = "INSERT INTO javatest.foobar_2(value) VALUES (42)"
+)
+@SQLAction(
+ requires = { "transition triggers", "foobar2_42" },
+ install = "UPDATE javatest.foobar_2 SET value = 43 WHERE value = 42"
+)
+/*
+ * Note for another day: this would seem an excellent place to add a
+ * regression test for github issue #134 (make sure invocations of a
+ * trigger do not fail with SPI_ERROR_UNCONNECTED). However, any test
+ * here that runs from the deployment descriptor will be running when
+ * SPI is already connected, so a regression would not be caught.
+ * A proper test for it will have to wait for a proper testing harness
+ * invoking tests from outside PL/Java itself.
+ */
public class Triggers
{
/**
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/UnicodeRoundTripTest.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/UnicodeRoundTripTest.java
index 568d64017..4f2c0ec47 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/UnicodeRoundTripTest.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/UnicodeRoundTripTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015 Tada AB and other contributors, as listed below.
+ * Copyright (c) 2015-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -15,7 +15,6 @@
import java.sql.SQLException;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.Function;
/**
@@ -39,18 +38,17 @@
* This example relies on {@code implementor} tags reflecting the PostgreSQL
* version, set up in the {@link ConditionalDDR} example, and also sets its own.
*/
-@SQLActions({
- @SQLAction(provides="postgresql_unicodetest",
- implementor="postgresql_ge_90000", install=
- "SELECT CASE" +
- " WHEN 'UTF8' = current_setting('server_encoding')" +
- " THEN set_config('pljava.implementors', 'postgresql_unicodetest,' ||" +
- " current_setting('pljava.implementors'), true) " +
- "END"
- ),
- @SQLAction(requires="unicodetest fn",
- implementor="postgresql_unicodetest",
- install=
+@SQLAction(provides="postgresql_unicodetest",
+ implementor="postgresql_ge_90000", install=
+ "SELECT CASE" +
+ " WHEN 'UTF8' = current_setting('server_encoding')" +
+ " THEN set_config('pljava.implementors', 'postgresql_unicodetest,' ||" +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
+@SQLAction(requires="unicodetest fn",
+implementor="postgresql_unicodetest",
+install=
" with " +
" usable_codepoints ( cp ) as ( " +
" select generate_series(1,x'd7ff'::int) " +
@@ -88,15 +86,14 @@
" 'all Unicode codepoint ranges roundtripped successfully.') " +
" end " +
" from test_summary"
- ),
- @SQLAction(
- install=
- "CREATE TYPE unicodetestrow AS " +
- "(matched boolean, cparray integer[], s text)",
- remove="DROP TYPE unicodetestrow",
- provides="unicodetestrow type"
- )
-})
+)
+@SQLAction(
+ install=
+ "CREATE TYPE unicodetestrow AS " +
+ "(matched boolean, cparray integer[], s text)",
+ remove="DROP TYPE unicodetestrow",
+ provides="unicodetestrow type"
+)
public class UnicodeRoundTripTest {
/**
* This function takes a string and an array of ints constructed in PG,
diff --git a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/XMLRenderedTypes.java b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/XMLRenderedTypes.java
index ca7f501d9..871e96445 100644
--- a/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/XMLRenderedTypes.java
+++ b/pljava-examples/src/main/java/org/postgresql/pljava/example/annotation/XMLRenderedTypes.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019 Tada AB and other contributors, as listed below.
+ * Copyright (c) 2019-2020 Tada AB and other contributors, as listed below.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the The BSD 3-Clause License
@@ -17,7 +17,6 @@
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLAction;
-import org.postgresql.pljava.annotation.SQLActions;
import org.postgresql.pljava.annotation.SQLType;
import static org.postgresql.pljava.example.LoggerTest.logMessage;
@@ -30,16 +29,14 @@
* in case of being loaded into a PostgreSQL instance built without that type.
* The {@code pg_node_tree} type appears in 9.1.
*/
-@SQLActions({
- @SQLAction(implementor="postgresql_ge_90100",
- provides="postgresql_xml_ge91",
- install=
- "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
- " THEN set_config('pljava.implementors', 'postgresql_xml_ge91,' || " +
- " current_setting('pljava.implementors'), true) " +
- "END"
- )
-})
+@SQLAction(implementor="postgresql_ge_90100",
+ provides="postgresql_xml_ge91",
+ install=
+ "SELECT CASE (SELECT 1 FROM pg_type WHERE typname = 'xml') WHEN 1" +
+ " THEN set_config('pljava.implementors', 'postgresql_xml_ge91,' || " +
+ " current_setting('pljava.implementors'), true) " +
+ "END"
+)
public class XMLRenderedTypes
{
@Function(schema="javatest", implementor="postgresql_xml_ge91")