tag:github.com,2008:/tada/pljava/wikipljava: Recent Wiki Updates2025-09-29T12:51:54-04:00https://github.com/tada/pljava/wiki/c68e24c235759ab05a1174c53e1ebeaed0dd9f482025-09-29T12:51:54-04:002025-09-29T12:51:54-04:00Homejcflack
<p><img src="https://camo.githubusercontent.com/d329aef7d57e31ec241d8338d4fd151f5c56599ead67823b272ec6f2c587f59a/68747470733a2f2f7261772e6769746875622e636f6d2f746164612f706c6a6176612f67682d70616765732f696d616765732f706c6a6176615f6c6f676f2e6a7067" alt="PL/Java" data-canonical-src="https://raw.github.com/tada/pljava/gh-pages/images/pljava_logo.jpg"></p>
<div class="markdown-heading"><h1 class="heading-element">Welcome to PL/Java</h1><a id="user-content-welcome-to-pljava" class="anchor" aria-label="Permalink: Welcome to PL/Java" href="#welcome-to-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>If you have comments or ideas regarding this wiki, please convey them on the
<a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">Mailing List</a>.
A great deal of information can also be found at
the <a href="https://tada.github.io/pljava/" rel="nofollow">project information site</a>.</p>
<table role="table">
<tbody><tr>
<td></td>
<th scope="col" colspan="2">Releases quick guide</th>
</tr>
<tr>
<td></td>
<th scope="col">1.6 series</th>
<th scope="row">1.5 series</th>
</tr>
<tr>
<th scope="row">Description</th>
<td>
Current recommended; for PostgreSQL 9.5 and later, Java 9 and later.
Upgrades from the 1.5 series should be planned upgrades; please review
the <a href="http://tada.github.io/pljava/releasenotes.html" rel="nofollow">release notes</a>
1.6.0 to current.
</td>
<td>
Legacy support, for PostgreSQL back to 8.2, Java back to 6.
Will not build with Java 15 or later. Can be used with 15 through 23 if
built with an earlier JDK.
</td>
</tr>
<tr>
<th scope="row">Latest</th>
<td><a href="https://github.com/tada/pljava/releases/tag/V1_6_10">1.6.10</a></td>
<td><a href="https://github.com/tada/pljava/releases/tag/V1_5_8">1.5.8</a></td>
</tr>
</tbody></table>
<div class="markdown-heading"><h2 class="heading-element">Important news</h2><a id="user-content-important-news" class="anchor" aria-label="Permalink: Important news" href="#important-news"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>For <strong>implications of running on Java 24 and later</strong>, please see <a class="internal present" href="/tada/pljava/wiki/JEP-411">JEP 411</a>.</p>
<div class="markdown-heading"><h2 class="heading-element">Overview</h2><a id="user-content-overview" class="anchor" aria-label="Permalink: Overview" href="#overview"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java is a free add-on module that brings Java™ Stored Procedures, Triggers,
and Functions to the <a href="http://www.postgresql.org/" rel="nofollow">PostgreSQL™</a> backend. The
development started late 2003 and the first release of PL/Java arrived in
January 2005. The project is released under the <a class="internal present" href="/tada/pljava/wiki/PLJava-License">PLJava License</a> license.</p>
<div class="markdown-heading"><h2 class="heading-element">Features</h2><a id="user-content-features" class="anchor" aria-label="Permalink: Features" href="#features"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>Ability to write functions, triggers, user-defined types, ...
using recent Java versions. (To see the currently-targeted versions,
please see <a href="https://tada.github.io/pljava/build/versions.html" rel="nofollow">the versions page</a>.)</li>
</ul>
<ul>
<li>Standardized utilities (modeled after the SQL 2003 proposal) to install and
maintain Java code in the database.</li>
<li>Standardized mappings of parameters and result. Supports scalar and
composite user-defined types (UDTs), pseudo types, arrays, and sets.</li>
<li>An embedded, high performance JDBC driver utilizing the internal PostgreSQL
SPI routines.</li>
<li>Metadata support for the JDBC driver. Both DatabaseMetaData and
ResultSetMetaData are included.</li>
<li>Integration with PostgreSQL savepoints and exception handling.</li>
<li>Ability to use IN, INOUT, and OUT parameters</li>
<li>Two language handlers, <code>javau</code> (functions not restricted in behavior,
only superusers can create them) and <code>java</code> (functions run under a
security manager blocking filesystem access, users who can create them
configurable with <code>GRANT</code>/<code>REVOKE</code>). <strong>For implications of running on
Java 24 and later, please see <a class="internal present" href="/tada/pljava/wiki/JEP-411">JEP 411</a></strong>.</li>
<li>Transaction and Savepoint listeners enabling code execution when a
transaction or savepoint is commited or rolled back.</li>
</ul>
<p><em>PL/Java earlier supported GCJ, but targets conventional Java
virtual machines for current development.</em></p>
<div class="markdown-heading"><h2 class="heading-element">Documentation</h2><a id="user-content-documentation" class="anchor" aria-label="Permalink: Documentation" href="#documentation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The first stop for <em>up-to-date</em> documentation should be the
<a href="https://tada.github.io/pljava/" rel="nofollow">project information site</a>.</p>
<p>You may also find useful information via the wiki links below.
Information here will be migrating to the <a href="https://tada.github.io/pljava/" rel="nofollow">project information site</a>
as it is brought up to date.</p>
<p><a class="internal present" href="/tada/pljava/wiki/Installation-guide">Installation Guide</a><br>
<a class="internal present" href="/tada/pljava/wiki/User-guide">User Guide</a><br>
<a class="internal present" href="/tada/pljava/wiki/Contribution-guide">Contribution Guide</a></p>
<div class="markdown-heading"><h2 class="heading-element">Resources</h2><a id="user-content-resources" class="anchor" aria-label="Permalink: Resources" href="#resources"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><em>Note: To be sure of running a current PL/Java, please check the
<a href="/tada/pljava/releases">releases</a> page to see what is current. You may check for any
<a class="internal present" href="/tada/pljava/wiki/Prebuilt-packages">prebuilt packages</a> available for your platform. If prebuilt packages are
not available for your platform, or if they are behind the current version,
please consider <a href="https://tada.github.io/pljava/build/build.html" rel="nofollow">Building PL/Java</a> using the source here on GitHub.</em></p>
<p>The "no longer supported" downloads linked below are quite old and of
chiefly historical interest.</p>
<p><a href="/tada/pljava/releases">Source downloads</a><br>
<a class="internal present" href="/tada/pljava/wiki/Prebuilt-packages">Prebuilt packages</a><br>
<a href="https://web.archive.org/web/20161105202944/http://pgfoundry.org/frs/?group_id=1000038" rel="nofollow">No longer supported downloads</a><br>
<a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">Mailing List</a><br>
Questions tagged <code>pljava</code> <a href="https://stackoverflow.com/questions/tagged/?tagnames=pljava&sort=newest" rel="nofollow">on Stack Overflow</a> (Atom <a href="https://stackoverflow.com/feeds/tag?tagnames=pljava&sort=newest" rel="nofollow">feed</a>)<br>
Feed for <a href="/tada/pljava/wiki.atom">changes to this wiki itself</a><br>
<a href="/tada/pljava/issues">Bug Tracking</a><br>
<a href="https://web.archive.org/web/20180216005532/http://pgfoundry.org/tracker/?group_id=1000038" rel="nofollow">Older bug tracker at PgFoundry</a><br>
<a href="https://web.archive.org/web/20071104170322/http://gborg.postgresql.org:80/project/pljava/bugs/buglist.php" rel="nofollow">Even older bug tracker at GBorg</a></p>
<div class="markdown-heading"><h2 class="heading-element">Technology</h2><a id="user-content-technology" class="anchor" aria-label="Permalink: Technology" href="#technology"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><a class="internal present" href="/tada/pljava/wiki/Technology-in-brief">Technology in Brief</a><br>
<a class="internal present" href="/tada/pljava/wiki/The-choice-of-JNI">The choice of JNI</a></p>
https://github.com/tada/pljava/wiki/Contribution-guide/91d866470738bf46435d0f3e0f2a9e203341354f2025-05-31T17:15:34-04:002025-05-31T17:15:34-04:00Contribution guidejcflack
<p>PL/Java is an open source project and contributions are vital for its success. In fact, all development of the project is done using contributions. Here are a few guide lines that will help you submit a contribution.</p>
<div class="markdown-heading"><h2 class="heading-element">Getting started</h2><a id="user-content-getting-started" class="anchor" aria-label="Permalink: Getting started" href="#getting-started"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>Make sure you have a <a href="/signup/free">GitHub account</a>.</li>
<li>Create a fork of the <a href="/tada/pljava">PL/Java repository</a>.</li>
<li>Take a look at the <a href="http://sethrobertson.github.com/GitBestPractices/">Git Best Practices</a> document.</li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Let people know what you're planning</h2><a id="user-content-let-people-know-what-youre-planning" class="anchor" aria-label="Permalink: Let people know what you're planning" href="#let-people-know-what-youre-planning"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>You should let the community know what you're planning to do by discussing it on the <a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">PL/Java Mailing List</a>. In many cases it might also be a good idea to first <a href="/tada/pljava/issues">create an issue</a> where the details of what needs to be done can be discussed (the actual pull-request is an issue in itself so in case you already have something, that issue is probably sufficient).</p>
<div class="markdown-heading"><h2 class="heading-element">Making Changes</h2><a id="user-content-making-changes" class="anchor" aria-label="Permalink: Making Changes" href="#making-changes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>Create a local clone of your fork.</li>
<li>Choose an appropriate PL/Java branch as the base for your contribution.
This guide used to say "You should branch off the <em>master</em> branch", but that
is not always the best choice. Please take a moment to look at
<a href="#which-branch-base">Which PL/Java branch to base on?</a> below. Then pop that
section off your reading stack and return to this point. :)</li>
<li>Create a topic branch for your work. You should base it on the branch you
selected in the previous step. Name your branch by the type of contribution,
source branch, and nature of the contribution, for example,
<code>bug/master/my_contribution</code>. Generally, the type is <code>bug</code>, or <code>feature</code>,
but you can use something else if those don't fit. You can look at existing
branch names in the repository for ideas. To create a topic branch
based on <code>master</code>:
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="git checkout master && git pull && git checkout -b bug/master/my_contribution"><pre class="notranslate"><code>git checkout master && git pull && git checkout -b bug/master/my_contribution
</code></pre></div>
</li>
<li>Don't work directly on the <em>master</em> branch, or any other core branch. Your pull request will be rejected unless it is on a topic branch.</li>
<li>As to source code formatting and other coding conventions, please look at the
upstream <a href="https://www.postgresql.org/docs/current/source.html" rel="nofollow">PostgreSQL Coding Conventions</a>. PL/Java generally follows those,
only without using the automated <code>pgindent</code> tool, so if there is a place
in your code that some slight departure from those rules could make much
easier to read, then you may do the more-readable thing and not worry about
something like <code>pgindent</code> messing it up.</li>
<li>Keep your commits distinct. Each commit should accomplish one clear step in
the development of your contribution, and include whatever changes to
whatever files were needed for that step ... and then the next clear step
should come in another commit. Please look at
<a href="#organizing-commits">Organizing commits</a> below for more on this.</li>
<li>Make sure your commit messages are in <a href="#wiki-commit-message-format">the proper format</a>.</li>
<li>If your commit fixes an issue, close it with your commit message (by appending, e.g., fixes #1234, to the summary).</li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Submitting Changes</h2><a id="user-content-submitting-changes" class="anchor" aria-label="Permalink: Submitting Changes" href="#submitting-changes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>Be sure to test your changes! Test more than just the build,
where appropriate; for example, test the documentation build
(<code>mvn site site:stage</code>) if you have edited documentation files,
<code>javadoc</code> comments, the version of <code>maven-site-plugin</code>, etc.</li>
<li>Keep in mind the range of PostgreSQL and Java versions that should be
supported by the branch of PL/Java you are working on. The <code>REL1_6_STABLE</code>
branch, for example, documents support for PostgreSQL back to 9.5
and Java back to 9. Be careful not to introduce hard dependencies on newer
versions. Test on older supported versions if you can.</li>
<li>Push your changes to a topic branch in your fork of the repository.</li>
<li>Submit a pull request to the <code>tada/pljava</code> repository.</li>
</ul>
<p><a id="user-content-which-branch-base"></a></p>
<div class="markdown-heading"><h2 class="heading-element">Which PL/Java branch to base on?</h2><a id="user-content-which-pljava-branch-to-base-on" class="anchor" aria-label="Permalink: Which PL/Java branch to base on?" href="#which-pljava-branch-to-base-on"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In many projects, active development all happens on a branch called something
like <em>main</em> (or sometimes <em>master</em> in a project as old as PL/Java) and, if
there are older branches supporting released versions, selected changes get
"backpatched" into those.</p>
<p>PL/Java's development does not, at present, fit into that model. There are
currently (as of mid-2025) two distinct threads of development taking place
in the project:</p>
<ul>
<li>Ongoing maintenance of PL/Java 1.6.x, which is what's in active use and gets
regular minor-number releases, takes place on the <code>REL1_6_STABLE</code> branch.</li>
<li>The <code>REL1_7_STABLE</code> branch is reserved for a future release once a major
refactoring and modernization is complete. The progress of the refactoring
is being tracked in a long-lived pull request, <a href="https://github.com/tada/pljava/pull/399">PR 399</a>. PR 399 is
effectively the branch <a href="https://github.com/tada/pljava/tree/feature/REL1_7_STABLE/model"><code>feature/REL1_7_STABLE/model</code></a>.</li>
<li>The branch called <code>master</code> has a future major version of 2 reserved, but
nothing is really happening on that branch at present.</li>
</ul>
<p>Under the current development practice, maintenance changes that are made on
<code>REL1_6_STABLE</code> get merged forward so that the <code>master</code> and <code>REL1_7_STABLE</code>
branches do not fall behind.</p>
<p>Under these conditions, you have these most-likely choices of branch to form
the base of your contribution:</p>
<ul>
<li>If your contribution is a simple bug fix to currently-in-release PL/Java 1.6,
use <code>REL1_6_STABLE</code> as the base.</li>
<li>Or, if your contribution is a simple new feature that you would like to have
soon in a regular release (and is straightforward enough that you will not
mind having to build it in the devilishly-hard-to-maintain unrefactored
1.6 code base!), use <code>REL1_6_STABLE</code> as your base for that too.</li>
<li>For any more ambitious contribution you would like to make to the future
of PL/Java, the best choice will be to base your branch on <code>REL1_7_STABLE</code>
and regularly merge <code>feature/REL1_7_STABLE/model</code> into it to keep it up
to date. You should study the <a href="https://github.com/tada/pljava/pull/399">PR 399</a> pull-request comments to understand
the new interfaces available and prefer them to the ones being deprecated.</li>
</ul>
<p><a id="user-content-organizing-commits"></a></p>
<div class="markdown-heading"><h2 class="heading-element">Organizing commits</h2><a id="user-content-organizing-commits" class="anchor" aria-label="Permalink: Organizing commits" href="#organizing-commits"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Some projects request that you squash multiple commits into one before
submitting a pull request, but that is not wanted in the PL/Java project.
Any pull request more involved than the simplest bug fix should probably
consist of more than one commit. Each commit should cover a clear step along
the path from PL/Java-without-the-new-feature to PL/Java-with-it, and the
commit message for each step should explain that step, and explain whatever
key decisions led to that step being done that way and not some other way.</p>
<p>This does not mean that a pull request should be all the commits that you
made in your local repository clone as you developed the contribution, with
all the times you backtracked, fixed typos, and changed your mind. As soon
as you feel you have something ready to submit, you should look back over
the history of your commits and think of a way to organize them into a
deliberate sequence of steps, clear enough for another reader to easily follow,
for getting from PL/Java-without-the-feature to PL/Java-with.</p>
<p>At that point, you should become familiar with <code>git rebase --interactive</code>
if you are not already, and use it to rework your commits into the sequence
that will tell your clear story. Look over the new commit history after
you have done that. If you see that it is good, it is ready to be included
in a pull request.</p>
<div class="markdown-heading"><h3 class="heading-element">But generally avoid force-pushing to a shared repository</h3><a id="user-content-but-generally-avoid-force-pushing-to-a-shared-repository" class="anchor" aria-label="Permalink: But generally avoid force-pushing to a shared repository" href="#but-generally-avoid-force-pushing-to-a-shared-repository"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>If you have interactively revised a history of commits, then the next time
you push to a git repository where the old commits existed, a "force-push"
will be needed because the history has changed.</p>
<p>That is a non-problem as long as you are working locally and pushing into your
own locally-cloned repository. Once you have pushed some commits up to a
shared repository, on the other hand, it is possible other people have linked
to those or based branches on them, and a force-push that changes them will
create problems for others.</p>
<p>Therefore, it makes sense to force-push freely and often in your own local
repository, as much as you need while reorganizing your commits into a
coherent story. But once you have pushed those commits up to a visible
repository, it is best to leave them as they are. If you have pushed some
commits before your development is complete, then as you continue the work
in a further sequence of commits, you can again freely revise that sequence
locally until you have another sequence ready to push, and then push that
sequence upstream and leave it alone as well. If you discover a mistake in
something already pushed and publicly visible, that should just be fixed
somewhere in your next sequence of commits.</p>
<p>Most rules can be bent: if you have just pushed something up to a public
repository and then recognized a mistake minutes or seconds later, a force-push
may be ok if no one else is likely to have saved references to your branch
during that time.</p>
<p><a id="user-content-commit-message-format"></a></p>
<div class="markdown-heading"><h2 class="heading-element">Commit Message Format</h2><a id="user-content-commit-message-format" class="anchor" aria-label="Permalink: Commit Message Format" href="#commit-message-format"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>What should be included in a commit message?
The three basic things to include are:</p>
<ul>
<li>Summary or title.</li>
<li>Detailed description</li>
<li>Issue number (optional).</li>
</ul>
<p>Here is a sample commit message with all that information:</p>
<pre>Adds UTF-8 encoding to POM properties
Some POM's did not have the source encoding specified. This
caused unnecessary warning printouts during build. This commit
ensures that all POM's includes the correct declaration for
UTF-8.
Closes #1234
</pre>
<p>The summary should be kept short, no more than 49 characters, and
the lines in the detailed message should not exceed 72 characters.
These limits are recommended to get the best output possible from
the <code>git log</code> command and also to be able to view the commits in
a terminal window with 80 character limit.</p>
<p>The issue number is optional and should only be included when the commit really closes an issue. The close will then occur when the pull request is merged.</p>
https://github.com/tada/pljava/wiki/JEP-411/a7e9f97ec5e87f43f4e757b79965a3512d9efa112025-03-23T18:01:03-04:002025-03-23T18:01:03-04:00JEP 411jcflack
<div class="markdown-heading"><h1 class="heading-element">PL/Java and JEP 411: Java 17, Java 24, and beyond</h1><a id="user-content-pljava-and-jep-411-java-17-java-24-and-beyond" class="anchor" aria-label="Permalink: PL/Java and JEP 411: Java 17, Java 24, and beyond" href="#pljava-and-jep-411-java-17-java-24-and-beyond"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Changes in Java, first announced with Java 17 and of serious consequence in
Java 24, force important functional changes in PL/Java.</p>
<div class="markdown-heading"><h2 class="heading-element">Permissions and enforcement in PL/Java</h2><a id="user-content-permissions-and-enforcement-in-pljava" class="anchor" aria-label="Permalink: Permissions and enforcement in PL/Java" href="#permissions-and-enforcement-in-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java supports at least two PostgreSQL <code>CREATE LANGUAGE</code> declarations,
one with and one without <a href="https://www.postgresql.org/docs/9.6/sql-createlanguage.html#SQL-CREATELANGUAGE-PARAMETERS" rel="nofollow">the <code>TRUSTED</code> property</a>, and
enforces limits on what a function declared in the <code>TRUSTED</code> language can do.
The PL/Java 1.6 series goes further and makes those restrictions configurable,
and more than two PL/Java "languages" can be declared, with different
configurable restrictions for each, as described
<a href="https://tada.github.io/pljava/use/policy.html" rel="nofollow">in the documentation</a>.</p>
<p>To provide and support these controls, PL/Java relies on many features of the
groundbreaking <a href="https://docs.oracle.com/javase/8/docs/technotes/guides/security/spec/security-spec.doc12.html" rel="nofollow">Java 2 security architecture</a> as specified in 2002.</p>
<div class="markdown-heading"><h2 class="heading-element">Changes in Java 17 and beyond: JEP 411</h2><a id="user-content-changes-in-java-17-and-beyond-jep-411" class="anchor" aria-label="Permalink: Changes in Java 17 and beyond: JEP 411" href="#changes-in-java-17-and-beyond-jep-411"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In April 2021, the Java developers announced a JDK Enhancement Proposal,
<a href="https://openjdk.java.net/jeps/411" rel="nofollow">JEP 411</a>, to remove this functionality from Java over a
series of releases, with the first changes already shipped in Java 17.</p>
<p>As <a href="https://books.google.com/books?id=XfWlYWVzo20C&pg=PA35&lpg=PA35&dq=%22the+major+components+of+the+security+model+are+security+policy,+access+permissions,+protection+domain,+access+control+checking,+privileged+operation,+and+class+loading+and+resolution%22" rel="nofollow">originally described</a>, the "major components of the
security model are security policy, access permissions, protection domain,
access control checking, privileged operation,
and class loading and resolution." JEP 411 announced eventual elimination of the
first, fourth and fifth, with the second and third to remain in vestigial form.
PL/Java's policy enforcement relies on the affected Java features.</p>
<div class="markdown-heading"><h3 class="heading-element">Java 17</h3><a id="user-content-java-17" class="anchor" aria-label="Permalink: Java 17" href="#java-17"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In Java 17, all of the functionality remains; only warnings and
deprecation markings have been added. Java 17 and 21 are also positioned as
long-term support releases, successors in that role to Java 11. It will
therefore be possible to run current PL/Java versions without difficulty
for a number of years.</p>
<p>However, Java 17 will be designed to write an unconditional warning on its
standard error channel (which will go into PostgreSQL's log file, if
<code>logging_collector</code> is enabled), every time any backend loads PL/Java.
The JEP 411 proponents <a href="https://mail.openjdk.java.net/pipermail/security-dev/2021-May/026207.html" rel="nofollow">rebuffed requests</a> to allow a higher layer,
like PL/Java, to suppress the low-level JVM warning and issue one that is
layer-appropriate (such as an explanation about trusted functions or a link
to this wiki page).</p>
<p>The JVM's boilerplate warning will look like this:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by org.postgresql.pljava.internal.Backend
WARNING: Please consider reporting this to the maintainers of org.postgresql.pljava.internal.Backend
WARNING: System::setSecurityManager will be removed in a future release"><pre class="notranslate"><code>WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by org.postgresql.pljava.internal.Backend
WARNING: Please consider reporting this to the maintainers of org.postgresql.pljava.internal.Backend
WARNING: System::setSecurityManager will be removed in a future release
</code></pre></div>
<p>As much as the warnings will urge you, please do not consider reporting
them to the maintainers of PL/Java.</p>
<p>The PL/Java 1.6 series, as described below, does attempt to suppress the boilerplate JVM warning, and issue a "migration advisory" <code>ereport</code> of a more useful nature, only upon certain administrative actions like <code>CREATE EXTENSION</code> or installing a jar, and no more than once in a session. That should cut down on the log spam.</p>
<div class="markdown-heading"><h3 class="heading-element">Java 18 through 23</h3><a id="user-content-java-18-through-23" class="anchor" aria-label="Permalink: Java 18 through 23" href="#java-18-through-23"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>When run on Java 18 through 23, PL/Java can still provide policy enforcement and
a trusted/untrusted language distinction, but requires a specific JVM option
added in the <code>pljava.vmoptions</code> configuration setting:</p>
<ul>
<li>
<code>-Djava.security.manager=allow</code> will allow PL/Java to work as it always has,
with policy enforcement</li>
<li>
<code>-Djava.security.manager=disallow</code> will allow running PL/Java (1.6.9 or later)
<em>with no policy enforcement</em>, as described in <a href="https://tada.github.io/pljava/use/unenforced.html" rel="nofollow">new documentation</a>
</li>
</ul>
<p>Without one or the other of those settings, PL/Java 1.5 or 1.6 will fail
to start on Java 18 through 23.</p>
<div class="markdown-heading"><h3 class="heading-element">Java 24 and later</h3><a id="user-content-java-24-and-later" class="anchor" aria-label="Permalink: Java 24 and later" href="#java-24-and-later"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>With Java 24, only the <code>-Djava.security.manager=disallow</code> option (and therefore
only PL/Java 1.6.9 or later) will work, as the crucial Java language features
are no longer implemented. Where policy enforcement is needed, current PL/Java
releases should be run on any
earlier Java version, including 17 and 21, which are positioned for long-term support.</p>
<p>In some future Java version, the needed Java features will not be merely
unimplemented but removed from the API, and current PL/Java versions will fail
to compile, and fail with linkage errors at runtime. A future PL/Java version
will be needed that eliminates hard dependencies on the affected APIs.</p>
<div class="markdown-heading"><h2 class="heading-element">Plans for PL/Java release series</h2><a id="user-content-plans-for-pljava-release-series" class="anchor" aria-label="Permalink: Plans for PL/Java release series" href="#plans-for-pljava-release-series"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">PL/Java 1.5 series</h3><a id="user-content-pljava-15-series" class="anchor" aria-label="Permalink: PL/Java 1.5 series" href="#pljava-15-series"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java 1.5 is the series minimally maintained for legacy support (PostgreSQL
back to 8.2, Java back to 6). Its build process requires Java 14 or earlier,
but it can be run on later Java versions. Minimal changes will be made in 1.5.</p>
<ul>
<li>Because it already does not support building on newer Java versions, it
will not need any source code changes to suppress the new deprecation
warnings.</li>
<li>It will make no attempt to intercept the fixed warning message described
above. When running on Java 17 or later, that warning will be written
on the backend's standard error channel, every time a backend starts
PL/Java.</li>
<li>Code will not be added to automatically supply the
<code>-Djava.security.manager=allow</code> option for any Java version.</li>
<li>Code will be added (in 1.5.8) to attempt to detect when the needed
components have become no-ops, and then throw an exception rather than
executing any function declared as <code>trusted</code>.</li>
</ul>
<p>Options if that exception is seen can include:</p>
<ul>
<li>Continuing to use PL/Java 1.5, downgrading Java to the preceding version</li>
<li>Changing all <code>trusted</code> function declarations to untrusted and accepting that
they will run without security enforcement</li>
<li>Upgrading to a newer PL/Java version if available.</li>
</ul>
<p>Note that even functions declared as untrusted have normally had a few limits
enforced in PL/Java 1.5, and even those limits will be unenforced if running
on a version of Java where the needed components are no-ops.</p>
<div class="markdown-heading"><h3 class="heading-element">PL/Java 1.6 series</h3><a id="user-content-pljava-16-series" class="anchor" aria-label="Permalink: PL/Java 1.6 series" href="#pljava-16-series"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java 1.6 is the current recommended series covering PostgreSQL 9.5 and later,
Java 9 and later.</p>
<ul>
<li>Code added in 1.6.3 attempts to suppress the boilerplate, low-level
warning from the JVM, so that more meaningful notice in relevant PL/Java
terms can be given. Suppression of the boilerplate is best-effort,
relying on JDK internals, given the <a href="https://mail.openjdk.java.net/pipermail/security-dev/2021-May/026207.html" rel="nofollow">rebuffed request</a> for
an exposed control serving that purpose.</li>
<li>Code added in 1.6.3:
<ul>
<li>Issues warnings (or notices) of the upcoming JEP 411 impacts, including
a link to this wiki page</li>
<li>Issues the warning whenever the runtime Java major version is above 11,
so as to warn not only sites that have moved from 11 LTS to 17 LTS,
but also sites that update more frequently between LTS versions</li>
<li>Issues the warning when PL/Java is installed or upgraded, or when
a cluster that has PL/Java installed undergoes a binary <code>pg_upgrade</code>
(in the <code>pg_upgrade</code> case, the warning will be unconditional, because
no JVM is started at that time to query its version)</li>
<li>Issues the warning, at most one per session, at commit of a transaction
that has declared or redeclared at least one PL/Java function</li>
<li>Refuses to execute, if the needed support is detectably stubbed out,
unless a special configuration option is set</li>
</ul>
</li>
<li>Code added in 1.6.9:
<ul>
<li>Supports use in a <em>without enforcement</em> mode described in
<a href="https://tada.github.io/pljava/use/unenforced.html" rel="nofollow">new documentation</a>
</li>
</ul>
</li>
<li>1.6.9 will not be usable on whatever version of Java finally removes the
deprecated APIs. It will fail with linkage errors.</li>
<li>A release after 1.6.9 may also be adapted to run without linkage errors on
a Java version where the APIs have been finally removed.</li>
</ul>
<p>Note that even functions declared as untrusted run with significant limits
by default in PL/Java 1.6, and the limits on both trusted and untrusted
functions are configurable in policy, and <em>all such limits will be unenforced</em>
if running without enforcement. The <a href="https://tada.github.io/pljava/use/unenforced.html" rel="nofollow">new documentation</a> should be
reviewed carefully before using PL/Java in that mode.</p>
<p>PL/Java 1.6 will continue to see active development for the foreseeable future.
The existing enforcement mechanisms remain functional through Java 23, including
Java 21 LTS, and for some applications, its fine-grained security policy
may remain more attractive than what post-JEP-411 versions will support.</p>
<div class="markdown-heading"><h3 class="heading-element">PL/Java ?.?</h3><a id="user-content-pljava-" class="anchor" aria-label="Permalink: PL/Java ?.?" href="#pljava-"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A new major version of PL/Java will need to be developed that can support
some notion of trusted-function enforcement without relying on the rescinded
Java mechanisms.</p>
<p>This will be a big undertaking, and will have to scale back expectations
to a much more basic model of what can be enforced: chiefly filesystem access,
process manipulations, and IPC. The result will probably land somewhere more
fine-grained and configurable than PL/Java 1.5, but much less so than 1.6.</p>
<p>All usual disclaimers about forward-looking statements must be applied.</p>
<p>During that development, both existing PL/Java series can continue to be used
with the limitations described above.</p>
<div class="markdown-heading"><h3 class="heading-element">An OpenJDK fork to maintain policy enforcement</h3><a id="user-content-an-openjdk-fork-to-maintain-policy-enforcement" class="anchor" aria-label="Permalink: An OpenJDK fork to maintain policy enforcement" href="#an-openjdk-fork-to-maintain-policy-enforcement"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A fork of OpenJDK, independent of the PL/Java project, has been made whose goal
is to track the feature development of OpenJDK 24 and later while maintaining
support for policy enforcement.</p>
<p>If the project is successful and proves usable as a JVM runtime for PL/Java,
it may offer an attractive option for applications where both policy
enforcement and the most modern Java language features are wanted. It may be
worthy of support by organizations seeking such an option.</p>
<p>That project can be found on GitHub <a href="https://github.com/pfirmstone/jdk-with-authorization">here</a>.</p>
<p>This page will be updated as more is learned about that project's success
and usability with PL/Java.</p>
https://github.com/tada/pljava/wiki/Build-tips/0675a25a8203022d0deeeb7565395eb5a01cd2aa2024-04-12T11:26:27-04:002024-04-12T11:26:27-04:00Build tipsjcflack
<div class="markdown-heading"><h1 class="heading-element">Tips for resolving build problems</h1><a id="user-content-tips-for-resolving-build-problems" class="anchor" aria-label="Permalink: Tips for resolving build problems" href="#tips-for-resolving-build-problems"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Some typical issues encountered when building PL/Java can be listed here,
along with tips for resolving them.</p>
<div class="markdown-heading"><h2 class="heading-element">The tips that always apply</h2><a id="user-content-the-tips-that-always-apply" class="anchor" aria-label="Permalink: The tips that always apply" href="#the-tips-that-always-apply"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Please do carefully read the <a href="https://tada.github.io/pljava/build/build.html" rel="nofollow">build instructions</a>,
especially the "software prerequisites" section, and the "special topics"
section for any that apply to the platform where you are building.</p>
<p>Also be sure to review the "troubleshooting the build" section at the end
of the <a href="https://tada.github.io/pljava/build/build.html" rel="nofollow">build instructions page</a>.</p>
<p>If you review <a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">the mailing list archive</a> and the
<a href="https://github.com/tada/pljava/issues">issues list</a>, you may find a report of a situation like your own.
(On the issues list, it is possible someone reported an issue, a solution
was found, and the issue was closed, so look at recent closed issues too.)</p>
<div class="markdown-heading"><h2 class="heading-element">Failure shown for <code>pljava-api</code>
</h2><a id="user-content-failure-shown-for-pljava-api" class="anchor" aria-label="Permalink: Failure shown for pljava-api" href="#failure-shown-for-pljava-api"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">
<code>Fatal error compiling</code> caused by <code>invalid flag: --release</code>
</h3><a id="user-content-fatal-error-compiling-caused-by-invalid-flag---release" class="anchor" aria-label="Permalink: Fatal error compiling caused by invalid flag: --release" href="#fatal-error-compiling-caused-by-invalid-flag---release"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>By itself, <code>Fatal error compiling</code> isn't very helpful. Use Maven's <code>-e</code>
option to get full exception stack traces.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal ...:compile (default-compile) on project pljava-api: Fatal error compiling
...
Caused by: org.apache.maven.plugin.MojoExecutionException: Fatal error compiling
...
Caused by: org.codehaus.plexus.compiler.CompilerException: invalid flag: --release
...
Caused by: java.lang.IllegalArgumentException: invalid flag: --release
at com.sun.tools.javac.api.JavacTool.processOptions
...
at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess"><pre class="notranslate"><code>org.apache.maven.lifecycle.LifecycleExecutionException: Failed to execute goal ...:compile (default-compile) on project pljava-api: Fatal error compiling
...
Caused by: org.apache.maven.plugin.MojoExecutionException: Fatal error compiling
...
Caused by: org.codehaus.plexus.compiler.CompilerException: invalid flag: --release
...
Caused by: java.lang.IllegalArgumentException: invalid flag: --release
at com.sun.tools.javac.api.JavacTool.processOptions
...
at org.codehaus.plexus.compiler.javac.JavaxToolsCompiler.compileInProcess
</code></pre></div>
<p>If you see a stack trace like this building the PL/Java 1.6 series or later,
you simply have Maven running on a Java version that is too old. PL/Java 1.6.x
requires Java 9 or later.</p>
<p>It can be possible to have the environment set up so that simple command</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="javac --version"><pre>javac --version</pre></div>
<p>at the shell will find the <code>javac</code> that you want on the <code>PATH</code> and report
that version, but the <code>mvn</code> command finds a different installed Java version
and uses it to run Maven. Because Maven does Java compilation in-process,
the PL/Java code ends up being compiled by whatever Java version is running
Maven itself. If that version is not at least Java 9, this error results.
The command</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="mvn --version"><pre>mvn --version</pre></div>
<p>is useful because it does not show only the version of Maven, but also the
version of Java that Maven has found to run with.</p>
<p>The <code>JAVA_HOME</code> variable can be set in the environment to ensure Maven
runs on the needed version of Java.</p>
<div class="markdown-heading"><h2 class="heading-element">Failure shown for <code>pljava-so</code>
</h2><a id="user-content-failure-shown-for-pljava-so" class="anchor" aria-label="Permalink: Failure shown for pljava-so" href="#failure-shown-for-pljava-so"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">Missing <code>-devel</code> prerequisite packages</h3><a id="user-content-missing--devel-prerequisite-packages" class="anchor" aria-label="Permalink: Missing -devel prerequisite packages" href="#missing--devel-prerequisite-packages"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The most common cause of reported failures building <code>pljava-so</code> is a
missing required file. Sometimes your distribution's packaging system will
have chosen to organize a prerequisite piece of software into more than
one package, for example, one that contains only library files, and another
with a name ending in <code>-dev</code> or <code>-devel</code> that contains the necessary <code>.h</code>
files. Some distributions take this further than others; see the "special
topics" section for Ubuntu for an example where even libraries built as
part of PostgreSQL itself are split up into multiple separate packages.</p>
<p>The solution is simple: look over the error messages from the <code>pljava-so</code>
section of the build output to find any that refer to a file that could not
be found. Usually it will be a <code>.h</code> file or a library (<code>.so</code>, <code>.dll</code>, <code>.dylib</code>,
etc.).</p>
<p>Find out the name of the package, according to the OS or package distribution
you are using, that contains the missing file, install that package,
and you have probably solved the whole problem.</p>
<p><strong>Further tip:</strong> Finding the error message that really mattered is easier
if you follow the "troubleshooting the build" tip about the <code>-Pwnosign</code>
option, to cut down the number of other messages that do not matter, if
that option works on your platform.</p>
<div class="markdown-heading"><h2 class="heading-element">Still stuck?</h2><a id="user-content-still-stuck" class="anchor" aria-label="Permalink: Still stuck?" href="#still-stuck"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Please describe the issue you are facing on
<a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">the mailing list</a>.</p>
https://github.com/tada/pljava/wiki/Prebuilt-packages/1313d82a7f246f3f4ddbca73ee20f286808672a82023-09-19T15:40:06-04:002023-09-19T15:40:06-04:00Prebuilt packagesjcflack
<div class="markdown-heading"><h1 class="heading-element">Prebuilt PL/Java distributions</h1><a id="user-content-prebuilt-pljava-distributions" class="anchor" aria-label="Permalink: Prebuilt PL/Java distributions" href="#prebuilt-pljava-distributions"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>At present, the PL/Java project is reliant on downstream packagers to
produce prebuilt, installable PL/Java packages for various platforms. The
<a href="https://github.com/tada/pljava/releases">official PL/Java releases</a> are offered in source form and take
only a few minutes to build with Apache Maven as described in the
<a href="https://tada.github.io/pljava/build/build.html" rel="nofollow">build instructions</a>.</p>
<p>This wiki page will be updated to list known prebuilt PL/Java packages
and the platforms they are built for. As with any prebuilt distribution,
you should be acquainted with the policies and reputation of any supplier
of a prebuilt package. The PL/Java project has not directly built or verified
any package listed here.</p>
<div class="markdown-heading"><h2 class="heading-element">Known prebuilt packages available</h2><a id="user-content-known-prebuilt-packages-available" class="anchor" aria-label="Permalink: Known prebuilt packages available" href="#known-prebuilt-packages-available"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">Debian/Ubuntu packages <a href="http://apt.postgresql.org/pub/repos/apt/pool/main/p/postgresql-pljava/" rel="nofollow">on apt.postgresql.org</a>
</h3><a id="user-content-debianubuntu-packages-on-aptpostgresqlorg" class="anchor" aria-label="Permalink: Debian/Ubuntu packages on apt.postgresql.org" href="#debianubuntu-packages-on-aptpostgresqlorg"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>As of 2020, the Debian/Ubuntu packages have been consistently available at
the current PL/Java versions (now 1.5.6) and for a range of Debian, Ubuntu,
and PostgreSQL versions and architectures.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{1.5.2,"11.1 (Debian 11.1-1.pgdg+1)",11.0.1,Linux,amd64}"><pre class="notranslate"><code>{1.5.2,"11.1 (Debian 11.1-1.pgdg+1)",11.0.1,Linux,amd64}
</code></pre></div>
<p>PL/Java 1.5.2 packages available for PostgreSQL 11 back to 9.3 for Debian unstable/buster/stretch and Ubuntu cosmic/bionic/xenial, for amd64/i386/ppc64el. Dbgsym packages available. Includes <code>pljava-examples</code> jar with the <a href="http://tada.github.io/pljava/examples/saxon.html" rel="nofollow">optional Saxon examples</a> already built (download Saxon-HE 9.8.0.14 jar separately to use them).</p>
<p><em>Added 14 November 2018</em> <em>Updated 5 October 2020</em></p>
<div class="markdown-heading"><h3 class="heading-element">Docker images</h3><a id="user-content-docker-images" class="anchor" aria-label="Permalink: Docker images" href="#docker-images"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><strong>Bear Giles</strong> reports offering the following images on <code>hub.docker.com</code>:</p>
<ul>
<li>
<a href="https://hub.docker.com/beargiles/postgres-pgxnclient" rel="nofollow">beargiles/postgres-pgxnclient</a>: PostgreSQL image with only pgxn-client installed. This can be used as the base for other extensions.</li>
<li>
<a href="https://hub.docker.com/beargiles/postgres-pljava" rel="nofollow">beargiles/postgres-pljava</a>: Same as above but with PL/Java installed. It includes the default Java 11 JRE.</li>
<li>
<a href="https://hub.docker.com/beargiles/postgres-pljava-dev" rel="nofollow">beargiles/postgres-pljava-dev</a>: Same as above but with everything required to built the extension. Note: this uses Java 17 JDK, not the Java 11 JDK.</li>
</ul>
<p><em>From information 9 August 2023</em></p>
<p><strong>Adrian Escutia Soto</strong> has prepared an <a href="https://adrianescutia.github.io/adrianes/docs/postgres/enable-pljava-in-a-postgres-database" rel="nofollow">image</a> of 64-bit PostgreSQL 11 on Debian with Java 11 and PL/Java 1.6.2 for use with <a href="https://www.docker.com/" rel="nofollow">Docker</a>.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{1.6.2,"11.11 (Debian 11.11-1.pgdg90+1)",11.0.6,Linux,amd64}"><pre class="notranslate"><code>{1.6.2,"11.11 (Debian 11.11-1.pgdg90+1)",11.0.6,Linux,amd64}
</code></pre></div>
<p><em>added 21 February 2021</em></p>
<p><strong>Martin Bednar</strong> has prepared <a href="https://hub.docker.com/r/xxbedy/postgres-pljava/tags/" rel="nofollow">images</a> of 64-bit PostgreSQL (9.5
and 9.4) with PL/Java 1.5.0 and Oracle Java 8 for use with <a href="https://www.docker.com/" rel="nofollow">Docker</a>.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="{1.5.0,9.5.1,1.8.0_74,Linux,amd64}
{1.5.0,9.4.6,1.8.0_74,Linux,amd64}"><pre class="notranslate"><code>{1.5.0,9.5.1,1.8.0_74,Linux,amd64}
{1.5.0,9.4.6,1.8.0_74,Linux,amd64}
</code></pre></div>
<p><em>added 12 April 2016</em></p>
<div class="markdown-heading"><h3 class="heading-element">Complete PostgreSQL distributions from BigSQL</h3><a id="user-content-complete-postgresql-distributions-from-bigsql" class="anchor" aria-label="Permalink: Complete PostgreSQL distributions from BigSQL" href="#complete-postgresql-distributions-from-bigsql"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><a href="http://www.bigsql.org/se/" rel="nofollow">BigSQL</a> provides native installers for Centos 6 and 7,
Ubuntu 12.04 and 14.04, OS X 10.9+, Windows 7+, and Windows Server 2008
and 2012. These distributions of PostgreSQL 9.5, 9.4, 9.3,
and 9.2 <a href="http://www.bigsql.org/se/docs/proclang/proclang.jsp#pljava" rel="nofollow">include PL/Java 1.5.0</a>.</p>
<p><em>added 12 April 2016</em></p>
<div class="markdown-heading"><h2 class="heading-element">To list a prebuilt package here</h2><a id="user-content-to-list-a-prebuilt-package-here" class="anchor" aria-label="Permalink: To list a prebuilt package here" href="#to-list-a-prebuilt-package-here"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Please announce the availability of your package on
<a href="https://www.postgresql.org/list/pljava-dev/" rel="nofollow">the pljava-dev mailing list</a>, along with the output of
the third query below:</p>
<p><strong>Note: as of mid-May 2016, the <code>pljava-dev</code> mailing list is working again,
and should be used to announce packages. In case the mailing list does not
seem to work, then please <a href="https://github.com/tada/pljava/issues">open an issue</a>.</strong></p>
<p><code>SELECT sqlj.install_jar(</code> <em>fileurl-to-built-pljava-examples-*.jar</em> <code>, 'ex', true);</code><br>
<code>SELECT sqlj.set_classpath('javatest', 'ex');</code></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT array_agg(java_getsystemproperty(p)) FROM (values
('org.postgresql.pljava.version'),
('org.postgresql.version'),
('java.version'),
('os.name'),
('os.arch')
) AS props(p);"><pre class="notranslate"><code>SELECT array_agg(java_getsystemproperty(p)) FROM (values
('org.postgresql.pljava.version'),
('org.postgresql.version'),
('java.version'),
('os.name'),
('os.arch')
) AS props(p);
</code></pre></div>
https://github.com/tada/pljava/wiki/Security/7449c3076d747ba39dde9ae5c84f1c8f55380d4c2021-09-25T17:38:28-04:002021-09-25T17:38:28-04:00Securityjcflack
<div class="markdown-heading"><h2 class="heading-element">Installation</h2><a id="user-content-installation" class="anchor" aria-label="Permalink: Installation" href="#installation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Only a PostgreSQL super user can install PL/Java. The PL/Java utility functions
are installed as "security definer" so that they execute with the access
permissions that were granted to the creator of the functions.</p>
<div class="markdown-heading"><h2 class="heading-element">Trusted vs. untrusted language</h2><a id="user-content-trusted-vs-untrusted-language" class="anchor" aria-label="Permalink: Trusted vs. untrusted language" href="#trusted-vs-untrusted-language"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java can declare two language entries in SQL: <code>java</code> and <code>javau</code>.
Following the conventions of other PostgreSQL PLs, the 'untrusted' language
(<code>javau</code>) places no restrictions on what the Java code can do, while the
'trusted' language (<code>java</code>) installs a security manager that restricts access
to the filesystem. In PL/Java 1.5.x, a legacy version, those policies are
fixed.</p>
<p>In PL/Java 1.6.x, the policies for both <code>java</code> and <code>javau</code> are configurable,
and additional language "aliases" can be created and given policies of their
own, as described <a href="https://tada.github.io/pljava/use/policy.html" rel="nofollow">in the docs</a>.</p>
<p><code>GRANT/REVOKE USAGE ON LANGUAGE java</code> can be used to regulate which users
are able to create functions in the <code>java</code> language. For the <code>javau</code> language,
regardless of permissions, only superusers can create functions.</p>
<p><strong>Important: for implications of running on Java 17 and later,
please see <a class="internal present" href="/tada/pljava/wiki/JEP-411">JEP 411</a>.</strong></p>
<div class="markdown-heading"><h2 class="heading-element">Execution of the deployment descriptor</h2><a id="user-content-execution-of-the-deployment-descriptor" class="anchor" aria-label="Permalink: Execution of the deployment descriptor" href="#execution-of-the-deployment-descriptor"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <a href="SQL-functions#install_jar">install_jar</a>,
<a href="SQL-functions#replace_jar">replace-jar</a>, and
<a href="SQL-functions#remove_jar">remove_jar</a>
utility functions optionally execute commands found in a
<a class="internal present" href="/tada/pljava/wiki/Sql-deployment-descriptor">SQL deployment descriptor</a>. Such commands are executed with the
permissions of the caller. In
other words, although the utility function is declared with "security definer",
it switches back to the identity of the invoker during execution of the
deployment descriptor commands.</p>
<div class="markdown-heading"><h2 class="heading-element">Classpath manipulation</h2><a id="user-content-classpath-manipulation" class="anchor" aria-label="Permalink: Classpath manipulation" href="#classpath-manipulation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The utility function <a href="SQL-functions#set_classpath">set_classpath</a> requires
that the caller of the function has been granted <em>CREATE</em> permission on the
affected schema, unless it is the <code>public</code> schema, in which case the caller
must be a superuser.</p>
https://github.com/tada/pljava/wiki/Build-process-custom-Maven-plugin/1b9e023a740a6a79ded03c4dbbd231990242a0432020-07-01T00:43:13-04:002020-07-01T00:43:13-04:00Build process custom Maven pluginjcflack
<div class="markdown-heading"><h1 class="heading-element">Custom Maven plugin for the build process (GSoC 2020)</h1><a id="user-content-custom-maven-plugin-for-the-build-process-gsoc-2020" class="anchor" aria-label="Permalink: Custom Maven plugin for the build process (GSoC 2020)" href="#custom-maven-plugin-for-the-build-process-gsoc-2020"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><em>As long as this page looks, it is still intended for discussion; there is
a lot of room still left for design decisions, better ideas, and so on.</em></p>
<p>Since PL/Java was <a href="https://github.com/tada/pljava/commit/efbbc1d">Mavenized in 2013</a>, the <code>pljava-so</code> subproject
has been built using the <code>nar-maven-plugin</code>, assisted by the
<code>maven-antrun-plugin</code> running some actions in an Ant <code>build.xml</code> that
were not available as a Maven plugin.</p>
<p>Since Kenneth Olson <a href="https://github.com/tada/pljava/commit/dbf2bdc">added MSVC support in 2014</a>, there has also been
some JavaScript in that process. With Ant already used in the build, an Ant
<code>script</code> target offers a useful way for small bits of straight code to express
clearly what was unwieldy or impossible to express in strict Maven declarative
style using only existing plugins.</p>
<p>Experience with this combination has shown that the <code>nar-maven-plugin</code> is not
a perfect fit for the needs of this build. Some of the reasons were covered in
the <a href="https://wiki.postgresql.org/wiki/GSoC_2020#Subproject_details_3:_the_C_shared-object_build" rel="nofollow">GSoC 2020 project idea</a>.</p>
<p>It appears that there are enough details specific to PostgreSQL and PL/Java to
warrant developing a custom Maven plugin to perform this build. It's been
confirmed that Maven can build a plugin subproject and use it in another
subproject in a single build, so this should not complicate the PL/Java build
process by adding another step.</p>
<div class="markdown-heading"><h2 class="heading-element">Relationship to PGXS</h2><a id="user-content-relationship-to-pgxs" class="anchor" aria-label="Permalink: Relationship to PGXS" href="#relationship-to-pgxs"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>PGXS</code> is the native extension building system supplied in PostgreSQL for
building extensions in C or C++, implemented as a system of makefiles for
GNU <code>make</code>. It encapsulates knowledge of the compiler and linker invocations
needed on different supported platforms, and standard actions such as running
<code>pg_config</code> to obtain needed options and flags for the specific PostgreSQL
installation being built against.</p>
<p>The current build system has been essentially an effort to cobble
<code>nar-maven-plugin</code>, Ant, and JavaScript into something that does what <code>PGXS</code>
does, but in cross-platform Java and from Maven. The issues filed against the
current system tend to reflect where it departs from what <code>PGXS</code> would do.</p>
<p>The proposed new plugin has <code>pgxs</code> in the name to suggest the intended
behavior similarity, but not necessarily to require it be implemented a
particular way, such as directly over the real <code>PGXS</code>. (While the <code>PGXS</code>
makefiles are supplied with PostgreSQL, typically in a development package,
and PL/Java already requires C compilers and linkers and a JDK to build,
if there are platforms where GNU <code>make</code> would be a separate install,
relying directly on <code>PGXS</code> would lengthen the list of prerequisites for
building PL/Java from source.)</p>
<div class="markdown-heading"><h2 class="heading-element">Role of scripting</h2><a id="user-content-role-of-scripting" class="anchor" aria-label="Permalink: Role of scripting" href="#role-of-scripting"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>It is not a goal to eliminate JavaScript from the build process. It has
proven too useful to have a clear and compact scripting language available
to express some parts of the build process directly. Makefiles, too, as used
in <code>PGXS</code>, get their flexibility from allowing bits of script wherever needed,
with the <code>make</code> machinery supplying the dependency resolution and ordering.</p>
<p>It is not a goal to produce something as complete and flexible and automated
as <code>make</code>. Really, PL/Java needs to compile some C files and link them. The
work is in selecting the right command sequences to do that on several different
platforms, relying on correct values from <code>pg_config</code>.</p>
<div class="markdown-heading"><h3 class="heading-element">We currently have this "inside-out"</h3><a id="user-content-we-currently-have-this-inside-out" class="anchor" aria-label="Permalink: We currently have this "inside-out"" href="#we-currently-have-this-inside-out"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The current build system could be said to have the role of scripting turned
inside out. It uses JavaScript where necessary to do something the
available Maven plugins would not do, instead of where it would be
the clearest expression of a task.</p>
<p>For example, details of what options might be passed to a platform's compiler
or linker can be buried inside <code>nar-maven-plugin</code> and not available for easy
inspection by reading PL/Java's POM. At the same time, a reader of the POM sees
72 lines of JavaScript to quote a string for C, an algorithm that hasn't
changed in twenty years and is not an interesting part of PL/Java's build.</p>
<p>The new plugin's philosophy should be to turn that around, implement the
boring details and building blocks inside the plugin, and make some available
as public methods that bits of script might call.</p>
<p>Ideally, it will have a configuration syntax that allows some JavaScript
inlined into the XML, the same as is now being done with the
<code>maven-antrun-plugin</code>. Done right, we could drop the reliance on both
<code>nar-maven-plugin</code> and <code>maven-antrun-plugin</code> and move all of the build
logic into <code>pom.xml</code> rather than having some of it split off in <code>build.xml</code>.</p>
<div class="markdown-heading"><h2 class="heading-element">Basic operations</h2><a id="user-content-basic-operations" class="anchor" aria-label="Permalink: Basic operations" href="#basic-operations"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">Get PostgreSQL build-specific information by querying pg_config</h3><a id="user-content-get-postgresql-build-specific-information-by-querying-pg_config" class="anchor" aria-label="Permalink: Get PostgreSQL build-specific information by querying pg_config" href="#get-postgresql-build-specific-information-by-querying-pg_config"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Both our current build process and <code>PGXS</code> do this. For <code>PGXS</code> it happens
<a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/Makefile.global.in;h=20d7a1d;hb=4fc935a#l119" rel="nofollow">in <code>Makefile.global</code></a> when it is included by <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/makefiles/pgxs.mk;h=271e7ea;hb=HEAD" rel="nofollow"><code>PGXS.mk</code></a>.</p>
<p>For the current PL/Java build it happens <a href="https://github.com/tada/pljava/blob/837b03b/pljava-so/build.xml#L39">in build.xml</a>; <code>ant</code>
ends up <a href="https://github.com/tada/pljava/blob/837b03b/pljava-so/build.xml#L98">writing values</a> into a <code>pgsql.properties</code> file just so
a Maven plugin can <a href="https://github.com/tada/pljava/blob/622e004/pljava-so/pom.xml#L396">read the file</a> and set the properties in Maven.
We should be able to simplify that and just set Maven's properties.
(But beware! They can't just be set as <code>pljava-so</code>'s properties;
<code>pljava-packaging</code> uses them too, currently by <a href="https://github.com/tada/pljava/blob/a0ffcd2/packaging/build.xml#L21">reading that file</a> again.)</p>
<div class="markdown-heading"><h3 class="heading-element">Merge build-specific information into platform-specific recipes</h3><a id="user-content-merge-build-specific-information-into-platform-specific-recipes" class="anchor" aria-label="Permalink: Merge build-specific information into platform-specific recipes" href="#merge-build-specific-information-into-platform-specific-recipes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Both <code>PGXS</code> and <code>nar-maven-plugin</code> contain embedded information on the
needed compiling and linking commands for different supported platforms.
The build-specific information from <code>pg_config</code> gets merged into those
generic recipes.</p>
<p>For <code>PGXS</code>, the embedded rules for linking a shared object on the different
platforms are found <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/Makefile.shlib;h=003aefb;hb=c217b36#l78" rel="nofollow">in <code>Makefile.shlib</code></a>.</p>
<p>For the <code>nar-maven-plugin</code>, they are found in a file inside the plugin's jar
file in the Maven repository, so the easiest way to inspect them is
<a href="https://github.com/maven-nar/nar-maven-plugin/blob/7ba6ca9/src/main/resources/com/github/maven_nar/aol.properties#L1">on github</a>. It is inconvenient to add support to PL/Java for
additional platforms, because the <code>nar-maven-plugin</code> does not offer a way to
supply some additional platform definitions that <em>add to</em> its built-in set.
There is only the option of using a system property to specify another file
to be used <em>instead of</em> the built-in one, so a new platform can only be
supported by dropping a new file into the source directory and editing the
docs to tell a person building for that platform to use an extra command-line
option. (<a href="https://github.com/tada/pljava/commit/b69aaf5">This commit</a> is an example.)</p>
<div class="markdown-heading"><h4 class="heading-element">How should the plugin embed the platform recipes?</h4><a id="user-content-how-should-the-plugin-embed-the-platform-recipes" class="anchor" aria-label="Permalink: How should the plugin embed the platform recipes?" href="#how-should-the-plugin-embed-the-platform-recipes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The super-ambitious idea would be a Java parser for GNU makefiles that would
gather the information directly <a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/Makefile.shlib;h=003aefb;hb=c217b36#l78" rel="nofollow">from PostgreSQL's files</a>. But that
would be a major undertaking and we could easily get away with less.</p>
<p>If the plugin had a configuration section in the POM that would accept some
simple JavaScript (maybe looking like JSON, or like a map from platform names
to functions, etc.), that would be an easily readable form for the recipes
They would be right there in the POM for inspection, not buried somewhere
inside a jar file, and would be easy to edit to add new platforms in the
future. The initial set could just be human-populated by looking at
<a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/Makefile.shlib;h=003aefb;hb=c217b36#l78" rel="nofollow"><code>Makefile.shlib</code></a>, which wouldn't be much work, and changes are
infrequent.</p>
<p>(Just for the record, the Java makefile parser idea would not be <em>completely</em>
bonkers; somebody <a href="https://sourceforge.net/projects/makefileparser/" rel="nofollow">has started one</a> but no commits in several years.
It has a TODO saying no support for many things I'm sure are in PostgreSQL
makefiles, but it also has commits more recent than the TODO that mention
some of those things, so maybe the TODO is out of date. I have not tried to
run it. It is not BSD licensed, so would not belong in a PL/Java distribution,
but if somebody forked it, got it complete enough to read PostgreSQL's
makefiles, and deployed it to Maven Central, it would be usable as a
build-time dependency. It might also get used more widely.)</p>
<div class="markdown-heading"><h3 class="heading-element">Exported symbol filtering</h3><a id="user-content-exported-symbol-filtering" class="anchor" aria-label="Permalink: Exported symbol filtering" href="#exported-symbol-filtering"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The PGXS makefiles appear to support
<a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/Makefile.shlib;h=3cb5e55;hb=a1d5d85#l27" rel="nofollow">filtering of which global symbols to export</a> for most or all
supported platforms, something PL/Java does not currently do. That is worth
supporting if we can: PL/Java only has a couple of entry points that need to be
exported for PostgreSQL to call, and keeping the rest of its global symbols
non-exported would reduce the pressure to give others long unwieldy names
hoping they won't collide with other extensions.</p>
<div class="markdown-heading"><h2 class="heading-element">Argument passing workaround for Windows</h2><a id="user-content-argument-passing-workaround-for-windows" class="anchor" aria-label="Permalink: Argument passing workaround for Windows" href="#argument-passing-workaround-for-windows"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>When invoking other programs on Windows, various characters in command-line
arguments can cause the receiving program to parse the command line incorrectly
(background in <a href="https://github.com/tada/pljava/issues/190">issue 190</a>). The root cause is inherent in the Java
<code>Process</code> API itself, whose design doesn't take the weirdness of Windows
command-line parsing into effect.</p>
<p>What makes Windows command-line parsing weird is that Windows doesn't do it:
it is up to <em>each program</em> to parse the command line it receives, and different
ones can use <em>different rules</em>.</p>
<p>In practice, most programs use the C library they are linked to, so the number
of different rule sets out there is more like the number of C
libraries/versions in use, but that number is greater than 1 and with rules
that differ. (I am relying on <a href="http://daviddeley.com/autohotkey/parameters/parameters.htm#WINPASS" rel="nofollow">this source</a> for these details.)</p>
<p>That means on Windows, when invoking a program with arguments, in some way
<em>which lexical rules to apply</em> must also be somehow specified, so that any
interesting argument values can have the correct escaping done to ensure they
are recovered correctly when the invoked program parses them.</p>
<p>Windows might have something comparable to <code>ldd</code> that could look at a target
executable and report what runtime library it links to, so the right rules
could be selected. But autodetection might be more ambitious than we need
(and could still have exceptions anyway, programs that link to an unknown
library, or do their own custom argument parsing). So a way to specify the
right set of rules to use will be necessary anyway, and probably sufficient.</p>
<p>There's no need to implement every different set of lexical rules any Windows
program has ever used, as long as we figure out what rules are used by each
of the compiling/linking tools our build recipes will use, and make sure to
implement those.</p>
<div class="markdown-heading"><h3 class="heading-element">What might a workaround API look like?</h3><a id="user-content-what-might-a-workaround-api-look-like" class="anchor" aria-label="Permalink: What might a workaround API look like?" href="#what-might-a-workaround-api-look-like"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>An obvious idea would look like subclasses of <code>ProcessBuilder</code> that apply
different escaping rules. Code would pass individual arguments to the builder
in the usual way, but they would have the right rules applied when the process
is started.</p>
<p>However, <code>ProcessBuilder</code> is <code>final</code>, so the API can't look exactly like that.</p>
<p>It could look like some other class that has a <code>start</code> method taking a
<code>ProcessBuilder</code> argument and returning a <code>Process</code>, much like the <code>start</code>
method of <code>ProcessBuilder</code> itself. The argument list of a <code>ProcessBuilder</code>
can be retrieved and modified. A POSIX-flavored subclass would have a <code>start</code>
method that does nothing special, and directly calls <code>start</code> on the
<code>ProcessBuilder</code>; a Windows-flavored one could modify the arguments first.</p>
<div class="markdown-heading"><h4 class="heading-element">But it's not quite that simple</h4><a id="user-content-but-its-not-quite-that-simple" class="anchor" aria-label="Permalink: But it's not quite that simple" href="#but-its-not-quite-that-simple"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>It won't be enough to simply transform the argument list, before calling
<code>ProcessBuilder.start</code>, so that the values have the right escaping for the
target program. That's because this argument list still has to go through
Java's <code>start</code> implementation, which will try to add Windows escaping
itself (using its built-in rules that were the problem in the first place).</p>
<p>It can be absorbing to try to think of ways to transform the arguments so
that the end result of (our transformation) followed by (Java's transformation)
produces the right values for the target program. But depending on the rules
in play, there is no guarantee it is even possible.</p>
<p>When I faced a similar problem another time, I ended up transforming the command
and arguments into an invocation of <code>python</code>, with the original arguments
passed through <code>base64</code> (no spaces, no punctuation, nothing to go wrong) and
a snippet of Python code that would un-base64 the arguments and invoke the
intended target.</p>
<p>On Windows, a similar idea using PowerShell might be most natural.</p>
<p>I don't know enough about PowerShell to say whether there's an advantage either
way between just passing encoded args as I was doing with Python (assuming
PowerShell has functions to decode base64), or to construct
<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp/c69507e9-370e-49f0-86df-16d8aadfa79b" rel="nofollow">a serialized object</a> to pass to PowerShell as by the
<a href="https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-psrp/b2baf403-78aa-4f41-b140-cc4f5090cd68" rel="nofollow">PowerShell Remoting Protocol</a>.</p>
<div class="markdown-heading"><h2 class="heading-element">One last thing: a simple report Mojo</h2><a id="user-content-one-last-thing-a-simple-report-mojo" class="anchor" aria-label="Permalink: One last thing: a simple report Mojo" href="#one-last-thing-a-simple-report-mojo"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>This is not directly related to building the native code, but with adding
a custom plugin anyway, it would be helpful to have one simple Mojo
that <a href="https://maven.apache.org/guides/plugin/guide-java-report-plugin-development.html" rel="nofollow">implements <code>MavenReport</code></a> and allows a bit of JavaScript to be
given and run in the <code>site</code> life cycle.</p>
<p>The reason is that I am very unhappy with the <code>maven-javadoc-plugin</code>, as
<a href="https://github.com/tada/pljava/commit/5ee9b6b">this commit</a> and <a href="https://github.com/tada/pljava/commit/395ac0d">this one</a> will show.</p>
<p>By the end of those two commits, it seems PL/Java now gets its Javadoc built
by threading one tricky path, maybe even the only path, between the existing
bugs in the plugin and <code>javadoc</code>. The arrival any day of one more bug in the
wrong place might leave zero paths.</p>
<p>That is way too much work and too much risk, considering that the docs could
be built simply by launching <code>javadoc</code> with nearly all default options. The
extra work here has only been to get <code>maven-javadoc-plugin</code> not to add extra
options that cause failure.</p>
<p>In the build life cycle, using <code>maven-antrun-plugin</code> again with four lines
of JavaScript to launch <code>javadoc</code> with the right options would solve the
problem once and for all.</p>
<p>But the <code>maven-antrun-plugin</code>'s Mojos do not implement <code>MavenReport</code>, so that
isn't an available option in the <code>site</code> life cycle.</p>
https://github.com/tada/pljava/wiki/Sql-deployment-descriptor/eb59e0eceaf848811be322e03be6e9a990445a962020-05-12T22:16:54-04:002020-05-12T22:16:54-04:00Sql deployment descriptorjcflack
<div class="markdown-heading"><h1 class="heading-element">SQLJ deployment descriptors</h1><a id="user-content-sqlj-deployment-descriptors" class="anchor" aria-label="Permalink: SQLJ deployment descriptors" href="#sqlj-deployment-descriptors"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <a href="SQL-functions#install_jar">install_jar</a>,
<a href="SQL-functions#replace_jar">replace_jar</a>, and
<a href="SQL-functions#remove_jar">remove_jar</a> functions
can act on a <em>deployment descriptor</em> allowing SQL commands to be executed
after the jar has been installed or prior to removal.</p>
<p>The descriptor is added as a normal text file to your jar file. In the Manifest
of the jar there must be an entry that appoints the file as the SQLJ deployment
descriptor.</p>
<div class="highlight highlight-source-yaml notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Name: deployment/examples.ddr
SQLJDeploymentDescriptor: TRUE"><pre><span class="pl-ent">Name</span>: <span class="pl-s">deployment/examples.ddr</span>
<span class="pl-ent">SQLJDeploymentDescriptor</span>: <span class="pl-c1">TRUE</span></pre></div>
<p>Such a file can be written by hand according to the format below, but the usual method is to add specific Java annotations in the source code, as described under <a href="Function-mapping#sql-generation">function mapping - SQL generation</a>. The Java compiler then generates the deployment descriptor file at the same time it compiles the Java sources, and the compiled classes and <code>.ddr</code> file can all be placed in the jar together.</p>
<p>The format of the deployment descriptor is stipulated by ISO/IEC 9075-13:2003.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="<descriptor file> ::=
SQLActions <left bracket> <rightbracket> <equal sign>
{ [ <double quote> <action group> <double quote>
[ <comma> <double quote> <action group> <double quote> ] ] }
<action group> ::=
<install actions>
| <remove actions>
<install actions> ::=
BEGIN INSTALL [ <command> <semicolon> ]... END INSTALL
<remove actions> ::=
BEGIN REMOVE [ <command> <semicolon> ]... END REMOVE
<command> ::=
<SQL statement>
| <implementor block>
<SQL statement> ::= <SQL token>...
<implementor block> ::=
BEGIN <implementor name> <SQL token>... END <implementor name>
<implementor name> ::= <identifier>
<SQL token> ::= ! an SQL lexical unit specified by the term "<token>"
in Sub clause 5.2, "<token> and <separator>", in ISO/IEC 9075-2."><pre lang="bnf" class="notranslate"><code><descriptor file> ::=
SQLActions <left bracket> <rightbracket> <equal sign>
{ [ <double quote> <action group> <double quote>
[ <comma> <double quote> <action group> <double quote> ] ] }
<action group> ::=
<install actions>
| <remove actions>
<install actions> ::=
BEGIN INSTALL [ <command> <semicolon> ]... END INSTALL
<remove actions> ::=
BEGIN REMOVE [ <command> <semicolon> ]... END REMOVE
<command> ::=
<SQL statement>
| <implementor block>
<SQL statement> ::= <SQL token>...
<implementor block> ::=
BEGIN <implementor name> <SQL token>... END <implementor name>
<implementor name> ::= <identifier>
<SQL token> ::= ! an SQL lexical unit specified by the term "<token>"
in Sub clause 5.2, "<token> and <separator>", in ISO/IEC 9075-2.
</code></pre></div>
<p>If implementor blocks are used, PL/Java will consider only those with
implementor name PostgreSQL (case insensitive) by default. Here is a sample
deployment descriptor:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SQLActions[] = {
"BEGIN INSTALL
CREATE FUNCTION javatest.java_getTimestamp()
RETURNS timestamp
AS 'org.postgresql.pljava.example.Parameters.getTimestamp'
LANGUAGE java;
END INSTALL",
"BEGIN REMOVE
DROP FUNCTION javatest.java_getTimestamp();
END REMOVE"
}"><pre><span class="pl-smi">SQLActions</span>[]<span class="pl-s1"></span> = {
<span class="pl-s">"BEGIN INSTALL</span>
<span class="pl-s"> CREATE FUNCTION javatest.java_getTimestamp()</span>
<span class="pl-s"> RETURNS timestamp</span>
<span class="pl-s"> AS 'org.postgresql.pljava.example.Parameters.getTimestamp'</span>
<span class="pl-s"> LANGUAGE java;</span>
<span class="pl-s"> END INSTALL"</span>,
<span class="pl-s">"BEGIN REMOVE</span>
<span class="pl-s"> DROP FUNCTION javatest.java_getTimestamp();</span>
<span class="pl-s"> END REMOVE"</span>
}</pre></div>
<div class="markdown-heading"><h2 class="heading-element">Configurable implementor-block recognition</h2><a id="user-content-configurable-implementor-block-recognition" class="anchor" aria-label="Permalink: Configurable implementor-block recognition" href="#configurable-implementor-block-recognition"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Although, by default, only the implementor name PostgreSQL is recognized,
the implementor name(s) to be recognized can be set as a list in the
variable <code>pljava.implementors</code>. It is consulted after every command while
executing a deployment descriptor, which gives code in the descriptor
a rudimentary form of conditional execution control, by changing which
implementor blocks will be executed based on discovered conditions.</p>
https://github.com/tada/pljava/wiki/Thoughts-on-logging/651934a0ff31911c4af914518df88a4038046f302019-01-27T20:50:14-05:002019-01-27T20:50:14-05:00Thoughts on loggingjcflack
<div class="markdown-heading"><h1 class="heading-element">Thoughts on logging</h1><a id="user-content-thoughts-on-logging" class="anchor" aria-label="Permalink: Thoughts on logging" href="#thoughts-on-logging"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<hr>
<p><strong>Update:</strong> This turns out to be more timely than I realized—PL/Pythonu is also <a href="http://postgresql.nabble.com/proposal-PL-Pythonu-function-ereport-td5869255.html" rel="nofollow">developing a patch</a> (starting last month) to the same end.</p>
<p>On their client side, psycopg2 already exposes a <a href="http://initd.org/psycopg/docs/extensions.html#psycopg2.extensions.Diagnostics" rel="nofollow">documented, supported PostgreSQL-specific Diagnostics object</a>.</p>
<hr>
<p><em>Note: this page does not describe how PL/Java currently works, except in
the "Background" part. It is a proposal for further development.</em></p>
<p><em>Also, to anyone reading this for review or comment, a lot of this material
may be more familiar than it is to me. If I seem to describe it in excessive
detail, please regard that as my effort to have it straight in my own head.</em></p>
<p><em>Also also, to some it may seem strange that I use phrases like "log event"
without insisting on any essential difference between</em> thrown exceptions
<em>and</em> calls on loggers. <em>It's true, I'm not marking any such essential
difference, and I hope, before this is done, that won't seem so strange.</em></p>
<p>So, here goes.</p>
<p><em>... logging isn't particularly magical.</em><br>
—Dave Cramer</p>
<p><em>... it's what you do with it.</em><br>
—variously attributed</p>
<div class="markdown-heading"><h2 class="heading-element">Background</h2><a id="user-content-background" class="anchor" aria-label="Permalink: Background" href="#background"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">PostgreSQL has supremely good log messages.</h3><a id="user-content-postgresql-has-supremely-good-log-messages" class="anchor" aria-label="Permalink: PostgreSQL has supremely good log messages." href="#postgresql-has-supremely-good-log-messages"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>It even has a <a href="http://www.postgresql.org/docs/current/static/error-style-guide.html" rel="nofollow">style guide</a> for writing them, and it pays off
in the well-known quality and helpfulness of PostgreSQL messages.</p>
<p>Part of the excellence of PostgreSQL's messages can be traced to their rich
structure. A message is not a blob of text with whatever details seemed
useful while writing the code. It is a structured record with information
serving several specific purposes and at several distinct levels of detail:</p>
<table role="table">
<thead>
<tr>
<th>item</th>
<th>pq</th>
<th>PL/pgSQL</th>
<th>pgjdbc (+ -ng Notice)</th>
<th>pgjdbc-ng Exc</th>
<th>PL/Java</th>
</tr>
</thead>
<tbody>
<tr>
<td>elevel</td>
<td>S</td>
<td></td>
<td>getSeverity</td>
<td></td>
<td>getErrorLevel</td>
</tr>
<tr>
<td>sqlstate</td>
<td>C</td>
<td>RETURNED_SQLSTATE</td>
<td>getSQLState getCode</td>
<td>getSQLState</td>
<td>getSqlState</td>
</tr>
<tr>
<td>message</td>
<td>M</td>
<td>MESSAGE_TEXT</td>
<td>getMessage</td>
<td>getMessage</td>
<td>getMessage</td>
</tr>
<tr>
<td>detail</td>
<td>D</td>
<td>PG_EXCEPTION_DETAIL</td>
<td>getDetail</td>
<td></td>
<td>getDetail</td>
</tr>
<tr>
<td>hint</td>
<td>H</td>
<td>PG_EXCEPTION_HINT</td>
<td>getHint</td>
<td></td>
<td>getHint</td>
</tr>
<tr>
<td>context</td>
<td>W</td>
<td>PG_EXCEPTION_CONTEXT</td>
<td>getWhere</td>
<td></td>
<td>getContextMessage</td>
</tr>
<tr>
<td>schema_name</td>
<td>s</td>
<td>SCHEMA_NAME</td>
<td>getSchema</td>
<td>getSchema</td>
<td></td>
</tr>
<tr>
<td>table_name</td>
<td>t</td>
<td>TABLE_NAME</td>
<td>getTable</td>
<td>getTable</td>
<td></td>
</tr>
<tr>
<td>column_name</td>
<td>c</td>
<td>COLUMN_NAME</td>
<td>getColumn</td>
<td>getColumn</td>
<td></td>
</tr>
<tr>
<td>datatype_name</td>
<td>d</td>
<td>PG_DATATYPE_NAME</td>
<td>getDatatype</td>
<td>getDatatype</td>
<td></td>
</tr>
<tr>
<td>constraint_name</td>
<td>n</td>
<td>CONSTRAINT_NAME</td>
<td>getConstraint</td>
<td>getConstraint</td>
<td></td>
</tr>
<tr>
<td>cursorpos</td>
<td>P</td>
<td></td>
<td>getPosition</td>
<td></td>
<td>getCursorPos</td>
</tr>
<tr>
<td>internalpos</td>
<td>p</td>
<td></td>
<td>getInternalPosition</td>
<td></td>
<td>getInternalPos</td>
</tr>
<tr>
<td>internalquery</td>
<td>q</td>
<td></td>
<td>getInternalQuery</td>
<td></td>
<td>getInternalQuery</td>
</tr>
<tr>
<td>filename</td>
<td>F</td>
<td></td>
<td>getFile</td>
<td></td>
<td>getFilename</td>
</tr>
<tr>
<td>lineno</td>
<td>L</td>
<td></td>
<td>getLine</td>
<td></td>
<td>getLineno</td>
</tr>
<tr>
<td>funcname</td>
<td>R</td>
<td></td>
<td>getRoutine</td>
<td></td>
<td>getFuncname</td>
</tr>
<tr>
<td>output_to_server</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>isOutputToServer</td>
</tr>
<tr>
<td>output_to_client</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>isOutputToClient</td>
</tr>
<tr>
<td>show_funcname</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>isShowFuncname</td>
</tr>
<tr>
<td>saved_errno</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>getSavedErrno</td>
</tr>
<tr>
<td>hide_stmt</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>hide_ctx</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>domain</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>context_domain</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<p>The <code>libpq</code> on-the-wire protocol preserves this structure, sending these
components (the ones with <code>pq</code> codes) distinctly and intact to the front end.
This gives client code enormous flexibility to catch and handle conditions
appropriately. If the condition has to be logged or reported to a user, it can
be shown at any appropriate level of detail, or even with a user interface that
permits drilling down from generalities to specifics.</p>
<p>How awesome is that? Consider this: I have seen, with my own eyes,
non-technical users entering stuff into a PostgreSQL database (using
something as generic as LibreOffice Base as the front end) have an
error dialog pop up, <em>read it</em>, understand what had to be corrected
in the entry, and recover on their own.</p>
<p>I challenge anyone who has had support experience to tell me <em>that</em> ain't magic.</p>
<p>By and large, messages in PostgreSQL really are <em>that</em> good.</p>
<div class="markdown-heading"><h3 class="heading-element">Original log event life cycle</h3><a id="user-content-original-log-event-life-cycle" class="anchor" aria-label="Permalink: Original log event life cycle" href="#original-log-event-life-cycle"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A message that originates in the PostgreSQL backend proper begins as a call
to <code>ereport</code> or <code>elog</code> in <a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/error/elog.c" rel="nofollow">elog.c</a>. The rules there are just a bit
<em>special</em>:</p>
<ol start="0">
<li>
<p>If the message has any severity <em>below</em> <code>ERROR</code> (so, <code>DEBUG5</code>, <code>DEBUG4</code>,
<code>DEBUG3</code>, <code>DEBUG2</code>, <code>DEBUG1</code>, <code>LOG</code>, <code>COMMERROR</code>, <code>INFO</code>, <code>NOTICE</code>, or
<code>WARNING</code>) <strong>or</strong> <em>above</em> <code>ERROR</code> (so, <code>FATAL</code>, <code>PANIC</code>), it gets written
immediately to logs / reported to the front end (according to
the <code>log_min_messages</code> and <code>client_min_messages</code> settings), and then
control returns to the call site if it was below <code>ERROR</code>, and does not
return if it was above.</p>
</li>
<li>
<p>If the severity is <em>exactly</em> <code>ERROR</code>, it gets <em>thrown</em> PostgreSQL-style, and
can be caught in <code>PG_TRY</code>/<code>PG_CATCH</code> constructs. The <a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/error/elog.c" rel="nofollow">elog</a> code
does <em>not</em> send it to the server log or the front end at all at that point,
but only when (if ever) it bubbles up to <code>PostgresMain</code> without having been
handled. If it gets caught and handled, then any logging becomes the
responsibility of whatever code caught it.</p>
</li>
</ol>
<div class="markdown-heading"><h3 class="heading-element">Handling logged events in front-end code</h3><a id="user-content-handling-logged-events-in-front-end-code" class="anchor" aria-label="Permalink: Handling logged events in front-end code" href="#handling-logged-events-in-front-end-code"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Events from the server that arrive at the front end show up in a form the
front-end code can inspect and choose how to handle, either by polling for
them (libpq <code>PQresultErrorField</code>, JDBC <code>getWarnings</code> if less severe than
<code>ERROR</code>), or catching an exception (JDBC if severity is <code>ERROR</code>).</p>
<p>This code in turn might want to log an event (whether one received from the
backend as just described, or one originating in the front-end code itself).
To do that, it will probably use some convenient library available to it,
such as <code>java.util.logging</code> in Java.</p>
<p>For code that is really running in a front end, that's the end of the story,
but for code running in a backend PL, the story has only begun.</p>
<div class="markdown-heading"><h3 class="heading-element">Handling logged events in a back-end PL</h3><a id="user-content-handling-logged-events-in-a-back-end-pl" class="anchor" aria-label="Permalink: Handling logged events in a back-end PL" href="#handling-logged-events-in-a-back-end-pl"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The first requirements for server-side code are the same as for the front end:
it should be able to intercept, examine, and handle or not handle as
appropriate, events that originate during its calls into the backend.
PL/pgSQL makes a good example, with the <a href="http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING" rel="nofollow">trapping of errors</a>
built into the language, and <a href="http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-EXCEPTION-DIAGNOSTICS" rel="nofollow">inspection of (most) elements</a> of
the structure. Naturally, whatever isn't caught in PL/pgSQL code should
continue propagating outward with all its structured information intact.</p>
<p>In PL/pgSQL, all of that applies to events with the exact severity <code>ERROR</code>:
warnings/notices/etc. are invisible to PL/pgSQL code, as the
<a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/error/elog.c" rel="nofollow">elog</a> logic sends those right out from under the PL and straight
to the front-end client (conditioned only on the <code>client_min_messages</code>
setting). That might not be always ideal: there can be a tension between ease
of development/troubleshooting, favoring lots of logging, and confidentiality
demands, which could require that some messages be edited or suppressed, which
the PL code can't do if they zip right past it.</p>
<div class="markdown-heading"><h4 class="heading-element">As for PL/Java</h4><a id="user-content-as-for-pljava" class="anchor" aria-label="Permalink: As for PL/Java" href="#as-for-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java is at parity with PL/pgSQL as far as the ability to catch error events
from the backend (as Java <code>SQLException</code>s), or to propagate them up the stack
without information loss if they are not caught, or are caught and rethrown
without change.</p>
<p>Internally, it has good provisions for examining individual properties of
the event (currently not including the schema, table, column, datatype, and
constraint names that <a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=blobdiff;f=src/include/utils/elog.h;h=d5fec89a4801481d0494c34cd38e72653d3da99a;hp=5e937fb10c3211b2c12d0ec2d7ee71fe506cb7f8;hb=991f3e5ab3f8196d18d5b313c81a5f744f3baaea;hpb=89d00cbe01447fd36edbc3bed659f869b18172d1" rel="nofollow">appeared in 9.3</a>). However, these provisions
aren't quite exposed yet to ordinary developers writing PL/Java code. Although
<a class="internal present" href="/tada/pljava/wiki/Exception-handling">documented</a> in the wiki, they aren't accessible to
PL/Java code compiled normally against <code>pljava-api.jar</code>; it would have to
be compiled against the full <code>pljava.jar</code> and refer explicitly to
<a href="http://tada.github.io/pljava/pljava/apidocs/index.html?org/postgresql/pljava/internal/ServerException.html" rel="nofollow"><code>ServerException</code></a> and <a href="http://tada.github.io/pljava/pljava/apidocs/index.html?org/postgresql/pljava/internal/ErrorData.html" rel="nofollow"><code>ErrorData</code></a> in the
<code>org.postgresql.pljava.internal</code> package.</p>
<p>(In passing, the current design where the magic only happens for a single
<code>ServerException</code> subclass of <code>SQLException</code> stands in the way of implementing
the <a href="http://www.javaspecialists.eu/archive/Issue138.html" rel="nofollow">categorized exceptions</a> for JDBC 4.0.)</p>
<p>This is one area where a good API should be worked out and published.
PL/Java provides a JDBC interface to the backend, because that is how
the SQL/JRT standard is written, which PL/Java is meant to implement.
As far as JDBC is concerned, access to these implementation-specific error
details would be an extension, such as might be accessed
by <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/sql/Wrapper.html#unwrap(java.lang.Class)" rel="nofollow"><code>unwrap</code></a> on a standard JDBC object. Being committed to a JDBC
interface
to PostgreSQL, it would be ideal to agree on the details with the other,
front-end JDBC interfaces to PostgreSQL, as front-ends also receive finely
structured PostgreSQL error details that client code may want to examine.</p>
<p>(Again in passing, the fact that PL/Java presents a JDBC interface could raise
hopes that PL/Java functions are also able to examine warnings using the
standard <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/sql/ResultSet.html#getWarnings()" rel="nofollow">JDBC mechanism</a>. At the moment, they aren't, and the
<code>PG_TRY</code>/<code>PG_CATCH</code> constructs aren't enough to fix that, because only severity
level <code>ERROR</code> is handled that way. PL/Java would have to also use the
<code>emit_log_hook</code> in order to present a behavior analogous to JDBC on the
front end. It would then pull ahead of PL/pgSQL on that dimension.)</p>
<div class="markdown-heading"><h4 class="heading-element">How do the other PostgreSQL JDBCs give access to error details?</h4><a id="user-content-how-do-the-other-postgresql-jdbcs-give-access-to-error-details" class="anchor" aria-label="Permalink: How do the other PostgreSQL JDBCs give access to error details?" href="#how-do-the-other-postgresql-jdbcs-give-access-to-error-details"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h5 class="heading-element">pgjdbc</h5><a id="user-content-pgjdbc" class="anchor" aria-label="Permalink: pgjdbc" href="#pgjdbc"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>If you have an <code>SQLException</code> <em>and</em> it can be cast to
<a href="https://jdbc.postgresql.org/development/privateapi/index.html?org/postgresql/util/PSQLException.html" rel="nofollow"><code>org.postgresql.util.PSQLException</code></a>, then you can call
<code>getServerErrorMessage()</code> on it, and get a <a href="https://jdbc.postgresql.org/documentation/publicapi/index.html?org/postgresql/util/ServerErrorMessage.html" rel="nofollow"><code>ServerErrorMessage</code></a>.
Same deal if you have an <code>SQLWarning</code> that is castable to
<a href="https://jdbc.postgresql.org/development/privateapi/index.html?org/postgresql/util/PSQLWarning.html" rel="nofollow"><code>org.postgresql.util.PSQLWarning</code></a>. (None of this is
exactly trumpeted in the <a href="https://jdbc.postgresql.org/documentation/head/index.html" rel="nofollow">docs</a>, and as you can see, the
<code>PSQLException</code> and <code>PSQLWarning</code> links above are to <code>privateapi</code> pages,
though the classes are <code>public</code> and accessible.)</p>
<p>Just as in PL/Java, the design here with a single <code>PSQLException</code> class is an
obstacle to moving forward with the categorized exceptions in JDBC 4.0.</p>
<div class="markdown-heading"><h5 class="heading-element">pgjdbc-ng</h5><a id="user-content-pgjdbc-ng" class="anchor" aria-label="Permalink: pgjdbc-ng" href="#pgjdbc-ng"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In <code>pgjdbc-ng</code>, categorized exceptions are partially implemented: at least
there is one <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/jdbc/PGSQLIntegrityConstraintViolationException.html" rel="nofollow"><code>PGSQLIntegrityConstraintViolationException</code></a>, and one
<a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/jdbc/PGSQLSimpleException.html" rel="nofollow"><code>PGSQLSimpleException</code></a> for everything else. To allow for multiple
categories, these share a common <em>interface</em>, <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/api/jdbc/PGSQLExceptionInfo.html#method_summary" rel="nofollow"><code>PGSQLExceptionInfo</code></a>.
Calling code does not need to test for a bunch of implementation-specific
class names, but can simply catch JDBC exceptions by their standard <code>java.sql</code>
names, and test for castability to a single interface.</p>
<p>Interestingly, the interface gives access <em>only</em> to the column, constraint,
datatype, schema, and table names available from PostgreSQL 9.3 onward (exactly
the five things PL/Java currently <em>doesn't</em> expose!) and none of the much more
anciently supported detail, hint, context, etc. And <code>pgjdbc-ng</code> doesn't supply
any <code>SQLWarning</code> subclass that implements it.</p>
<p><em>All</em> of the elements the protocol can forward are available on a different
object, <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/protocol/Notice.html#method_summary" rel="nofollow"><code>com.impossibl.postgres.protocol.Notice</code></a>, but I am not sure
user code has any way to get one. The classes that use it seem fairly internal.</p>
<p>Unlike both PL/Java's <a href="http://tada.github.io/pljava/pljava/apidocs/index.html?org/postgresql/pljava/internal/ErrorData.html" rel="nofollow"><code>ErrorData</code></a> and <code>pgjdbc</code>'s
<a href="https://jdbc.postgresql.org/documentation/publicapi/index.html?org/postgresql/util/ServerErrorMessage.html" rel="nofollow"><code>ServerErrorMessage</code></a>, in <code>pgjdbc-ng</code> both the
<a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/api/jdbc/PGSQLExceptionInfo.html#method_summary" rel="nofollow"><code>PGSQLExceptionInfo</code></a> and the <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/protocol/Notice.html#method_summary" rel="nofollow"><code>Notice</code></a> are mutable,
providing setter methods as well as getters ... leading naturally into
the next section.</p>
<div class="markdown-heading"><h3 class="heading-element">Originating loggable events</h3><a id="user-content-originating-loggable-events" class="anchor" aria-label="Permalink: Originating loggable events" href="#originating-loggable-events"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Whether running client-side or in a server-side PL, it's often helpful to look
at the details of events from below, as the last section explored. But for a
server-side PL, it doesn't stop there, because server-side code is usually
implementing logic that may have its own events to report, and as far as the
client-side is concerned, <em>those are just more events from the backend</em>.
Ideally, a PL function would be a "full citizen" and able to originate events
(or rethrow caught ones wrapped in higher-level descriptions) with the same
structure and quality one expects to see from PostgreSQL itself.</p>
<p>Here again, PL/pgSQL makes a good example. Using <a href="http://www.postgresql.org/docs/current/static/plpgsql-errors-and-messages.html" rel="nofollow">RAISE</a>, code can generate
an event with direct control of eleven of its most interesting attributes.
(The ones not settable from PL/pgSQL, cursor positions, line numbers, and such,
are at a level of detail few PL/pgSQL functions would want to work at anyway.)</p>
<p>PL/pgSQL has hit a kind of sweet spot with syntax that is so easy and clear
it invites writing good messages that an ultimate user could find helpful.
A statement like:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="RAISE invalid_text_representation USING
MESSAGE = 'Unrecognized prefix in telephone number ' || tno,
DETAIL = 'The digits at the start of the number do not match any known '
'international number prefix. Are you sure it is right?',
HINT = 'If you are sure it''s right, ask the IT people if '
'there is a more recent "ITU-T bulletin 994" they can load. '
'Meanwhile, you can enter the number with a ! in front, '
'but it may be flagged on data quality reports until fixed.';"><pre class="notranslate"><code>RAISE invalid_text_representation USING
MESSAGE = 'Unrecognized prefix in telephone number ' || tno,
DETAIL = 'The digits at the start of the number do not match any known '
'international number prefix. Are you sure it is right?',
HINT = 'If you are sure it''s right, ask the IT people if '
'there is a more recent "ITU-T bulletin 994" they can load. '
'Meanwhile, you can enter the number with a ! in front, '
'but it may be flagged on data quality reports until fixed.';
</code></pre></div>
<p>is about as clear as can be in the code, as well as giving anyone who receives
it a fighting chance at understanding what has happened.</p>
<div class="markdown-heading"><h4 class="heading-element">As for PL/Java</h4><a id="user-content-as-for-pljava-1" class="anchor" aria-label="Permalink: As for PL/Java" href="#as-for-pljava-1"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java is not yet at parity with PL/pgSQL on this dimension. If PL/Java code
<em>catches</em> any exception that began as a PostgreSQL <a href="http://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/utils/error/elog.c" rel="nofollow"><code>ereport</code></a>, that
Java exception will wrap an <a href="http://tada.github.io/pljava/pljava/apidocs/index.html?org/postgresql/pljava/internal/ErrorData.html" rel="nofollow"><code>ErrorData</code></a> object; if <em>that same
exception</em> is rethrown, it is transparently turned back into a PostgreSQL
event and continues on its way without information loss. But there is no way
for PL/Java code to <em>create</em> an exception with those properties. At best, it
can create an ordinary <code>SQLException</code>, which will turn into a PostgreSQL log
event using its <code>SQLState</code> and with its class name and message used as the
<code>message</code>.</p>
<p>For any other kind of exception, only <code>message</code> is set (from the exception
class name and message), and <code>SQLState</code> of <code>XX000</code> for "internal error".
When the origin is a Java exception, the severity will always be <code>ERROR</code>.</p>
<p>The other way for PL/Java code to originate a log event is to use the
logging API. PL/Java presents mostly Java standard APIs for code to use,
so in this case the API is <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/package-summary.html" rel="nofollow"><code>java.util.logging</code></a>, and PL/Java has
wired it so log events created that way are handed off to the PostgreSQL
logging system. (As a side effect of the way that system works, 'logging'
any event with a severity that maps to PostgreSQL <code>ERROR</code> turns out to have
the same effect as <em>throwing</em> it, while at any other severity it simply gets
logged.)</p>
<p>When passed on to PostgreSQL, the details include the timestamp, class name
or logger name, the message, and the stack trace of any associated Java
throwable—but at present, all of that ends up strung together in the
<code>message</code> attribute of the PostgreSQL event, using a severity mapped from
the <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Level.html" rel="nofollow"><code>java.util.logging.Level</code></a>. There are some other low-hanging-fruit
mappings that could be made automatically,
like the Java <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/LogRecord.html#getSourceClassName()" rel="nofollow"><code>SourceClassName</code></a> and <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/LogRecord.html#getSourceMethodName()" rel="nofollow"><code>SourceMethodName</code></a> to
PostgreSQL <code>filename</code> and <code>funcname</code>, but for the present they are not,
and no other programmatic control over the created log event is yet available
to PL/Java code.</p>
<div class="markdown-heading"><h5 class="heading-element">Mapping of severity levels</h5><a id="user-content-mapping-of-severity-levels" class="anchor" aria-label="Permalink: Mapping of severity levels" href="#mapping-of-severity-levels"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Because there are only seven predefined <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Level.html" rel="nofollow"><code>java.util.logging.Level</code></a>s and
some of their names are different from PostgreSQL's, PL/Java maps them as
follows:</p>
<table role="table">
<thead>
<tr>
<th></th>
<th></th>
<th>FINEST</th>
<th>FINER</th>
<th>FINE</th>
<th></th>
<th></th>
<th>INFO</th>
<th></th>
<th>WARNING</th>
<th>SEVERE</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>DEBUG5</td>
<td>DEBUG4</td>
<td>DEBUG3</td>
<td>DEBUG2</td>
<td>DEBUG1</td>
<td>LOG</td>
<td>COMMERROR</td>
<td>INFO</td>
<td>NOTICE</td>
<td>WARNING</td>
<td>ERROR</td>
<td>FATAL</td>
<td>PANIC</td>
</tr>
</tbody>
</table>
<p>The Java level <code>CONFIG</code> isn't explicitly mapped, and anything that isn't
explicit will map to the PostgreSQL level <code>LOG</code>. For completeness, I've
shown the PostgreSQL levels <code>FATAL</code> and <code>PANIC</code>, though a good case could be
made that no PL code should ever be allowed to use them.)</p>
<div class="markdown-heading"><h4 class="heading-element">How can JDBC front-end code originate events?</h4><a id="user-content-how-can-jdbc-front-end-code-originate-events" class="anchor" aria-label="Permalink: How can JDBC front-end code originate events?" href="#how-can-jdbc-front-end-code-originate-events"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>While the front-end situation may be simpler (there is no need to make
logging interoperate with server code in both directions, as PL/Java must),
some of the same considerations can be carried over. Even on the client end,
JDBC is not <em>the client</em>, it's still part of <em>the stack</em>. It may originate
its own log messages or throw its own <code>SQLException</code>s for reasons other than
events it forwards from the backend. Layers above it see a clean, consistent
picture of "the database stack" when those events are of similar form, no
matter the level they come from.</p>
<p>These days, there could even be another sophisticated layer or three sitting
on top of JDBC and beneath the application code, and it might want to have the
same facilities available to it.</p>
<p>A day that I would like to see—and I think it can be reached—is the day
when a PostgreSQL error can be raised by the backend, caught by PL/Java,
examined in all its structured detail by Java code using some extension
of the JDBC API, rethrown, piped to the frontend JDBC and thrown again to the
client code, caught there, and examined again in the same structured detail
using <em>the same extended API</em>.</p>
<p>This becomes even more appealing, and maybe even more achievable, if PL/Java
and a front-end JDBC work toward sharing more code.</p>
<div class="markdown-heading"><h5 class="heading-element">when throwing</h5><a id="user-content-when-throwing" class="anchor" aria-label="Permalink: when throwing" href="#when-throwing"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Being JDBC interfaces, both <code>pgjdbc</code> and <code>pgjdbc-ng</code> throw the standard JDBC
<code>SQLException</code> (or, more precisely, subclasses of it), and create instances
of the standard <code>SQLWarning</code>, which are collected and polled for, rather than
thrown.</p>
<p>JDBC categorized exceptions are not yet supported by <code>pgjdbc</code>, and are
partly supported by <code>pgjdbc-ng</code>.</p>
<p>The <code>pgjdbc-ng</code> exceptions that implement <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/api/jdbc/PGSQLExceptionInfo.html#method_summary" rel="nofollow"><code>PGSQLExceptionInfo</code></a> can be
instantiated from scratch, and can have the column, constraint,
datatype, schema, and table names set, as well as the JDBC standard
<code>SQLException</code> attributes.</p>
<p>The <code>pgjdbc</code> <a href="https://jdbc.postgresql.org/development/privateapi/index.html?org/postgresql/util/PSQLException.html" rel="nofollow"><code>PSQLException</code></a> and <a href="https://jdbc.postgresql.org/development/privateapi/index.html?org/postgresql/util/PSQLWarning.html" rel="nofollow"><code>PSQLWarning</code></a> throwables
can be instantiated from scratch, and can be constructed from a
<a href="https://jdbc.postgresql.org/documentation/publicapi/index.html?org/postgresql/util/ServerErrorMessage.html" rel="nofollow"><code>ServerErrorMessage</code></a> that can also be built from scratch, allowing
control over all of the same log event attributes that would be sent to the
front-end for a backend event. However, the only way at present to construct
that <code>ServerErrorMessage</code> is to supply a <code>String</code> in the exact format of the
<code>v3</code> protocol message that would come from the backend to represent the event.
The constructed exception's <code>message</code> then is set to the entire result of
<code>toString</code> on the <code>ServerErrorMessage</code>.</p>
<div class="markdown-heading"><h5 class="heading-element">when logging</h5><a id="user-content-when-logging" class="anchor" aria-label="Permalink: when logging" href="#when-logging"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Logging <strong>in <code>pgjdbc</code></strong>, which is older than <code>java.util.logging</code>, is done with
the project-specific <code>org.postgresql.core.Logger</code>. This simple class identifies
messages with a connection ID prefix, filters them by severity, timestamps
them, and writes them to the DriverManager's LogWriter. Unlike
<code>java.util.logging</code>, it doesn't do message formatting or internationalization,
but a separate class <a href="https://jdbc.postgresql.org/development/privateapi/index.html?org/postgresql/util/GT.html" rel="nofollow"><code>org.postgresql.util.GT</code></a> (also excluded from the
public API) does both when used in calls
to the logger. It gets translations from <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/ResourceBundle.html" rel="nofollow"><code>ResourceBundle</code></a>s, the same
form <code>java.util.logging</code> uses.</p>
<p>When logging a <code>PSQLException</code> instance that carries a
<code>ServerErrorMessage</code>, the result looks much like a message logged by the
backend, because <code>ServerErrorMessage.toString</code> produces that form (and it was
entirely stuffed into the <code>message</code> attribute of the exception).</p>
<p>Logging <strong>in <code>pgjdbc-ng</code></strong> is done using <code>java.util.logging</code>, as in PL/Java,
and in keeping with the appearance of <code>java.util.logging</code>-related API in
JDBC itself <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/sql/Driver.html#getParentLogger()" rel="nofollow">starting in 4.1</a>. In the existing examples in the code where a
<code>NoticeException</code> or <code>SQLException</code> are passed directly to the logger, most
of the available <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/protocol/Notice.html#method_summary" rel="nofollow"><code>Notice</code></a> or <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/api/jdbc/PGSQLExceptionInfo.html#method_summary" rel="nofollow"><code>PGSQLExceptionInfo</code></a> will
not be seen, as far as I can see, as <code>toString</code> has not been overridden.
<a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/jdbc/ErrorUtils.html" rel="nofollow"><code>ErrorUtils</code></a> will create the <code>SQLException</code> subclasses using only
the <code>message</code> and sqlstate from the original <code>Notice</code>. A
<a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/system/NoticeException.html" rel="nofollow"><code>NoticeException</code></a> holds a reference to the <code>Notice</code> it was constructed
from, and has a method to retrieve it, but the exception's message is set using
only the additional <code>String</code> passed to its constructor.</p>
<div class="markdown-heading"><h2 class="heading-element">What would a nice API look like?</h2><a id="user-content-what-would-a-nice-api-look-like" class="anchor" aria-label="Permalink: What would a nice API look like?" href="#what-would-a-nice-api-look-like"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>By this point it should be clear why I've been writing about "log events" as
one concept, when I might be expected to talk of log messages and exceptions
as separate things. In PostgreSQL and in JDBC, both are forms the same
information may take as it travels between A and B. It may be passed along
as a message on a log channel, received, and thrown as an exception; something
thrown as an exception can be caught and stuffed onto a log channel, where
"log channel" might mean the <code>ereport</code> conveyor in the server code, the
network protocol to the front end, the SQL warnings chain in JDBC, ....</p>
<p>This shapeshifting is not only possible but downright common in PostgreSQL and
JDBC, and especially in PL/Java, where the same event may be batted about
between those two forms repeatedly (how deep can the call stack get with PL/Java
functions making SQL queries that call other functions also made in PL/Java?).
And all of that is just fine as long as the conversion at each step is
information-preserving and reversible.</p>
<div class="markdown-heading"><h3 class="heading-element">An abstract <code>LogRecord</code> class (not derived from <code>Exception</code>)</h3><a id="user-content-an-abstract-logrecord-class-not-derived-from-exception" class="anchor" aria-label="Permalink: An abstract LogRecord class (not derived from Exception)" href="#an-abstract-logrecord-class-not-derived-from-exception"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>We've seen that all three of (<code>pgjdbc</code>, <code>pgjdbc-ng</code>, <code>PL/Java</code>) include a
class of some sort (<a href="https://jdbc.postgresql.org/documentation/publicapi/index.html?org/postgresql/util/ServerErrorMessage.html" rel="nofollow"><code>ServerErrorMessage</code></a>, <a href="http://impossibl.github.io/pgjdbc-ng/apidocs/0.6/index.html?com/impossibl/postgres/protocol/Notice.html#method_summary" rel="nofollow"><code>Notice</code></a>, and
<a href="http://tada.github.io/pljava/pljava/apidocs/index.html?org/postgresql/pljava/internal/ErrorData.html" rel="nofollow"><code>ErrorData</code></a>, respectively) that is meant to carry all the information
about a PostgreSQL log event in its intact structured form, and can be
carried over a log channel or wrapped in an exception, and recovered at the
end of a journey either way.</p>
<p>So, my proposal starts here: there should be such a class, and it should be
documented and available as PostgreSQL extended JDBC API. For this discussion,
I'll call it <code>LogRecord</code>. (There will be time for polishing name choices.
There is an existing Java class <code>LogRecord</code> but of course the package is
different.)</p>
<div class="markdown-heading"><h3 class="heading-element">An interface for exceptions that carry <code>LogRecord</code>s</h3><a id="user-content-an-interface-for-exceptions-that-carry-logrecords" class="anchor" aria-label="Permalink: An interface for exceptions that carry LogRecords" href="#an-interface-for-exceptions-that-carry-logrecords"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>To allow moving forward with the <a href="http://www.javaspecialists.eu/archive/Issue138.html" rel="nofollow">categorized exceptions</a> in
JDBC 4.0, there needs to be an interface rather than a common parent class,
and simply has a setter and getter for attaching a <code>LogRecord</code> to the
exception. These would ordinarily not be used directly, but rather through
methods of <code>LogRecord</code>.</p>
<div class="markdown-heading"><h3 class="heading-element">Different concrete subclasses of <code>LogRecord</code>
</h3><a id="user-content-different-concrete-subclasses-of-logrecord" class="anchor" aria-label="Permalink: Different concrete subclasses of LogRecord" href="#different-concrete-subclasses-of-logrecord"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java would supply its special concrete implementation that wraps a
native error-data block; a front-end JDBC would supply one (or two) that
are initialized from the on-the-wire protocol. In all cases, there would be
a plain pure-Java one that can be filled in from scratch.</p>
<div class="markdown-heading"><h3 class="heading-element">An <code>ereport</code>-like API for creating a <code>LogRecord</code> from scratch</h3><a id="user-content-an-ereport-like-api-for-creating-a-logrecord-from-scratch" class="anchor" aria-label="Permalink: An ereport-like API for creating a LogRecord from scratch" href="#an-ereport-like-api-for-creating-a-logrecord-from-scratch"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>... starting with a static method on <code>LogRecord</code> and with method chaining:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import static org.postgresql.something.LogRecord.ereport;
...
logrec = ereport(Level.ERROR).errcode(ERRCODE_DIVISION_BY_ZERO)
.errmsg("You''ve tried to divide {0} by zero", dividend)
// .log() OR
// .throwAs(SQLException.class)"><pre class="notranslate"><code>import static org.postgresql.something.LogRecord.ereport;
...
logrec = ereport(Level.ERROR).errcode(ERRCODE_DIVISION_BY_ZERO)
.errmsg("You''ve tried to divide {0} by zero", dividend)
// .log() OR
// .throwAs(SQLException.class)
</code></pre></div>
<div class="markdown-heading"><h3 class="heading-element">Methods for the conversions into/out of log system or exception</h3><a id="user-content-methods-for-the-conversions-intoout-of-log-system-or-exception" class="anchor" aria-label="Permalink: Methods for the conversions into/out of log system or exception" href="#methods-for-the-conversions-intoout-of-log-system-or-exception"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Examples <code>log()</code> and <code>throwAs()</code> were seen above, with <code>throwAs</code> a convenience
built on <code>asException(...)</code>. If the <code>LogRecord</code> has been freshly constructed,
<code>asException</code> creates the correct JDBC 4 categorized exception with a reference
to the log record and vice versa. If that has happened already, it just returns
the already created exception object.</p>
<p>The static <code>fromException()</code> method does the reverse: if the exception was
created from a <code>LogRecord</code> originally (so, it implements the interface and its
log record reference isn't null), just returns that original <code>LogRecord</code>. If
not, creates a new <code>LogRecord</code> initialized as informatively as possible with
whatever can be gleaned from the exception.</p>
<p>Those methods are what make possible the repeated batting around that an event
might live through on its way from a deep call stack in PL/Java all the way
out to a handler on the front end, without having serious identity crises.
(It will be trickier inside PL/Java than I need to spend time on here, but
should not be prohibitively so.)</p>
<div class="markdown-heading"><h3 class="heading-element">In concert with existing standard API</h3><a id="user-content-in-concert-with-existing-standard-api" class="anchor" aria-label="Permalink: In concert with existing standard API" href="#in-concert-with-existing-standard-api"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>I propose to converge on <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/package-summary.html" rel="nofollow"><code>java.util.logging</code></a>, and for this extended
<code>LogRecord</code> class to be derived from the standard <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/LogRecord.html" rel="nofollow"><code>LogRecord</code></a>.</p>
<p>(Soon below I will touch on how to "converge on <code>java.util.logging</code>" without
serious disruption of <code>pgjdbc</code>, which currently uses the homegrown logging
class.)</p>
<p>The specialized class will have several extra methods, and some overridden
ones just to give it a reasonable default behavior when treated as an
ordinary <code>java.util.logging.LogRecord</code>. For example its overridden
<a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/LogRecord.html#getMessage()" rel="nofollow"><code>getMessage</code></a> method may do some formatting by default and return
more information than just the <code>message</code> field, while different methods would
be provided for a caller in the know to examine specific individual fields.</p>
<p>None of those differences stop it from being a valid instance of
<code>java.util.logging.LogRecord</code>, and it can be passed into the logging system
by calling <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Logger.html#log(java.util.logging.LogRecord)" rel="nofollow"><code>log</code></a> just like any other record. So can other, non-extended
<code>LogRecord</code>s and normal calls on the convenience methods of
<a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Logger.html" rel="nofollow"><code>Logger</code></a>, all at the same time. Code ported from other environments,
knowing nothing of the extensions and using the standard logger API will work
fine, and can be mixed with code using the extended features.</p>
<p>Call sites that aren't trying to make good user-visible messages (all the
usual <code>logger.finest("sent an M, got two dollar signs and a comma")</code> kind of
thing) don't have any need to change.</p>
<div class="markdown-heading"><h3 class="heading-element">Using familiar level names</h3><a id="user-content-using-familiar-level-names" class="anchor" aria-label="Permalink: Using familiar level names" href="#using-familiar-level-names"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The current implementation in PL/Java maps PostgreSQL severity levels onto
the (smaller set of) standard <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Level.html" rel="nofollow"><code>Level</code></a>s. This adds another bit of
cognitive load in the development process: I have to remember, for example,</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SET log_min_messages TO DEBUG2;
SELECT javatest.logmessage('FINER', 'Hello world');"><pre class="notranslate"><code>SET log_min_messages TO DEBUG2;
SELECT javatest.logmessage('FINER', 'Hello world');
</code></pre></div>
<p>are talking about the same severity level, and it's an error to forget and
use the other name either place, and the mapping loses information—it's
not invertible.</p>
<p>A feature of the design of <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Level.html" rel="nofollow"><code>Level</code></a> is it can be subclassed, and
additional levels can be defined; the numeric values of the standard ones
are spaced widely apart to allow new ones between them, and the parser even
learns the names of new levels so they "just work". I propose defining the
PostgreSQL levels whose names do not already match <a href="http://docs.oracle.com/javase/7/docs/api/index.html?java/util/logging/Level.html" rel="nofollow"><code>Level</code></a> names,
with a possible relationship like this:</p>
<table role="table">
<thead>
<tr>
<th align="right">PostgreSQL</th>
<th>Java</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right"></td>
<td>ALL</td>
</tr>
<tr>
<td align="right"></td>
<td>FINEST?</td>
</tr>
<tr>
<td align="right">DEBUG5</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>FINEST?</td>
</tr>
<tr>
<td align="right">DEBUG4</td>
<td></td>
</tr>
<tr>
<td align="right">DEBUG3</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>FINER</td>
</tr>
<tr>
<td align="right">DEBUG2</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>FINE</td>
</tr>
<tr>
<td align="right">DEBUG1</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>CONFIG</td>
</tr>
<tr>
<td align="right">LOG</td>
<td></td>
</tr>
<tr>
<td align="right">COMMERROR</td>
<td></td>
</tr>
<tr>
<td align="right">INFO</td>
<td>INFO</td>
</tr>
<tr>
<td align="right">NOTICE</td>
<td></td>
</tr>
<tr>
<td align="right">WARNING</td>
<td>WARNING</td>
</tr>
<tr>
<td align="right"></td>
<td>SEVERE?</td>
</tr>
<tr>
<td align="right">ERROR</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>SEVERE?</td>
</tr>
<tr>
<td align="right">FATAL</td>
<td></td>
</tr>
<tr>
<td align="right">PANIC</td>
<td></td>
</tr>
<tr>
<td align="right"></td>
<td>OFF</td>
</tr>
</tbody>
</table>
<p>As you can see, I'm still considering arguments about where <code>FINEST</code> and
<code>SEVERE</code> should go.</p>
<p>The effect, again, is that code from elsewhere that only expects the usual
names from the standard library will work fine, code with more PostgreSQLy
origins can use those familiar names, and a developer or admin can set the
logging level using any of them, whichever seems more natural at the time.</p>
<div class="markdown-heading"><h3 class="heading-element">Could <code>pgjdbc</code> move to <code>java.util.logging</code> without disruption?</h3><a id="user-content-could-pgjdbc-move-to-javautillogging-without-disruption" class="anchor" aria-label="Permalink: Could pgjdbc move to java.util.logging without disruption?" href="#could-pgjdbc-move-to-javautillogging-without-disruption"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>I think so. The class <code>org.postgresql.core.Logger</code> could be kept, and
simply delegate to other classes; the changes at points where log events
are read off the wire and exceptions are created should be fairly internal
and localized. I'd like to give it a shot.</p>
<p>I think the categorized exceptions in JDBC 4 are worth moving to, and
offer a much nicer way for client code to distinguish what kind of thing
went wrong, but changing <em>that</em> might actually turn out to be what needs
the most coordination with client code. I would like to hope there isn't
much client code out there that has linked to <code>PSQLException</code> by name
(when it is only shown on "privateapi" javadocs), but I can only imagine
there is some.</p>
<div class="markdown-heading"><h2 class="heading-element">A place to pause</h2><a id="user-content-a-place-to-pause" class="anchor" aria-label="Permalink: A place to pause" href="#a-place-to-pause"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>I have not managed to squeeze in every relevant thought here, but this is
already long and enough to elicit some discussion and questions, and if I
keep writing I will probably just be answering the wrong ones, so this
seems a good place to stop and listen.</p>
https://github.com/tada/pljava/wiki/Performance-tuning/537b40c0e180bfa2d9a35191e64aae2ac9edc9e62018-10-17T02:02:42-04:002018-10-17T02:02:42-04:00Performance tuningjcflack
<div class="markdown-heading"><h1 class="heading-element">Tuning PL/Java performance</h1><a id="user-content-tuning-pljava-performance" class="anchor" aria-label="Permalink: Tuning PL/Java performance" href="#tuning-pljava-performance"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>As of 2018, there is a strong selection of Java runtimes that can be used
to back PL/Java, including at least:</p>
<ul>
<li>Oracle's Java (and Hotspot JVM)</li>
<li>OpenJDK (with Hotspot JVM)</li>
<li>OpenJDK (with Eclipse OpenJ9 JVM)</li>
</ul>
<p>These JVMs offer a wide variety of configurable options affecting both memory
footprint and time performance of applications using PL/Java. The options
include initial and limit sizes for different memory regions, aggressiveness
of just-in-time and ahead-of-time compilation, choice of garbage-collection
algorithm, and various forms of shared-memory caching of precompiled classes.</p>
<p>The formal PL/Java documentation contains
<a href="http://tada.github.io/pljava/install/vmoptions.html" rel="nofollow">a fairly extensive treatment of useful Hotspot settings</a>, including
a section on plausible minimum settings for memory footprint achievable with
different class-sharing and garbage-collector settings. The documentation there
of the comparable options and limits for OpenJ9 is more sparse at present.</p>
<p>This wiki page is intended as a clearinghouse for tuning tips and performance
measurements for various PL/Java workloads and the available Java runtimes,
that can be updated more actively between releases of the formal documentation.</p>
<div class="markdown-heading"><h2 class="heading-element">Tip for quickly comparing runtime configurations</h2><a id="user-content-tip-for-quickly-comparing-runtime-configurations" class="anchor" aria-label="Permalink: Tip for quickly comparing runtime configurations" href="#tip-for-quickly-comparing-runtime-configurations"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Once the PL/Java extension is installed in a database, in any newly-created
session, the Java virtual machine is started on the first use of a PL/Java
function. The JVM that is started, and how, are determined by the settings
of <code>pljava.*</code> configuration variables in effect at that moment, most
importantly:</p>
<ul>
<li>
<code>pljava.libjvm_location</code> selects which Java runtime will be used</li>
<li>
<code>pljava.vmoptions</code> supplies the options to be passed to it</li>
</ul>
<p>Therefore, all without exiting <code>psql</code>, a new Java runtime or combination of
options can be tested by switching to a new connection with <code>\c</code>, setting those
options differently, and again calling the PL/Java function of interest.</p>
<p>It can be convenient to include the settings on the psql <code>\c</code> line. For example,
to time <code>functionOfInterest()</code> on two different Java runtimes:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="\c "dbname=postgres options='-c pljava.libjvm_location=/path/to/oracle/.../libjvm.so'"
EXPLAIN ANALYZE SELECT functionOfInterest();
\c "dbname=postgres options='-c pljava.libjvm_location=/path/to/openj9/.../libjvm.so'"
EXPLAIN ANALYZE SELECT functionOfInterest();"><pre class="notranslate"><code>\c "dbname=postgres options='-c pljava.libjvm_location=/path/to/oracle/.../libjvm.so'"
EXPLAIN ANALYZE SELECT functionOfInterest();
\c "dbname=postgres options='-c pljava.libjvm_location=/path/to/openj9/.../libjvm.so'"
EXPLAIN ANALYZE SELECT functionOfInterest();
</code></pre></div>
<p>For obvious reasons, the <code>pljava.libjvm_location</code> and <code>pljava.vmoptions</code>
variables require privilege to set, so the connection needs to be made
with superuser credentials.</p>
<div class="markdown-heading"><h2 class="heading-element">Sample workload: Java XML manipulation</h2><a id="user-content-sample-workload-java-xml-manipulation" class="anchor" aria-label="Permalink: Sample workload: Java XML manipulation" href="#sample-workload-java-xml-manipulation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>We will create a table containing a single XML document:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE TABLE catalog_as_xml AS
SELECT schema_to_xml('pg_catalog', true, false, '') AS x;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">TABLE</span> <span class="pl-en">catalog_as_xml</span> <span class="pl-k">AS</span>
<span class="pl-k">SELECT</span> schema_to_xml(<span class="pl-s"><span class="pl-pds">'</span>pg_catalog<span class="pl-pds">'</span></span>, true, false, <span class="pl-s"><span class="pl-pds">'</span><span class="pl-pds">'</span></span>) <span class="pl-k">AS</span> x;</pre></div>
<p>In PostgreSQL 11beta3, the resulting document has the following size (after
PL/Java and the example code have been loaded):</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT octet_length(xml_send(x)) AS uncompressed, pg_column_size(x) AS toasted
FROM catalog_as_xml;"><pre><span class="pl-k">SELECT</span> octet_length(xml_send(x)) <span class="pl-k">AS</span> uncompressed, pg_column_size(x) <span class="pl-k">AS</span> toasted
<span class="pl-k">FROM</span> catalog_as_xml;</pre></div>
<table role="table">
<thead>
<tr>
<th align="right">uncompressed</th>
<th align="right">toasted</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right">14049808</td>
<td align="right">1130828</td>
</tr>
</tbody>
</table>
<p>A test query will return the string value of every element whose string value
is exactly six characters (a query that may be artificial and contrived, but
can be expressed nearly identically in XML Query (the standard-mandated language
for SQL <code>XMLTABLE</code>) and in the PostgreSQL native <code>XMLTABLE</code> syntax, which is
limited to XPath 1.0).</p>
<p>The baseline will be the query expressed in XPath 1.0 using the PostgreSQL
<code>XMLTABLE</code> function:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="EXPLAIN ANALYZE SELECT
xmltable.*
FROM
catalog_as_xml,
XMLTABLE('//*[string-length(.) = 6]'
PASSING x
COLUMNS s text PATH 'string(.)'
);"><pre>EXPLAIN ANALYZE <span class="pl-k">SELECT</span>
xmltable.<span class="pl-k">*</span>
<span class="pl-k">FROM</span>
catalog_as_xml,
XMLTABLE(<span class="pl-s"><span class="pl-pds">'</span>//*[string-length(.) = 6]<span class="pl-pds">'</span></span>
PASSING x
COLUMNS s <span class="pl-k">text</span> <span class="pl-k">PATH</span> <span class="pl-s"><span class="pl-pds">'</span>string(.)<span class="pl-pds">'</span></span>
);</pre></div>
<p>It will be compared to the equivalent query expressed in XQuery 1.0
and the <code>"xmltable"</code> function defined in the not-built-by-default
<a href="http://tada.github.io/pljava/examples/saxon.html" rel="nofollow"><code>org.postgresql.pljava.example.saxon.S9</code></a> example, relying on the
<a href="http://www.saxonica.com/products/products.xml" rel="nofollow">Saxon-HE</a> library:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="EXPLAIN ANALYZE SELECT
xmltable.*
FROM
catalog_as_xml,
LATERAL (SELECT x AS ".") AS p,
"xmltable"('//*[string-length(.) eq 6]',
PASSING => p,
COLUMNS => array[ 'string(.)' ]
) AS ( s text );"><pre>EXPLAIN ANALYZE <span class="pl-k">SELECT</span>
xmltable.<span class="pl-k">*</span>
<span class="pl-k">FROM</span>
catalog_as_xml,
LATERAL (<span class="pl-k">SELECT</span> x <span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">"</span>.<span class="pl-pds">"</span></span>) <span class="pl-k">AS</span> p,
<span class="pl-s"><span class="pl-pds">"</span>xmltable<span class="pl-pds">"</span></span>(<span class="pl-s"><span class="pl-pds">'</span>//*[string-length(.) eq 6]<span class="pl-pds">'</span></span>,
PASSING <span class="pl-k">=></span> p,
COLUMNS <span class="pl-k">=></span> array[ <span class="pl-s"><span class="pl-pds">'</span>string(.)<span class="pl-pds">'</span></span> ]
) <span class="pl-k">AS</span> ( s <span class="pl-k">text</span> );</pre></div>
<p>The Java query will be run in both Oracle Java 8 (on the Hotspot JVM) and
OpenJDK 8 (with the OpenJ9 JVM), with different choices of class-sharing
options:</p>
<table role="table">
<thead>
<tr>
<th align="right">tag</th>
<th>description</th>
</tr>
</thead>
<tbody>
<tr>
<td align="right"><code>pg</code></td>
<td>Baseline, PostgreSQL <code>XMLTABLE</code>
</td>
</tr>
<tr>
<td align="right"><code>hs</code></td>
<td>Hotspot, no sharing</td>
</tr>
<tr>
<td align="right"><code>hs-cds</code></td>
<td>Hotspot, class data sharing (Java runtime classes only)</td>
</tr>
<tr>
<td align="right"><code>hs-appcds</code></td>
<td>Hotspot, AppCDS (commercial feature), Java runtime, PL/Java, Saxon</td>
</tr>
<tr>
<td align="right"><code>j9</code></td>
<td>OpenJ9, no <code>-Xquickstart</code>, no sharing</td>
</tr>
<tr>
<td align="right"><code>j9q</code></td>
<td>OpenJ9, <code>-Xquickstart</code>, no sharing</td>
</tr>
<tr>
<td align="right"><code>j9s</code></td>
<td>OpenJ9, no <code>-Xquickstart</code>, sharing (Java runtime, PL/Java, Saxon)</td>
</tr>
<tr>
<td align="right"><code>j9qs</code></td>
<td>OpenJ9, <code>-Xquickstart</code>, sharing (as above)</td>
</tr>
</tbody>
</table>
<p><code>EXPLAIN ANALYZE</code> reported timings in milliseconds:</p>
<table role="table">
<thead>
<tr>
<th>iteration</th>
<th align="right"><code>pg</code></th>
<th align="right"><code>hs</code></th>
<th align="right"><code>hs-cds</code></th>
<th align="right"><code>hs-appcds</code></th>
<th align="right"><code>j9</code></th>
<th align="right"><code>j9q</code></th>
<th align="right"><code>j9s</code></th>
<th align="right"><code>j9qs</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>1st</td>
<td align="right">908.231</td>
<td align="right">1888.859</td>
<td align="right">1837.186</td>
<td align="right">1539.781</td>
<td align="right">3250.965</td>
<td align="right">3095.733</td>
<td align="right">2443.649</td>
<td align="right">2644.991</td>
</tr>
<tr>
<td>2nd</td>
<td align="right">879.483</td>
<td align="right">772.545</td>
<td align="right">838.082</td>
<td align="right">826.558</td>
<td align="right">1229.200</td>
<td align="right">1855.513</td>
<td align="right">1073.335</td>
<td align="right">1932.083</td>
</tr>
<tr>
<td>4th</td>
<td align="right">881.302</td>
<td align="right">664.422</td>
<td align="right">688.487</td>
<td align="right">673.037</td>
<td align="right">1011.018</td>
<td align="right">1708.208</td>
<td align="right">987.191</td>
<td align="right">1912.010</td>
</tr>
<tr>
<td>8th</td>
<td align="right">880.766</td>
<td align="right">640.940</td>
<td align="right">643.535</td>
<td align="right">632.260</td>
<td align="right">962.517</td>
<td align="right">1660.867</td>
<td align="right">952.857</td>
<td align="right">1870.506</td>
</tr>
<tr>
<td>16th</td>
<td align="right">880.622</td>
<td align="right">654.674</td>
<td align="right">682.772</td>
<td align="right">627.037</td>
<td align="right">967.805</td>
<td align="right">1656.651</td>
<td align="right">943.923</td>
<td align="right">1941.888</td>
</tr>
</tbody>
</table>
<div class="markdown-heading"><h3 class="heading-element">Discussion</h3><a id="user-content-discussion" class="anchor" aria-label="Permalink: Discussion" href="#discussion"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>The baseline native <code>XMLTABLE</code> implementation in PostgreSQL delivers
consistent times over successive runs. Java timings improve over successive
early runs, as the VM identifies and reoptimizes hot areas.</li>
<li>For all of the Java results, the first-iteration result includes the time
to launch the Java virtual machine. For Hotspot, this gives a time to first
result from 67% (best) to 108% (worst) longer than the native baseline.</li>
<li>All tested Hotspot configurations are outperforming the native implementation
as soon as the next iteration, and eventually by 22% to 28%.</li>
<li>For this workload, Hotspot seems to have a striking performance advantage
relative to OpenJ9. Possible explanations:
<ul>
<li>Saxon is a mature and carefully-optimized library; are its optimizations
extremely specific to Hotspot?</li>
<li>PL/Java makes heavy use of JNI; could this pattern be less well handled
in OpenJ9?</li>
</ul>
</li>
<li>OpenJ9's <code>-Xquickstart</code> is a poor fit for this workload, as it suppresses
JIT optimization so drastically that performance improves very little on
successive runs.</li>
<li>The combination of <code>-Xquickstart</code> and <code>-Xshareclasses</code> for this workload is
especially disappointing, probably because the two features, when combined,
force the ahead-of-time compilation of all methods. That sounds promising,
but not if the AOT code significantly underperforms what the optimizing JIT
would generate.</li>
<li>Memory footprint was not compared. PL/Java's <a href="http://tada.github.io/pljava/install/vmoptions.html" rel="nofollow">documentation</a> already
has a section on plausible memory settings for Hotspot, but not for OpenJ9,
which has a good reputation for memory frugality. Exploration would be
worthwhile.</li>
<li>There could be other workloads in which the Hotspot and OpenJ9 relative
timings could be closer, or even reversed.</li>
<li>The procedure to set up class sharing for OpenJ9 is considerably simpler
than to set up <code>AppCDS</code> for Hotspot, enough to make OpenJ9 an attractive
choice for workloads where the performance is more comparable.</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Variation by processor count</h3><a id="user-content-variation-by-processor-count" class="anchor" aria-label="Permalink: Variation by processor count" href="#variation-by-processor-count"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The results above were obtained with 6 available processor cores (12
hyperthreads). Here, the best Hotspot (<code>h-</code>) and OpenJ9 (<code>j-</code>) configurations
from above (<code>hs-appcds</code> and <code>j9s</code>, respectively) are repeated for different
numbers of cores and threads available to the backend process.</p>
<table role="table">
<thead>
<tr>
<th>iteration</th>
<th align="right"><code>h-4c8t</code></th>
<th align="right"><code>h-4c4t</code></th>
<th align="right"><code>h-2c4t</code></th>
<th align="right"><code>h-2c2t</code></th>
<th align="right"><code>h-1c2t</code></th>
<th align="right"><code>h-1c1t</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>1st</td>
<td align="right">1798.020</td>
<td align="right">2140.068</td>
<td align="right">1871.740</td>
<td align="right">2760.872</td>
<td align="right">2564.169</td>
<td align="right">4306.058</td>
</tr>
<tr>
<td>2nd</td>
<td align="right">780.182</td>
<td align="right">827.379</td>
<td align="right">825.943</td>
<td align="right">1054.749</td>
<td align="right">1064.300</td>
<td align="right">1704.112</td>
</tr>
<tr>
<td>4th</td>
<td align="right">661.740</td>
<td align="right">672.415</td>
<td align="right">662.259</td>
<td align="right">786.407</td>
<td align="right">734.421</td>
<td align="right">756.054</td>
</tr>
<tr>
<td>8th</td>
<td align="right">619.978</td>
<td align="right">653.686</td>
<td align="right">641.784</td>
<td align="right">659.112</td>
<td align="right">678.855</td>
<td align="right">722.792</td>
</tr>
<tr>
<td>16th</td>
<td align="right">619.824</td>
<td align="right">647.092</td>
<td align="right">664.287</td>
<td align="right">671.862</td>
<td align="right">639.365</td>
<td align="right">651.502</td>
</tr>
</tbody>
</table>
<table role="table">
<thead>
<tr>
<th>iteration</th>
<th align="right"><code>j-4c8t</code></th>
<th align="right"><code>j-4c4t</code></th>
<th align="right"><code>j-2c4t</code></th>
<th align="right"><code>j-2c2t</code></th>
<th align="right"><code>j-1c2t</code></th>
<th align="right"><code>j-1c1t</code></th>
</tr>
</thead>
<tbody>
<tr>
<td>1st</td>
<td align="right">2413.365</td>
<td align="right">2419.176</td>
<td align="right">2411.006</td>
<td align="right">2470.092</td>
<td align="right">2457.868</td>
<td align="right">3673.986</td>
</tr>
<tr>
<td>2nd</td>
<td align="right">1108.991</td>
<td align="right">1093.504</td>
<td align="right">1050.731</td>
<td align="right">1142.424</td>
<td align="right">1072.635</td>
<td align="right">2599.973</td>
</tr>
<tr>
<td>4th</td>
<td align="right">969.465</td>
<td align="right">1003.736</td>
<td align="right">988.883</td>
<td align="right">983.431</td>
<td align="right">941.495</td>
<td align="right">1032.896</td>
</tr>
<tr>
<td>8th</td>
<td align="right">967.447</td>
<td align="right">900.644</td>
<td align="right">963.011</td>
<td align="right">926.342</td>
<td align="right">920.390</td>
<td align="right">1032.316</td>
</tr>
<tr>
<td>16th</td>
<td align="right">1113.963</td>
<td align="right">932.503</td>
<td align="right">1496.240</td>
<td align="right">925.137</td>
<td align="right">939.179</td>
<td align="right">990.072</td>
</tr>
</tbody>
</table>
<div class="markdown-heading"><h4 class="heading-element">Discussion</h4><a id="user-content-discussion-1" class="anchor" aria-label="Permalink: Discussion" href="#discussion-1"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Hotspot's initial startup uses parallelism to good advantage, so the startup
time suffers when cores are limited, and especially when limited to one hardware
thread. Interestingly, comparing sets with the same number of threads, in one
case independent on an equal number of cores, and in the other case hyperthreads
on half as many cores, the data above seem to favor the hyperthreaded case.
More runs might reveal whether that apparent pattern persists.</p>
<p>Even with only one hardware thread available, Hotspot can still produce code
that outperforms the native <code>libxml2</code> no later than the fourth iteration.</p>
<p>OpenJ9, while not achieving the ultimate speeds of Hotspot on this workload,
shows a first-run time that suffers less when limited to few CPUs. However,
that advantage diminishes when taking the times of the first two runs into
account.</p>
<p>Not shown in these tables, but as expected, the baseline PostgreSQL native
<code>XMLTABLE</code> posted timings of 893 ms first run, 877 ms second run, consistently
with the earlier values, even when limited to one core, one thread.</p>
<div class="markdown-heading"><h3 class="heading-element">Notes on methodology</h3><a id="user-content-notes-on-methodology" class="anchor" aria-label="Permalink: Notes on methodology" href="#notes-on-methodology"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h4 class="heading-element">Platform</h4><a id="user-content-platform" class="anchor" aria-label="Permalink: Platform" href="#platform"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Intel Xeon X5650 2.67 GHz, 6 cores (12 hyperthreads), 24 GB RAM, Linux.</p>
<p>PostgreSQL installation, Java runtimes, database, and PL/Java and Saxon
libraries and jars installed in an in-memory (<code>tmpfs</code>) filesystem.</p>
<div class="markdown-heading"><h4 class="heading-element">Connection strings used for each test configuration</h4><a id="user-content-connection-strings-used-for-each-test-configuration" class="anchor" aria-label="Permalink: Connection strings used for each test configuration" href="#connection-strings-used-for-each-test-configuration"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><em>Note: the connection strings below for the Hotspot runs with <code>AppCDS</code> contain
the option <code>-XX:+UnlockCommercialFeatures</code> because the runs were done on
Oracle Java 8 where <code>AppCDS</code> is a commercial feature, and its use in production
will need a license from Oracle. The same feature appears in OpenJDK with
Hotspot starting in Java 10, where it is not a commercial feature, and does not
require that <code>-XX:+UnlockCommercialFeatures</code> option; it is otherwise configured
in the same way.</em></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:off -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:on -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:on\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS\\\ -XX:SharedArchiveFile=/var/tmp/nohome/pljava.jsa -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xquickstart'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xshareclasses:cacheDir=/var/tmp/pljavaj9cache'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xshareclasses:cacheDir=/var/tmp/pljavaj9cache\\\ -Xquickstart'""><pre class="notranslate"><code>\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:off -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:on -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:on\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS\\\ -XX:SharedArchiveFile=/var/tmp/nohome/pljava.jsa -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xquickstart'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xshareclasses:cacheDir=/var/tmp/pljavaj9cache'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so -c pljava.vmoptions=-Xshareclasses:cacheDir=/var/tmp/pljavaj9cache\\\ -Xquickstart'"
</code></pre></div>
<div class="markdown-heading"><h4 class="heading-element">Jars loaded into PL/Java</h4><a id="user-content-jars-loaded-into-pljava" class="anchor" aria-label="Permalink: Jars loaded into PL/Java" href="#jars-loaded-into-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The PL/Java <code>sqlj.install_jar</code> function was used to install the PL/Java
examples jar (giving it the name <code>ex</code>), with <code>deploy => true</code> to create the
function declarations, and also the <code>Saxon-HE-9.8.0-14.jar</code>, naming it <code>saxon</code>.</p>
<p>The PL/Java application classpath (set with <code>sqlj.set_classpath</code> on the <code>public</code>
schema), was <code>ex</code> during the Hotspot runs, and <code>ex:saxon</code> during the OpenJ9
runs. (For the Hotspot runs, the Saxon jar was placed on the system classpath
by adding it to <code>pljava.classpath</code> instead, as explained below.)</p>
<div class="markdown-heading"><h4 class="heading-element">Setup for Hotspot</h4><a id="user-content-setup-for-hotspot" class="anchor" aria-label="Permalink: Setup for Hotspot" href="#setup-for-hotspot"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>The existing Hotspot installation on disk was copied to the <code>tmpfs</code>.</li>
<li>That invalidates the paths in the supplied <code>classes.jsa</code> shared archive that
was generated when Java was installed to its location on disk, so the
<code>lib/amd64/server/classes.jsa</code> file was removed from the copy and
regenerated with <code>java -Xshare:dump</code> to contain the correct paths. That
shared archive contains only classes of the Java runtime itself.</li>
<li>The shared archive for <code>AppCDS</code>, to include PL/Java implementation
classes and the Saxon library as well as the Java runtime's classes,
was generated in two steps:
<ol>
<li>A connection string with <code>-XX:DumpLoadedClassList=filename</code> was issued
and the test query was executed, to populate the class list with the
needed classes.</li>
<li>A new connection string with <code>-Xshare:dump</code> and <code>-XX:SharedClassListFile</code>
naming the classlist file generated in the first step was issued, and
then <code>SELECT sqlj.get_classpath('public');</code> to trigger PL/Java loading.
Java reads the class list and generates the shared archive, and the
backend exits.</li>
</ol>
</li>
<li>Because Hotspot <code>AppCDS</code> will share only classes from the system classpath,
the <code>pljava.classpath</code> setting was altered to include
<code>Saxon-HE-9.8.0-14.jar</code> as well as the PL/Java jar.</li>
<li>Because PL/Java's security manager disallows jar loading from arbitrary
filesystem locations, the <code>Saxon-HE-9.8.0-14.jar</code> was placed in Java's
<code>jre/lib</code> directory and the <code>pljava.classpath</code> referred to it there.</li>
<li>
<code>AppCDS</code> will not share classes contained in a signed jar, and the distributed
<code>Saxon-HE-9.8.0-14.jar</code> is signed, so the copy placed in <code>jre/lib</code> was
"de-signed" by deleting its <code>TE-050AC.SF</code> entry and all <code>Name:</code>/<code>Digest:</code>
sections from its <code>MANIFEST.MF</code> entry.</li>
</ul>
<div class="markdown-heading"><h4 class="heading-element">Setup for OpenJ9</h4><a id="user-content-setup-for-openj9" class="anchor" aria-label="Permalink: Setup for OpenJ9" href="#setup-for-openj9"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>The OpenJDK with OpenJ9 download was unzipped in the <code>/var/tmp</code> <code>tmpfs</code>.</li>
<li>Because PL/Java under OpenJ9 is able to share classes from the PL/Java
application classpath (the one managed by <code>sqlj.set_classpath</code>) and not
just the system classpath, there was no need to add the Saxon jar to
<code>pljava.classpath</code> as there was for Hotspot. It was simply loaded
with <code>sqlj.install_jar</code> under the name <code>saxon</code>, and put on the application
classpath with <code>SELECT sqlj.set_classpath('public', 'ex:saxon');</code>.</li>
<li>Each set of runs with sharing (<code>j9s</code>, <code>j9qs</code>) was prepared by starting a fresh
session with the same connection string to be used for that set, and the
<code>shareDir</code> named in that connection string empty. Sixteen runs were made
without timing, to populate the shared cache.</li>
<li>Then the same connection string was used again to start a fresh session,
and the full set of 16 runs repeated and timed.</li>
</ul>
<div class="markdown-heading"><h4 class="heading-element">Connection strings generating <code>AppCDS</code> shared archive</h4><a id="user-content-connection-strings-generating-appcds-shared-archive" class="anchor" aria-label="Permalink: Connection strings generating AppCDS shared archive" href="#connection-strings-generating-appcds-shared-archive"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><em>See the earlier note concerning the <code>-XX:+UnlockCommercialFeatures</code> option,
which is needed (with legal implications) to use the <code>AppCDS</code> feature in
Oracle Java. The same feature appears in OpenJDK as of Java 10, without the
need for that option or a commercial license.</em></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:off\\\ -XX:DumpLoadedClassList=/var/tmp/nohome/pljava.classlist\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:dump\\\ -XX:SharedClassListFile=/var/tmp/nohome/pljava.classlist\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS\\\ -XX:SharedArchiveFile=/var/tmp/nohome/pljava.jsa -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'""><pre class="notranslate"><code>\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:off\\\ -XX:DumpLoadedClassList=/var/tmp/nohome/pljava.classlist\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
\c "dbname=postgres options='-c pljava.libjvm_location=/var/tmp/nohome/jre/lib/amd64/server/libjvm.so -c pljava.vmoptions=-Djava.home=/var/tmp/nohome/jre\\\ -XX:+UseSerialGC\\\ -XX:+DisableAttachMechanism\\\ -Xshare:dump\\\ -XX:SharedClassListFile=/var/tmp/nohome/pljava.classlist\\\ -XX:+UnlockCommercialFeatures\\\ -XX:+UseAppCDS\\\ -XX:SharedArchiveFile=/var/tmp/nohome/pljava.jsa -c pljava.classpath=/var/tmp/nohome/pg11/share/postgresql/pljava/pljava-1.5.1-SNAPSHOT.jar:/var/tmp/nohome/jre/lib/Saxon-HE-9.8.0-14.jar'"
</code></pre></div>
<div class="markdown-heading"><h4 class="heading-element">"De-signing" the Saxon jar</h4><a id="user-content-de-signing-the-saxon-jar" class="anchor" aria-label="Permalink: "De-signing" the Saxon jar" href="#de-signing-the-saxon-jar"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Hotspot's <code>AppCDS</code> will not share classes from a signed jar, so the signatures
were removed from the Saxon jar with this procedure:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="zip -d Saxon-HE-9.8.0-14.jar META-INF/TE-050AC.SF
unzip Saxon-HE-9.8.0-14.jar META-INF/MANIFEST.MF
ed META-INF/MANIFEST.MF <<END-COMMANDS
/^[[:space:]]/+1,$d
wq
END-COMMANDS
zip -u Saxon-HE-9.8.0-14.jar META-INF/MANIFEST.MF"><pre>zip -d Saxon-HE-9.8.0-14.jar META-INF/TE-050AC.SF
unzip Saxon-HE-9.8.0-14.jar META-INF/MANIFEST.MF
ed META-INF/MANIFEST.MF <span class="pl-s"><span class="pl-k"><<</span><span class="pl-k">END-COMMANDS</span></span>
<span class="pl-s">/^[[:space:]]/+1,<span class="pl-smi">$d</span></span>
<span class="pl-s">wq</span>
<span class="pl-s"><span class="pl-k">END-COMMANDS</span></span>
zip -u Saxon-HE-9.8.0-14.jar META-INF/MANIFEST.MF</pre></div>
<p>Stripping the signatures does not impair the operation of the open-source
Saxon-HE. It is conceivable that the commercial Saxon-PE or Saxon-EE would
object to such treatment.</p>
<div class="markdown-heading"><h4 class="heading-element">Setup for processor-count variation</h4><a id="user-content-setup-for-processor-count-variation" class="anchor" aria-label="Permalink: Setup for processor-count variation" href="#setup-for-processor-count-variation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Several Linux control groups were created as follows:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="mkdir /sys/fs/cgroup/cpuset/{1c1t,1c2t,2c2t,2c4t,4c4t,4c8t}
for i in /sys/fs/cgroup/cpuset/?c?t
do
echo 0 >$i/cpuset.mems
done
echo 0 >/sys/fs/cgroup/cpuset/1c1t/cpuset.cpus
echo 0,1 >/sys/fs/cgroup/cpuset/1c2t/cpuset.cpus
echo 0,2 >/sys/fs/cgroup/cpuset/2c2t/cpuset.cpus
echo 0-3 >/sys/fs/cgroup/cpuset/2c4t/cpuset.cpus
echo 0,2,4,6 >/sys/fs/cgroup/cpuset/4c4t/cpuset.cpus
echo 0-7 >/sys/fs/cgroup/cpuset/4c8t/cpuset.cpus"><pre>mkdir /sys/fs/cgroup/cpuset/{1c1t,1c2t,2c2t,2c4t,4c4t,4c8t}
<span class="pl-k">for</span> <span class="pl-smi">i</span> <span class="pl-k">in</span> /sys/fs/cgroup/cpuset/<span class="pl-k">?</span>c<span class="pl-k">?</span>t
<span class="pl-k">do</span>
<span class="pl-c1">echo</span> 0 <span class="pl-k">></span><span class="pl-smi">$i</span>/cpuset.mems
<span class="pl-k">done</span>
<span class="pl-c1">echo</span> 0 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/1c1t/cpuset.cpus
<span class="pl-c1">echo</span> 0,1 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/1c2t/cpuset.cpus
<span class="pl-c1">echo</span> 0,2 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/2c2t/cpuset.cpus
<span class="pl-c1">echo</span> 0-3 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/2c4t/cpuset.cpus
<span class="pl-c1">echo</span> 0,2,4,6 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/4c4t/cpuset.cpus
<span class="pl-c1">echo</span> 0-7 <span class="pl-k">></span>/sys/fs/cgroup/cpuset/4c8t/cpuset.cpus</pre></div>
<p>After each new backend was established with the appropriate <code>\c</code> line,
its process ID was obtained with <code>SELECT pg_backend_pid();</code> and echoed
into <code>cgroup.procs</code> in the appropriate <code>cpuset</code> subdirectory.</p>
<p>The OpenJ9 class share was initially populated with one set of 16 runs
before any timing was done. Timings were then done in the order shown, from
<code>4c8t</code> to <code>1c1t</code>, and the <code>-Xshareclasses</code> option did not have <code>readonly</code>
added for the timed sets. Because OpenJ9 can continue adding JIT hints to
a class share during operation, it is possible that the later sets benefit
from JIT hints added during the earlier ones.</p>
https://github.com/tada/pljava/wiki/Mapping-an-sql-type-to-a-java-class/97420ffeb82f42147069fc5d074a3b542f16ccdd2017-07-15T19:24:21-04:002017-07-15T19:24:21-04:00Mapping an sql type to a java classjcflack
<div class="markdown-heading"><h1 class="heading-element">Mapping an SQL type to a Java class</h1><a id="user-content-mapping-an-sql-type-to-a-java-class" class="anchor" aria-label="Permalink: Mapping an SQL type to a Java class" href="#mapping-an-sql-type-to-a-java-class"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Using PL/Java, you can install a mapping between an arbitrary type and a Java
class. There are two prerequisites for doing this:</p>
<ul>
<li>You must know the storage layout of the SQL type that you are mapping.</li>
<li>The Java class that you map to must implement the interface
<code>java.sql.SQLData</code>.</li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Mapping an existing SQL data type to a java class</h2><a id="user-content-mapping-an-existing-sql-data-type-to-a-java-class" class="anchor" aria-label="Permalink: Mapping an existing SQL data type to a java class" href="#mapping-an-existing-sql-data-type-to-a-java-class"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Here is an example of how to map the PostgreSQL geometric point type to a Java
class. We know that the point is stored as two float8's, the x and the y
coordinate.</p>
<p>You can consult the postgresql source code when the exact layout of a basic
type is unknown. I peeked at the <code>point_recv</code> function in file
<code>src/backend/utils/adt/geo_ops.c</code> to determine the exact layout of the
point type.</p>
<p>Once the layout is known, you can create the <code>java.sql.SQLData</code> implementation
that uses the class <code>java.sql.SQLInput</code> to read and the class
<code>java.sql.SQLOutput</code> to write data:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="package org.postgresql.pljava.example;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
public class Point implements SQLData {
private double m_x;
private double m_y;
private String m_typeName;
public String getSQLTypeName() {
return m_typeName;
}
public void readSQL(SQLInput stream, String typeName) throws SQLException {
m_x = stream.readDouble();
m_y = stream.readDouble();
m_typeName = typeName;
}
public void writeSQL(SQLOutput stream) throws SQLException {
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
/* Meaningful code that actually does something with this type was
* intentionally left out.
*/
}"><pre><span class="pl-k">package</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">example</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLData</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLException</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLInput</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLOutput</span>;
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Point</span> <span class="pl-k">implements</span> <span class="pl-smi">SQLData</span> {
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_x</span>;
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_y</span>;
<span class="pl-k">private</span> <span class="pl-smi">String</span> <span class="pl-s1">m_typeName</span>;
<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">getSQLTypeName</span>() {
<span class="pl-k">return</span> <span class="pl-s1">m_typeName</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">readSQL</span>(<span class="pl-smi">SQLInput</span> <span class="pl-s1">stream</span>, <span class="pl-smi">String</span> <span class="pl-s1">typeName</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span> {
<span class="pl-s1">m_x</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
<span class="pl-s1">m_y</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
<span class="pl-s1">m_typeName</span> = <span class="pl-s1">typeName</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">writeSQL</span>(<span class="pl-smi">SQLOutput</span> <span class="pl-s1">stream</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span> {
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_x</span>);
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_y</span>);
}
<span class="pl-c">/* Meaningful code that actually does something with this type was</span>
<span class="pl-c"> * intentionally left out.</span>
<span class="pl-c"> */</span>
}</pre></div>
<p>Finally, you install the type mapping using the <code>add_type_mapping</code> command:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT sqlj.add_type_mapping('point', 'org.postgresql.pljava.example.Point');"><pre><span class="pl-k">SELECT</span> <span class="pl-c1">sqlj</span>.<span class="pl-c1">add_type_mapping</span>(<span class="pl-s"><span class="pl-pds">'</span>point<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>org.postgresql.pljava.example.Point<span class="pl-pds">'</span></span>);</pre></div>
<p>You should now be able to use your new class. PL/Java will henceforth map any
point parameter to the org.postgresql.pljava.example.Point class.</p>
<div class="markdown-heading"><h2 class="heading-element">Creating a composite UDT and mapping it to a java class</h2><a id="user-content-creating-a-composite-udt-and-mapping-it-to-a-java-class" class="anchor" aria-label="Permalink: Creating a composite UDT and mapping it to a java class" href="#creating-a-composite-udt-and-mapping-it-to-a-java-class"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Here is an example of a complex type created as a composite UDT.</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE TYPE javatest.complextuple AS (x float8, y float8);
SELECT sqlj.add_type_mapping('javatest.complextuple',
'org.postgresql.pljava.example.ComplexTuple');"><pre><span class="pl-k">CREATE</span> <span class="pl-k">TYPE</span> <span class="pl-en">javatest</span>.complextuple <span class="pl-k">AS</span> (x float8, y float8);
<span class="pl-k">SELECT</span> <span class="pl-c1">sqlj</span>.<span class="pl-c1">add_type_mapping</span>(<span class="pl-s"><span class="pl-pds">'</span>javatest.complextuple<span class="pl-pds">'</span></span>,
<span class="pl-s"><span class="pl-pds">'</span>org.postgresql.pljava.example.ComplexTuple<span class="pl-pds">'</span></span>);</pre></div>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="package org.postgresql.pljava.example;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
public class ComplexTuple implements SQLData {
private double m_x;
private double m_y;
private String m_typeName;
public String getSQLTypeName()
{
return m_typeName;
}
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
m_typeName = typeName;
m_x = stream.readDouble();
m_y = stream.readDouble();
}
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
/* Meaningful code that actually does something with this type was
* intentionally left out.
*/
}"><pre><span class="pl-k">package</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">example</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLData</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLException</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLInput</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLOutput</span>;
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">ComplexTuple</span> <span class="pl-k">implements</span> <span class="pl-smi">SQLData</span> {
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_x</span>;
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_y</span>;
<span class="pl-k">private</span> <span class="pl-smi">String</span> <span class="pl-s1">m_typeName</span>;
<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">getSQLTypeName</span>()
{
<span class="pl-k">return</span> <span class="pl-s1">m_typeName</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">readSQL</span>(<span class="pl-smi">SQLInput</span> <span class="pl-s1">stream</span>, <span class="pl-smi">String</span> <span class="pl-s1">typeName</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">m_typeName</span> = <span class="pl-s1">typeName</span>;
<span class="pl-s1">m_x</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
<span class="pl-s1">m_y</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">writeSQL</span>(<span class="pl-smi">SQLOutput</span> <span class="pl-s1">stream</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_x</span>);
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_y</span>);
}
<span class="pl-c">/* Meaningful code that actually does something with this type was</span>
<span class="pl-c"> * intentionally left out.</span>
<span class="pl-c"> */</span>
}</pre></div>
<div class="markdown-heading"><h2 class="heading-element">Generating SQL automatically</h2><a id="user-content-generating-sql-automatically" class="anchor" aria-label="Permalink: Generating SQL automatically" href="#generating-sql-automatically"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The SQL shown above for this example will be written for you by the Java
compiler, if the <code>ComplexTuple</code> class is simply annotated as a "mapped
user-defined type" with the desired SQL name and structure:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="@MappedUDT(schema="javatest", name="complextuple",
structure={"x float8", "y float8"})
public class ComplexTuple implements SQLData {
..."><pre><span class="pl-c1">@</span><span class="pl-c1">MappedUDT</span>(<span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">name</span>=<span class="pl-s">"complextuple"</span>,
<span class="pl-s1">structure</span>={<span class="pl-s">"x float8"</span>, <span class="pl-s">"y float8"</span>})
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-s1">ComplexTuple</span> <span class="pl-k">implements</span> <span class="pl-smi">SQLData</span> {
...</pre></div>
<p>Generating the SQL reduces the burden of keeping the definitions in sync
in two places. See the <a href="https://tada.github.io/pljava/use/hello.html" rel="nofollow">hello world example</a> for more.</p>
https://github.com/tada/pljava/wiki/Packaging-tips/d7f1e3e92a11385dda2a89d77901d81a87e0315b2017-06-20T20:42:57-04:002017-06-20T20:42:57-04:00Packaging tipsjcflack
<div class="markdown-heading"><h1 class="heading-element">Packaging tips</h1><a id="user-content-packaging-tips" class="anchor" aria-label="Permalink: Packaging tips" href="#packaging-tips"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>This wiki page can be used to gather issues and tips that pertain to
building PL/Java packages for downstream distributions or repositories,
in between updates to the <a href="http://tada.github.io/pljava/build/package.html" rel="nofollow">packaging section</a> in the versioned
documentation.</p>
<p>Anyone producing a prebuilt PL/Java package is encouraged to announce
its availability on the <a class="internal present" href="/tada/pljava/wiki/Prebuilt-packages">Prebuilt packages</a> wiki page.</p>
https://github.com/tada/pljava/wiki/SQL-functions/e7790d89d177d72b84ff98f5e159d883d7d7cabd2017-06-20T01:15:33-04:002017-06-20T01:15:33-04:00SQL functionsjcflack
<div class="markdown-heading"><h1 class="heading-element">Functions in the sqlj schema</h1><a id="user-content-functions-in-the-sqlj-schema" class="anchor" aria-label="Permalink: Functions in the sqlj schema" href="#functions-in-the-sqlj-schema"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><a id="user-content-install_jar"></a></p>
<div class="markdown-heading"><h2 class="heading-element">install_jar</h2><a id="user-content-install_jar" class="anchor" aria-label="Permalink: install_jar" href="#install_jar"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>install_jar</code> command loads a jarfile from a location appointed by an URL
into the SQLJ jar repository. It is an error if a jar with the given name
already exists in the repository.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage" class="anchor" aria-label="Permalink: Usage" href="#usage"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.install_jar(<jar_url>, <jar_name>, <deploy>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>jar_url</td>
<td>
The URL that denotes the location of the jar that should be loaded
</td>
</tr>
<tr>
<td>jar_name</td>
<td>
This is the name by which this jar can be referenced once it has been loaded
</td>
</tr>
<tr>
<td>deploy</td>
<td>
True if the jar should be deployed according to a deployment descriptor, false
otherwise</td>
</tr>
</tbody></table>
<p><a id="user-content-replace_jar"></a></p>
<div class="markdown-heading"><h2 class="heading-element">replace_jar</h2><a id="user-content-replace_jar" class="anchor" aria-label="Permalink: replace_jar" href="#replace_jar"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>replace_jar</code> command will replace a loaded jar with another jar.
Use it to update already loaded files. It's an error if the jar is not found.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-1" class="anchor" aria-label="Permalink: Usage" href="#usage-1"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.replace_jar(<jar_url>, <jar_name>, <redeploy>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>jar_url</td>
<td>
The URL that denotes the location of the jar that should be loaded.
</td>
</tr>
<tr>
<td>jar_name</td>
<td>The name of the jar to be replaced.
</td>
</tr>
<tr>
<td>redeploy</td>
<td>
True if the jar should be undeployed according to the deployment descriptor of
the old jar and deployed according to the deployment descriptor of the new jar,
false otherwise. </td>
</tr>
</tbody></table>
<p><a id="user-content-remove_jar"></a></p>
<div class="markdown-heading"><h2 class="heading-element">remove_jar</h2><a id="user-content-remove_jar" class="anchor" aria-label="Permalink: remove_jar" href="#remove_jar"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>remove_jar</code> command will drop the jar from the jar repository.
Any classpath that references this jar will be updated accordingly. It's an
error if the jar is not found.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-2" class="anchor" aria-label="Permalink: Usage" href="#usage-2"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.remove_jar(<jar_name>, <undeploy>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>jar_name</td>
<td>The name of the jar to be removed.
</td>
</tr>
<tr>
<td>undeploy</td>
<td>
True if the jar should be undeployed according to a deployment descriptor,
false otherwise. </td>
</tr>
</tbody></table>
<p><a id="user-content-get_classpath"></a></p>
<div class="markdown-heading"><h2 class="heading-element">get_classpath</h2><a id="user-content-get_classpath" class="anchor" aria-label="Permalink: get_classpath" href="#get_classpath"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>get_classpath</code> command will return the classpath that has been defined for
the given schema. NULL is returned if the schema has no classpath. It's an
error if the given schema does not exist.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-3" class="anchor" aria-label="Permalink: Usage" href="#usage-3"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.get_classpath(<schema>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>schema</td>
<td>The name of the schema</td>
</tr>
</tbody></table>
<p><a id="user-content-set_classpath"></a></p>
<div class="markdown-heading"><h2 class="heading-element">set_classpath</h2><a id="user-content-set_classpath" class="anchor" aria-label="Permalink: set_classpath" href="#set_classpath"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>set_classpath</code> command will define a classpath for the given schema. A
classpath consists of a colon separated list of jar names. It's an error if the
given schema does not exist or if one or more jar names references nonexistent
jars.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-4" class="anchor" aria-label="Permalink: Usage" href="#usage-4"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.set_classpath(<schema>, <classpath>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>schema</td>
<td>The name of the schema.
</td>
</tr>
<tr>
<td>classpath</td>
<td>The colon separated list of jar names.</td>
</tr>
</tbody></table>
<p><a id="user-content-add_type_mapping"></a></p>
<div class="markdown-heading"><h2 class="heading-element">add_type_mapping</h2><a id="user-content-add_type_mapping" class="anchor" aria-label="Permalink: add_type_mapping" href="#add_type_mapping"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>add_type_mapping</code> command installs a mapping between a SQL type and a Java
class. Once the mapping is in place, parameters and return values will be
mapped accordingly. Please read <a class="internal present" href="/tada/pljava/wiki/Mapping-an-sql-type-to-a-java-class">Mapping an SQL type to a Java class</a> for
detailed information.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-5" class="anchor" aria-label="Permalink: Usage" href="#usage-5"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.add_type_mapping(<sql type>, <java class>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>sql type</td>
<td>The name of the SQL type. The name can be qualified with a schema (namespace). If the schema is omitted, it will be resolved according to the current setting of the search_path.
</td>
</tr>
<tr>
<td>java class</td>
<td>The name of the class. The class must be found in the classpath in effect for the current schema </td>
</tr>
</tbody></table>
<p><a id="user-content-drop_type_mapping"></a></p>
<div class="markdown-heading"><h2 class="heading-element">drop_type_mapping</h2><a id="user-content-drop_type_mapping" class="anchor" aria-label="Permalink: drop_type_mapping" href="#drop_type_mapping"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>drop_type_mapping</code> command removes a mapping between a SQL type and a Java
class.</p>
<div class="markdown-heading"><h4 class="heading-element">Usage</h4><a id="user-content-usage-6" class="anchor" aria-label="Permalink: Usage" href="#usage-6"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><code>SELECT sqlj.drop_type_mapping(<sql type>);</code></p>
<table role="table">
<tbody><tr>
<th>Parameter</th>
<th>Description</th>
</tr>
<tr>
<td>sql type</td>
<td>The name of the SQL type. The name can be qualified with a schema (namespace). If the schema is omitted, it will be resolved according to the current setting of the search_path.</td>
</tr>
</tbody></table>
<p><a id="user-content-jar_urls"></a></p>
<div class="markdown-heading"><h2 class="heading-element">Note on jar URLs</h2><a id="user-content-note-on-jar-urls" class="anchor" aria-label="Permalink: Note on jar URLs" href="#note-on-jar-urls"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The <code>install_jar</code> and <code>replace_jar</code> commands accept a URL (that must be
reachable from the server) to a jar file. It is even possible, using the
rules for jar URLs, to construct one that refers to a jar file within
another jar file. For example:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="jar:file:outer.jar!/inner.jar"><pre class="notranslate"><code>jar:file:outer.jar!/inner.jar
</code></pre></div>
<p>However, Java's caching of the "outer" jar may frustrate attempts to replace
or reload a newer version within the same session.</p>
https://github.com/tada/pljava/wiki/Logging/4e62c4b3f146ab7de5683fc0f1229e0765b57e652017-06-19T21:53:51-04:002017-06-19T21:53:51-04:00Loggingjcflack
<div class="markdown-heading"><h1 class="heading-element">Logging in PL/Java</h1><a id="user-content-logging-in-pljava" class="anchor" aria-label="Permalink: Logging in PL/Java" href="#logging-in-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java uses the standard java.util.logging.Logger Hence, you can write things
like:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Logger.getAnonymousLogger().info(
"Time is " + new Date(System.currentTimeMillis()));"><pre><span class="pl-smi">Logger</span>.<span class="pl-en">getAnonymousLogger</span>().<span class="pl-en">info</span>(
<span class="pl-s">"Time is "</span> + <span class="pl-k">new</span> <span class="pl-smi">Date</span>(<span class="pl-smi">System</span>.<span class="pl-en">currentTimeMillis</span>()));</pre></div>
<p>At present, the logger is hardwired to a handler that maps the state of
the PostgreSQL configuration setting <code>log_min_messages</code> to a valid Logger level
and that outputs all messages using the backend function <code>ereport()</code>.</p>
<p>Importantly, Java's Logger methods can quickly discard any message logged at a
finer level than the one that was mapped from PostgreSQL's setting <em>at the time
PL/Java was first used in the current session</em>. Such messages never even get
as far as <code>ereport()</code>, even if the PostgreSQL setting is changed later.</p>
<p>So, if expected messages from Java code are not showing up, be sure that the
setting in PostgreSQL, at the time of PL/Java's first use in the session, is
fine enough that Java will not throw the messages away. Once PL/Java has
started, the settings can be changed as desired and will control, in the
usual way, what <code>ereport</code> does with the messages PL/Java delivers to it.</p>
<p>Through PL/Java 1.5.0, only the <code>log_min_messages</code> setting is used to set
that Java cutoff level. Starting with 1.5.1, the cutoff level in Java is set
(still only once at PL/Java startup) based on the finer of <code>log_min_messages</code>
and <code>client_min_messages</code>.</p>
<p>The following mapping applies between the Logger levels and the PostgreSQL
backend levels:</p>
<table role="table">
<tbody><tr>
<th>java.util.logging.Level</th>
<th>PostgreSQL level</th>
</tr>
<tr>
<td>SEVERE</td>
<td>ERROR</td>
</tr>
<tr>
<td>WARNING</td>
<td>WARNING</td>
</tr>
<tr>
<td>INFO</td>
<td>INFO</td>
</tr>
<tr>
<td>FINE</td>
<td>DEBUG1</td>
</tr>
<tr>
<td>FINER</td>
<td>DEBUG2</td>
</tr>
<tr>
<td>FINEST</td>
<td>DEBUG3</td>
</tr>
</tbody></table>
<p>See <a class="internal present" href="/tada/pljava/wiki/Thoughts-on-logging">Thoughts on logging</a> for likely future directions in this area.</p>
https://github.com/tada/pljava/wiki/Functions-returning-sets/f156fa50ab0c5dee749a647ce36ab120ce081a1e2017-04-19T22:30:04-04:002017-04-19T22:30:04-04:00Functions returning setsjcflack
<div class="markdown-heading"><h1 class="heading-element">Set-returning functions</h1><a id="user-content-set-returning-functions" class="anchor" aria-label="Permalink: Set-returning functions" href="#set-returning-functions"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Returning sets is tricky. You don't want to first build a set and then return
it, since large sets would eat excessive resources. It's better to produce
one row at a time. Incidentally, that's exactly what the PostgreSQL backend
expects a function that <code>RETURNS SETOF <type></code> to do. The <code><type></code> can be a
<em>scalar type</em> such as an <em>int</em>, <em>float</em> or <em>varchar</em>, it can be a
<em>complex type</em>, or a <em>RECORD</em>.</p>
<div class="markdown-heading"><h3 class="heading-element">Returning a SETOF <scalar type></h3><a id="user-content-returning-a-setof-scalar-type" class="anchor" aria-label="Permalink: Returning a SETOF <scalar type>" href="#returning-a-setof-scalar-type"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In order to return a set of a scalar type, you need create a Java method that
returns an implementation the <code>java.util.Iterator</code> interface.</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION javatest.getNames()
RETURNS SETOF varchar
AS 'foo.fee.Bar.getNames'
IMMUTABLE LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">javatest</span>.getNames()
RETURNS SETOF <span class="pl-k">varchar</span>
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>foo.fee.Bar.getNames<span class="pl-pds">'</span></span>
IMMUTABLE LANGUAGE java;</pre></div>
<p>The corresponding Java class:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="package foo.fee;
import java.util.Iterator;
import org.postgresql.pljava.annotation.Function;
import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
public class Bar
{
@Function(schema="javatest", effects=IMMUTABLE)
public static Iterator<String> getNames()
{
ArrayList<String> names = new ArrayList<>();
names.add("Lisa");
names.add("Bob");
names.add("Bill");
names.add("Sally");
return names.iterator();
}
}"><pre><span class="pl-k">package</span> <span class="pl-s1">foo</span>.<span class="pl-s1">fee</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">util</span>.<span class="pl-s1">Iterator</span>;
<span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">Function</span>;
<span class="pl-k">import</span> <span class="pl-k">static</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">Function</span>.<span class="pl-s1">Effects</span>.<span class="pl-c1">IMMUTABLE</span>;
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Bar</span>
{
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>)
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">Iterator</span><<span class="pl-smi">String</span>> <span class="pl-en">getNames</span>()
{
<span class="pl-smi">ArrayList</span><<span class="pl-smi">String</span>> <span class="pl-s1">names</span> = <span class="pl-k">new</span> <span class="pl-smi">ArrayList</span><>();
<span class="pl-s1">names</span>.<span class="pl-en">add</span>(<span class="pl-s">"Lisa"</span>);
<span class="pl-s1">names</span>.<span class="pl-en">add</span>(<span class="pl-s">"Bob"</span>);
<span class="pl-s1">names</span>.<span class="pl-en">add</span>(<span class="pl-s">"Bill"</span>);
<span class="pl-s1">names</span>.<span class="pl-en">add</span>(<span class="pl-s">"Sally"</span>);
<span class="pl-k">return</span> <span class="pl-s1">names</span>.<span class="pl-en">iterator</span>();
}
}</pre></div>
<div class="markdown-heading"><h3 class="heading-element">Returning a SETOF <complex type></h3><a id="user-content-returning-a-setof-complex-type" class="anchor" aria-label="Permalink: Returning a SETOF <complex type>" href="#returning-a-setof-complex-type"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A method returning a <code>SETOF <complex type></code> must use either the interface
<code>org.postgresql.pljava.ResultSetProvider</code> or
<code>org.postgresql.pljava.ResultSetHandle</code>. The reason for having two interfaces
is that they cater for optimal handling of two distinct use cases. The former
is great when you want to dynamically create each row that is to be returned
from the <code>SETOF</code> function. The latter makes sense when you want to return the
result of an executed query.</p>
<div class="markdown-heading"><h3 class="heading-element">Using the ResultSetProvider interface</h3><a id="user-content-using-the-resultsetprovider-interface" class="anchor" aria-label="Permalink: Using the ResultSetProvider interface" href="#using-the-resultsetprovider-interface"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>This interface has two methods. The
<code>boolean assignRowValues(java.sql.ResultSet tupleBuilder, int rowNumber)</code>
and the <code>void close()</code> method. The PostgreSQL query evaluator will call the
<code>assignRowValues()</code> repeatedly until it returns false or until the evaluator
decides that it does not need any more rows. It will then call <code>close()</code>.</p>
<p>You can use this interface the following way:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION javatest.listComplexTests(int, int)
RETURNS SETOF complexTest
AS 'foo.fee.Fum.listComplexTest'
IMMUTABLE LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">javatest</span>.listComplexTests(<span class="pl-k">int</span>, <span class="pl-k">int</span>)
RETURNS SETOF complexTest
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>foo.fee.Fum.listComplexTest<span class="pl-pds">'</span></span>
IMMUTABLE LANGUAGE java;</pre></div>
<p>The function maps to a static java method that returns an instance that
implements the <code>ResultSetProvider</code> interface.</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="public class Fum implements ResultSetProvider
{
private final int m_base;
private final int m_increment;
public Fum(int base, int increment)
{
m_base = base;
m_increment = increment;
}
public boolean assignRowValues(ResultSet receiver, int currentRow)
throws SQLException
{
// Stop when we reach 12 rows.
//
if(currentRow >= 12)
return false;
receiver.updateInt(1, m_base);
receiver.updateInt(2, m_base + m_increment * currentRow);
receiver.updateTimestamp(3, new Timestamp(System.currentTimeMillis()));
return true;
}
public void close()
{
// Nothing needed in this example
}
@Function(effects=IMMUTABLE, schema="javatest", type="complexTest")
public static ResultSetProvider listComplexTests(int base, int increment)
throws SQLException
{
return new Fum(base, increment);
}
}"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Fum</span> <span class="pl-k">implements</span> <span class="pl-smi">ResultSetProvider</span>
{
<span class="pl-k">private</span> <span class="pl-k">final</span> <span class="pl-smi">int</span> <span class="pl-s1">m_base</span>;
<span class="pl-k">private</span> <span class="pl-k">final</span> <span class="pl-smi">int</span> <span class="pl-s1">m_increment</span>;
<span class="pl-k">public</span> <span class="pl-smi">Fum</span>(<span class="pl-smi">int</span> <span class="pl-s1">base</span>, <span class="pl-smi">int</span> <span class="pl-s1">increment</span>)
{
<span class="pl-s1">m_base</span> = <span class="pl-s1">base</span>;
<span class="pl-s1">m_increment</span> = <span class="pl-s1">increment</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">boolean</span> <span class="pl-en">assignRowValues</span>(<span class="pl-smi">ResultSet</span> <span class="pl-s1">receiver</span>, <span class="pl-smi">int</span> <span class="pl-s1">currentRow</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-c">// Stop when we reach 12 rows.</span>
<span class="pl-c">//</span>
<span class="pl-k">if</span>(<span class="pl-s1">currentRow</span> >= <span class="pl-c1">12</span>)
<span class="pl-k">return</span> <span class="pl-c1">false</span>;
<span class="pl-s1">receiver</span>.<span class="pl-en">updateInt</span>(<span class="pl-c1">1</span>, <span class="pl-s1">m_base</span>);
<span class="pl-s1">receiver</span>.<span class="pl-en">updateInt</span>(<span class="pl-c1">2</span>, <span class="pl-s1">m_base</span> + <span class="pl-s1">m_increment</span> * <span class="pl-s1">currentRow</span>);
<span class="pl-s1">receiver</span>.<span class="pl-en">updateTimestamp</span>(<span class="pl-c1">3</span>, <span class="pl-k">new</span> <span class="pl-smi">Timestamp</span>(<span class="pl-smi">System</span>.<span class="pl-en">currentTimeMillis</span>()));
<span class="pl-k">return</span> <span class="pl-c1">true</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">close</span>()
{
<span class="pl-c">// Nothing needed in this example</span>
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>, <span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">type</span>=<span class="pl-s">"complexTest"</span>)
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">ResultSetProvider</span> <span class="pl-en">listComplexTests</span>(<span class="pl-smi">int</span> <span class="pl-s1">base</span>, <span class="pl-smi">int</span> <span class="pl-s1">increment</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">Fum</span>(<span class="pl-s1">base</span>, <span class="pl-s1">increment</span>);
}
}</pre></div>
<p>The <code>listComplexTests(int base, int increment)</code> method is called once. It may
return <code>null</code> if no results are available, or an instance of the
<code>ResultSetProvider</code>. Here the <code>Fum</code> class implements this interface so it
returns an instance of itself. The method
<code>assignRowValues(ResultSet receiver, int currentRow)</code>
will then be called repeatedly until it returns <code>false</code>. At that
time, <code>close()</code> will be called.</p>
<p>The <code>currentRow</code> parameter can be a convenience in some cases, and
unnecessary in others. It will be passed as zero on the first call,
and incremented by one on each subsequent call. If the <code>ResultSetProvider</code>
is returning results from some source (like an <code>Iterator</code>) that remembers its
own position, it can simply ignore <code>currentRow</code>.</p>
<div class="markdown-heading"><h3 class="heading-element">Using the ResultSetHandle interface</h3><a id="user-content-using-the-resultsethandle-interface" class="anchor" aria-label="Permalink: Using the ResultSetHandle interface" href="#using-the-resultsethandle-interface"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>This interface is similar to the <code>ResultSetProvider</code> interface in that it has a
<code>close()</code> method that will be called at the end. But instead of having
the evaluator call a method that builds one row at a time, this method has a
method that returns a <code>ResultSet</code>. The query evaluator will iterate over
this set and deliver its contents, one tuple at a time, to the caller until a
call to <code>next()</code> returns <code>false</code> or the evaluator decides that no more
rows are needed.</p>
<p>Here is an example that executes a query using a statement that it obtained
using the default connection. The SQL looks like this:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION javatest.listSupers()
RETURNS SETOF pg_user
AS 'org.postgresql.pljava.example.Users.listSupers'
LANGUAGE java;
CREATE FUNCTION javatest.listNonSupers()
RETURNS SETOF pg_user
AS 'org.postgresql.pljava.example.Users.listNonSupers'
LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">javatest</span>.listSupers()
RETURNS SETOF pg_user
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>org.postgresql.pljava.example.Users.listSupers<span class="pl-pds">'</span></span>
LANGUAGE java;
<span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">javatest</span>.listNonSupers()
RETURNS SETOF pg_user
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>org.postgresql.pljava.example.Users.listNonSupers<span class="pl-pds">'</span></span>
LANGUAGE java;</pre></div>
<p>And here is the Java code:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="public class Users implements ResultSetHandle
{
private final String m_filter;
private Statement m_statement;
public Users(String filter)
{
m_filter = filter;
}
public ResultSet getResultSet()
throws SQLException
{
m_statement = DriverManager.getConnection("jdbc:default:connection")
.createStatement();
return m_statement.executeQuery("SELECT * FROM pg_user WHERE " + m_filter);
}
public void close()
throws SQLException
{
m_statement.close();
}
@Function(schema="javatest", type="pg_user")
public static ResultSetHandle listSupers()
{
return new Users("usesuper = true");
}
@Function(schema="javatest", type="pg_user")
public static ResultSetHandle listNonSupers()
{
return new Users("usesuper = false");
}
}"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Users</span> <span class="pl-k">implements</span> <span class="pl-smi">ResultSetHandle</span>
{
<span class="pl-k">private</span> <span class="pl-k">final</span> <span class="pl-smi">String</span> <span class="pl-s1">m_filter</span>;
<span class="pl-k">private</span> <span class="pl-smi">Statement</span> <span class="pl-s1">m_statement</span>;
<span class="pl-k">public</span> <span class="pl-smi">Users</span>(<span class="pl-smi">String</span> <span class="pl-s1">filter</span>)
{
<span class="pl-s1">m_filter</span> = <span class="pl-s1">filter</span>;
}
<span class="pl-k">public</span> <span class="pl-smi">ResultSet</span> <span class="pl-en">getResultSet</span>()
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">m_statement</span> = <span class="pl-smi">DriverManager</span>.<span class="pl-en">getConnection</span>(<span class="pl-s">"jdbc:default:connection"</span>)
.<span class="pl-en">createStatement</span>();
<span class="pl-k">return</span> <span class="pl-s1">m_statement</span>.<span class="pl-en">executeQuery</span>(<span class="pl-s">"SELECT * FROM pg_user WHERE "</span> + <span class="pl-s1">m_filter</span>);
}
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">close</span>()
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">m_statement</span>.<span class="pl-en">close</span>();
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">type</span>=<span class="pl-s">"pg_user"</span>)
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">ResultSetHandle</span> <span class="pl-en">listSupers</span>()
{
<span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">Users</span>(<span class="pl-s">"usesuper = true"</span>);
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">type</span>=<span class="pl-s">"pg_user"</span>)
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">ResultSetHandle</span> <span class="pl-en">listNonSupers</span>()
{
<span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">Users</span>(<span class="pl-s">"usesuper = false"</span>);
}
}</pre></div>
https://github.com/tada/pljava/wiki/Parallel-query-and-PLJava/74ececf28f0b7f08ddd1598b09a75ad75f04414b2016-10-30T18:15:44-04:002016-10-30T18:15:44-04:00Parallel query and PLJavajcflack
<div class="markdown-heading"><h1 class="heading-element">Parallel query and PL/Java</h1><a id="user-content-parallel-query-and-pljava" class="anchor" aria-label="Permalink: Parallel query and PL/Java" href="#parallel-query-and-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java 1.5.1 adds support for PostgreSQL 9.6, and with that comes the
possibility of using PL/Java functions in parallel queries. Simple testing shows
that this actually works; PL/Java functions can even be declared <code>PARALLEL SAFE</code>
if they meet the requirements, and executed in the parallelized parts of
queries.</p>
<p>However, this is a substantial change to conditions in which PL/Java was
developed, so this wiki page is here to collect the notes that are likely to
come with experience using this new capability. Such experience might include
empirically-determined, good values for <code>parallel_setup_cost</code>, nonobvious cases
where a function should not be declared <code>RESTRICTED</code> or <code>SAFE</code>, and so on.</p>
<hr>
<div class="markdown-heading"><h2 class="heading-element">Notes go here</h2><a id="user-content-notes-go-here" class="anchor" aria-label="Permalink: Notes go here" href="#notes-go-here"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<hr>
<div class="markdown-heading"><h2 class="heading-element">Preview of new documentation</h2><a id="user-content-preview-of-new-documentation" class="anchor" aria-label="Permalink: Preview of new documentation" href="#preview-of-new-documentation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Until PL/Java 1.5.1 is released, here is a preview of the new section of
the user's guide.</p>
<div class="markdown-heading"><h1 class="heading-element">PL/Java in parallel query or background worker</h1><a id="user-content-pljava-in-parallel-query-or-background-worker" class="anchor" aria-label="Permalink: PL/Java in parallel query or background worker" href="#pljava-in-parallel-query-or-background-worker"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>With some restrictions, PL/Java can be used in <a href="https://www.postgresql.org/docs/current/static/parallel-query.html" rel="nofollow">parallel queries</a>, from
PostgreSQL 9.6, and in some <a href="https://www.postgresql.org/docs/current/static/bgworker.html" rel="nofollow">background worker processes</a> (as
introduced in PostgreSQL 9.3, though 9.5 or later is needed for support
in PL/Java).</p>
<div class="markdown-heading"><h2 class="heading-element">Background worker processes</h2><a id="user-content-background-worker-processes" class="anchor" aria-label="Permalink: Background worker processes" href="#background-worker-processes"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Because PL/Java requires access to a database containing the <code>sqlj</code> schema,
PL/Java is only usable in a worker process that initializes a database
connection, which must happen before the first use of any function that
depends on PL/Java.</p>
<div class="markdown-heading"><h2 class="heading-element">Parallel queries</h2><a id="user-content-parallel-queries" class="anchor" aria-label="Permalink: Parallel queries" href="#parallel-queries"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Like any user-defined function, a PL/Java function can be
<a href="http://tada.github.io/pljava/pljava-api/apidocs/index.html?org/postgresql/pljava/annotation/Function.html#parallel()" rel="nofollow">annotated</a> with a level of "parallel safety", <code>UNSAFE</code> by default.</p>
<p>When a function labeled <code>UNSAFE</code> is used in a query, the query cannot be
parallelized at all. If a query contains a function labeled <code>RESTRICTED</code>, parts
of the query may execute in parallel, but the part that calls the <code>RESTRICTED</code>
function will be executed only in the lead process. A function labeled <code>SAFE</code>
may be executed in every process participating in the query.</p>
<div class="markdown-heading"><h3 class="heading-element">Parallel setup cost</h3><a id="user-content-parallel-setup-cost" class="anchor" aria-label="Permalink: Parallel setup cost" href="#parallel-setup-cost"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PostgreSQL parallel query processing uses multiple operating-system processes,
and these processes are new for each parallel query. If a PL/Java function is
labeled <code>PARALLEL SAFE</code> and is pushed by the query planner to run in the
parallel worker processes, each new process will start a Java virtual machine.
The cost of doing so will reduce the expected advantage of parallel execution.</p>
<p>To inform the query planner of this trade-off, the value of the PostgreSQL
configuration variable <a href="https://www.postgresql.org/docs/current/static/runtime-config-query.html#GUC-PARALLEL-SETUP-COST" rel="nofollow"><code>parallel_setup_cost</code></a> should be increased.
The startup cost can be minimized with attention to the
<a href="http://tada.github.io/pljava/install/vmoptions.html" rel="nofollow">PL/Java VM option recommendations</a>, including class data sharing.</p>
<div class="markdown-heading"><h3 class="heading-element">Limits on <code>RESTRICTED</code>/<code>SAFE</code> function behavior</h3><a id="user-content-limits-on-restrictedsafe-function-behavior" class="anchor" aria-label="Permalink: Limits on RESTRICTED/SAFE function behavior" href="#limits-on-restrictedsafe-function-behavior"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>There are stringent limits on what a function labeled <code>RESTRICTED</code> may do,
and even more stringent limits on what may be done in a function labeled <code>SAFE</code>.
The PostgreSQL manual describes the limits in the section
<a href="https://www.postgresql.org/docs/current/static/parallel-safety.html#PARALLEL-LABELING" rel="nofollow">Parallel Labeling for Functions and Aggregates</a>.</p>
<p>While PostgreSQL does check for some inappropriate operations from a
<code>PARALLEL SAFE</code> or <code>RESTRICTED</code> function, for the most part it relies on
functions being labeled correctly. When in doubt, the conservative approach
is to label a function <code>UNSAFE</code>, which can't go wrong. A function mistakenly
labeled <code>RESTRICTED</code> or <code>SAFE</code> could produce unpredictable results.</p>
<div class="markdown-heading"><h4 class="heading-element">Internal workings of PL/Java</h4><a id="user-content-internal-workings-of-pljava" class="anchor" aria-label="Permalink: Internal workings of PL/Java" href="#internal-workings-of-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>While a given PL/Java function itself may clearly qualify as <code>RESTRICTED</code> or
<code>SAFE</code> by inspection, there may still be cases where a forbidden operation
results from the internal workings of PL/Java itself. This has not been seen
in testing (simple parallel queries with <code>RESTRICTED</code> or <code>SAFE</code> PL/Java
functions work fine), but to rule out the possibility would require a careful
audit of PL/Java's code. Until then, it would be prudent for any application
involving parallel query with <code>RESTRICTED</code> or <code>SAFE</code> PL/Java functions
to be first tested in a non-production environment.</p>
<div class="markdown-heading"><h3 class="heading-element">Further reading</h3><a id="user-content-further-reading" class="anchor" aria-label="Permalink: Further reading" href="#further-reading"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p><a href="https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/backend/access/transam/README.parallel" rel="nofollow">README.parallel</a> in the PostgreSQL source, for more detail on why parallel
query works the way it does.</p>
https://github.com/tada/pljava/wiki/Creating-a-scalar-udt-in-java/17f03a14ae689539a5893b31617bc11b328418832016-01-29T22:41:22-05:002016-01-29T22:41:22-05:00Creating a scalar udt in javajcflack
<div class="markdown-heading"><h1 class="heading-element">Creating a scalar (or, base) user-defined type</h1><a id="user-content-creating-a-scalar-or-base-user-defined-type" class="anchor" aria-label="Permalink: Creating a scalar (or, base) user-defined type" href="#creating-a-scalar-or-base-user-defined-type"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>This text assumes that you have some familiarity with how scalar types are
created and added to the PostgreSQL type system. For more info on that topic,
please read <a href="http://www.postgresql.org/docs/8.4/static/xtypes.html" rel="nofollow">this chapter in the PostgreSQL docs</a>.</p>
<p>Creating new scalar type using Java functions is very similar to how they are
created using C functions from an SQL perspective but of course very different
when looking at the actual implementation. Java stipulates that the mapping
between a Java class and a corresponding SQL type should be done using the
interfaces <code>java.sql.SQLData</code>, <code>java.sql.SQLInput</code>, and
<code>java.sql.SQLOutput</code> and that is what PL/Java is using. In addition, the
PostgreSQL type system stipulates that each type must have a textual
representation.</p>
<p>Let us create a type called <code>javatest.complex</code> (similar to the complex
type used in the PostgreSQL documentation). The name of the corresponding
Java class will be <code>org.postgresql.pljava.example.ComplexScalar</code>.</p>
<div class="markdown-heading"><h2 class="heading-element">The Java code for the scalar type</h2><a id="user-content-the-java-code-for-the-scalar-type" class="anchor" aria-label="Permalink: The Java code for the scalar type" href="#the-java-code-for-the-scalar-type"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">Prerequisites for the Java implementation</h3><a id="user-content-prerequisites-for-the-java-implementation" class="anchor" aria-label="Permalink: Prerequisites for the Java implementation" href="#prerequisites-for-the-java-implementation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The java class for a scalar UDT must implement the <code>java.sql.SQLData</code>
interface. In addition, it must also implement a method
<code>static T parse(String stringRepresentation, String typeName)</code> where <code>T</code> will
be the name of the class--that is, <code>parse</code> will create and return an instance
of the class--and the <code>java.lang.String toString()</code> method.
The <code>toString()</code> method must return something
that the <code>parse()</code> method can parse.</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="package org.postgresql.pljava.example;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
import java.util.logging.Logger;
import org.postgresql.pljava.annotation.Function;
import org.postgresql.pljava.annotation.SQLType;
import org.postgresql.pljava.annotation.BaseUDT;
import static org.postgresql.pljava.annotation.Function.Effects.IMMUTABLE;
import static
org.postgresql.pljava.annotation.Function.OnNullInput.RETURNS_NULL;
@BaseUDT(schema="javatest", name="complex",
internalLength=16, alignment=BaseUDT.Alignment.DOUBLE)
public class ComplexScalar implements SQLData
{
private double m_x;
private double m_y;
private String m_typeName;
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
public static ComplexScalar parse(String input, String typeName)
throws SQLException
{
try
{
StreamTokenizer tz = new StreamTokenizer(new StringReader(input));
if(tz.nextToken() == '('
&& tz.nextToken() == StreamTokenizer.TT_NUMBER)
{
double x = tz.nval;
if(tz.nextToken() == ','
&& tz.nextToken() == StreamTokenizer.TT_NUMBER)
{
double y = tz.nval;
if(tz.nextToken() == ')')
{
return new ComplexScalar(x, y, typeName);
}
}
}
throw new SQLException("Unable to parse complex from string \""
+ input + '"');
}
catch(IOException e)
{
throw new SQLException(e.getMessage());
}
}
public ComplexScalar()
{
}
public ComplexScalar(double x, double y, String typeName)
{
m_x = x;
m_y = y;
m_typeName = typeName;
}
@Override
public String getSQLTypeName()
{
return m_typeName;
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public void readSQL(SQLInput stream, String typeName) throws SQLException
{
m_x = stream.readDouble();
m_y = stream.readDouble();
m_typeName = typeName;
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public void writeSQL(SQLOutput stream) throws SQLException
{
stream.writeDouble(m_x);
stream.writeDouble(m_y);
}
@Function(effects=IMMUTABLE, onNullInput=RETURNS_NULL)
@Override
public String toString()
{
s_logger.info(m_typeName + " toString");
StringBuffer sb = new StringBuffer();
sb.append('(');
sb.append(m_x);
sb.append(',');
sb.append(m_y);
sb.append(')');
return sb.toString();
}
/* Meaningful code that actually does something with this type was
* intentionally left out.
*/
}"><pre><span class="pl-k">package</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">example</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">io</span>.<span class="pl-s1">IOException</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">io</span>.<span class="pl-s1">StreamTokenizer</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">io</span>.<span class="pl-s1">StringReader</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLData</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLException</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLInput</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">sql</span>.<span class="pl-s1">SQLOutput</span>;
<span class="pl-k">import</span> <span class="pl-s1">java</span>.<span class="pl-s1">util</span>.<span class="pl-s1">logging</span>.<span class="pl-s1">Logger</span>;
<span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">Function</span>;
<span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">SQLType</span>;
<span class="pl-k">import</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">BaseUDT</span>;
<span class="pl-k">import</span> <span class="pl-k">static</span> <span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">Function</span>.<span class="pl-s1">Effects</span>.<span class="pl-c1">IMMUTABLE</span>;
<span class="pl-k">import</span> <span class="pl-k">static</span>
<span class="pl-s1">org</span>.<span class="pl-s1">postgresql</span>.<span class="pl-s1">pljava</span>.<span class="pl-s1">annotation</span>.<span class="pl-s1">Function</span>.<span class="pl-s1">OnNullInput</span>.<span class="pl-c1">RETURNS_NULL</span>;
<span class="pl-c1">@</span><span class="pl-c1">BaseUDT</span>(<span class="pl-s1">schema</span>=<span class="pl-s">"javatest"</span>, <span class="pl-s1">name</span>=<span class="pl-s">"complex"</span>,
<span class="pl-s1">internalLength</span>=<span class="pl-c1">16</span>, <span class="pl-s1">alignment</span>=<span class="pl-smi">BaseUDT</span>.<span class="pl-s1">Alignment</span>.<span class="pl-c1">DOUBLE</span>)
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">ComplexScalar</span> <span class="pl-k">implements</span> <span class="pl-smi">SQLData</span>
{
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_x</span>;
<span class="pl-k">private</span> <span class="pl-smi">double</span> <span class="pl-s1">m_y</span>;
<span class="pl-k">private</span> <span class="pl-smi">String</span> <span class="pl-s1">m_typeName</span>;
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>, <span class="pl-s1">onNullInput</span>=<span class="pl-c1">RETURNS_NULL</span>)
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">ComplexScalar</span> <span class="pl-en">parse</span>(<span class="pl-smi">String</span> <span class="pl-s1">input</span>, <span class="pl-smi">String</span> <span class="pl-s1">typeName</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-k">try</span>
{
<span class="pl-smi">StreamTokenizer</span> <span class="pl-s1">tz</span> = <span class="pl-k">new</span> <span class="pl-smi">StreamTokenizer</span>(<span class="pl-k">new</span> <span class="pl-smi">StringReader</span>(<span class="pl-s1">input</span>));
<span class="pl-k">if</span>(<span class="pl-s1">tz</span>.<span class="pl-en">nextToken</span>() == <span class="pl-s">'('</span>
&& <span class="pl-s1">tz</span>.<span class="pl-en">nextToken</span>() == <span class="pl-smi">StreamTokenizer</span>.<span class="pl-c1">TT_NUMBER</span>)
{
<span class="pl-smi">double</span> <span class="pl-s1">x</span> = <span class="pl-s1">tz</span>.<span class="pl-s1">nval</span>;
<span class="pl-k">if</span>(<span class="pl-s1">tz</span>.<span class="pl-en">nextToken</span>() == <span class="pl-s">','</span>
&& <span class="pl-s1">tz</span>.<span class="pl-en">nextToken</span>() == <span class="pl-smi">StreamTokenizer</span>.<span class="pl-c1">TT_NUMBER</span>)
{
<span class="pl-smi">double</span> <span class="pl-s1">y</span> = <span class="pl-s1">tz</span>.<span class="pl-s1">nval</span>;
<span class="pl-k">if</span>(<span class="pl-s1">tz</span>.<span class="pl-en">nextToken</span>() == <span class="pl-s">')'</span>)
{
<span class="pl-k">return</span> <span class="pl-k">new</span> <span class="pl-smi">ComplexScalar</span>(<span class="pl-s1">x</span>, <span class="pl-s1">y</span>, <span class="pl-s1">typeName</span>);
}
}
}
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">SQLException</span>(<span class="pl-s">"Unable to parse complex from string <span class="pl-cce">\"</span>"</span>
+ <span class="pl-s1">input</span> + <span class="pl-s">'"'</span>);
}
<span class="pl-k">catch</span>(<span class="pl-smi">IOException</span> <span class="pl-s1">e</span>)
{
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">SQLException</span>(<span class="pl-s1">e</span>.<span class="pl-en">getMessage</span>());
}
}
<span class="pl-k">public</span> <span class="pl-smi">ComplexScalar</span>()
{
}
<span class="pl-k">public</span> <span class="pl-smi">ComplexScalar</span>(<span class="pl-smi">double</span> <span class="pl-s1">x</span>, <span class="pl-smi">double</span> <span class="pl-s1">y</span>, <span class="pl-smi">String</span> <span class="pl-s1">typeName</span>)
{
<span class="pl-s1">m_x</span> = <span class="pl-s1">x</span>;
<span class="pl-s1">m_y</span> = <span class="pl-s1">y</span>;
<span class="pl-s1">m_typeName</span> = <span class="pl-s1">typeName</span>;
}
<span class="pl-c1">@</span><span class="pl-c1">Override</span>
<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">getSQLTypeName</span>()
{
<span class="pl-k">return</span> <span class="pl-s1">m_typeName</span>;
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>, <span class="pl-s1">onNullInput</span>=<span class="pl-c1">RETURNS_NULL</span>)
<span class="pl-c1">@</span><span class="pl-c1">Override</span>
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">readSQL</span>(<span class="pl-smi">SQLInput</span> <span class="pl-s1">stream</span>, <span class="pl-smi">String</span> <span class="pl-s1">typeName</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">m_x</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
<span class="pl-s1">m_y</span> = <span class="pl-s1">stream</span>.<span class="pl-en">readDouble</span>();
<span class="pl-s1">m_typeName</span> = <span class="pl-s1">typeName</span>;
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>, <span class="pl-s1">onNullInput</span>=<span class="pl-c1">RETURNS_NULL</span>)
<span class="pl-c1">@</span><span class="pl-c1">Override</span>
<span class="pl-k">public</span> <span class="pl-smi">void</span> <span class="pl-en">writeSQL</span>(<span class="pl-smi">SQLOutput</span> <span class="pl-s1">stream</span>) <span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_x</span>);
<span class="pl-s1">stream</span>.<span class="pl-en">writeDouble</span>(<span class="pl-s1">m_y</span>);
}
<span class="pl-c1">@</span><span class="pl-c1">Function</span>(<span class="pl-s1">effects</span>=<span class="pl-c1">IMMUTABLE</span>, <span class="pl-s1">onNullInput</span>=<span class="pl-c1">RETURNS_NULL</span>)
<span class="pl-c1">@</span><span class="pl-c1">Override</span>
<span class="pl-k">public</span> <span class="pl-smi">String</span> <span class="pl-en">toString</span>()
{
<span class="pl-s1">s_logger</span>.<span class="pl-en">info</span>(<span class="pl-s1">m_typeName</span> + <span class="pl-s">" toString"</span>);
<span class="pl-smi">StringBuffer</span> <span class="pl-s1">sb</span> = <span class="pl-k">new</span> <span class="pl-smi">StringBuffer</span>();
<span class="pl-s1">sb</span>.<span class="pl-en">append</span>(<span class="pl-s">'('</span>);
<span class="pl-s1">sb</span>.<span class="pl-en">append</span>(<span class="pl-s1">m_x</span>);
<span class="pl-s1">sb</span>.<span class="pl-en">append</span>(<span class="pl-s">','</span>);
<span class="pl-s1">sb</span>.<span class="pl-en">append</span>(<span class="pl-s1">m_y</span>);
<span class="pl-s1">sb</span>.<span class="pl-en">append</span>(<span class="pl-s">')'</span>);
<span class="pl-k">return</span> <span class="pl-s1">sb</span>.<span class="pl-en">toString</span>();
}
<span class="pl-c">/* Meaningful code that actually does something with this type was</span>
<span class="pl-c"> * intentionally left out.</span>
<span class="pl-c"> */</span>
}</pre></div>
<p>The class itself is annotated with <code>@BaseUDT</code>, giving its SQL schema and name,
and the length and alignment needed for its internal, stored form.</p>
<p>Because the compiler knows the class is a <code>BaseUDT</code>, it already expects the
<code>parse</code>, <code>toString</code>, <code>readSQL</code>, and <code>writeSQL</code> methods to be present, and
will generate the correct SQL to declare them as functions to PostgreSQL.
The <code>@Function</code> annotations are only there to declare the immutability and
on-null-input behavior for those methods, because those values are not the
defaults when declaring a function.</p>
https://github.com/tada/pljava/wiki/User-guide/9270215cbf4cc2271c4691f533d33eb69c8d908e2015-12-22T20:53:04-05:002015-12-22T20:47:12-05:00User guidejcflack
<div class="markdown-heading"><h1 class="heading-element">User guide (wiki version)</h1><a id="user-content-user-guide-wiki-version" class="anchor" aria-label="Permalink: User guide (wiki version)" href="#user-guide-wiki-version"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The first reference should be the <a href="https://tada.github.io/pljava/use/use.html" rel="nofollow">user guide at the main project site</a>.</p>
<p>Here at this wiki version, you may still find useful information that is
not yet migrated to the project site. Some of the information here may be
outdated. Wiki content is slowly migrating to the main site as it is checked
and brought up to date.</p>
<div class="markdown-heading"><h2 class="heading-element">Utilities</h2><a id="user-content-utilities" class="anchor" aria-label="Permalink: Utilities" href="#utilities"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li>The <a href="https://tada.github.io/pljava/pljava-deploy/apidocs/index.html?org/postgresql/pljava/deploy/Deployer.html" rel="nofollow">PL/Java Deployer</a> is a Java client program that
helps you deploy PL/Java in the database. <em>It is now obsolescent; for
current instructions on installing PL/Java, see the installation guide
<a href="https://tada.github.io/pljava/install/install.html" rel="nofollow">at the main project site</a>.</em>
</li>
<li>
<a class="internal present" href="/tada/pljava/wiki/SQL-functions">SQL functions</a> that can be executed from SQL</li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Authoring</h2><a id="user-content-authoring" class="anchor" aria-label="Permalink: Authoring" href="#authoring"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li><a class="internal present" href="/tada/pljava/wiki/Writing-java-functions%2C-triggers%2C-and-types">Writing Java functions, triggers, and types</a></li>
<li>Using a <a class="internal present" href="/tada/pljava/wiki/Sql-deployment-descriptor">SQL deployment descriptor</a>
</li>
<li><a class="internal present" href="/tada/pljava/wiki/Security">Security</a></li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Debugging</h2><a id="user-content-debugging" class="anchor" aria-label="Permalink: Debugging" href="#debugging"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li><a class="internal present" href="/tada/pljava/wiki/Debugging-your-java-code">Debugging your Java code</a></li>
<li><a class="internal present" href="/tada/pljava/wiki/Debugging-in-c">Debugging in C</a></li>
</ul>
<div class="markdown-heading"><h2 class="heading-element">Troubleshooting</h2><a id="user-content-troubleshooting" class="anchor" aria-label="Permalink: Troubleshooting" href="#troubleshooting"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<ul>
<li><a class="internal present" href="/tada/pljava/wiki/Sporadic-hanging">Sporadic hanging</a></li>
</ul>
https://github.com/tada/pljava/wiki/Savepoints/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Savepointsjcflack
<div class="markdown-heading"><h1 class="heading-element">Savepoints</h1><a id="user-content-savepoints" class="anchor" aria-label="Permalink: Savepoints" href="#savepoints"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PostgreSQL savepoints are exposed using the standard <code>setSavepoint()</code> and
<code>releaseSavepoint()</code> methods on the <code>java.sql.Connection</code> interface. Two
restrictions apply:</p>
<ul>
<li>A savepoint must be rolled back or released in the function where it was set.</li>
<li>A savepoint must not outlive the function where it was set.</li>
</ul>
<p>"Function" here refers to the PL/Java function that is called from SQL.
The restrictions do not prevent the Java code from being organized into
several methods, but the savepoint cannot survive the eventual return
from Java to the SQL caller.</p>
https://github.com/tada/pljava/wiki/Function-mapping/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Function mappingjcflack
<div class="markdown-heading"><h1 class="heading-element">Functions</h1><a id="user-content-functions" class="anchor" aria-label="Permalink: Functions" href="#functions"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A Java function is declared with the name of a class and a public static method
on that class. The class will be resolved using the classpath that has been
defined for the schema where the function is declared. If no classpath has been
defined for that schema, the <code>public</code> schema is used. Please note that the
<em>system classloader</em> will take precedence always. There is no way to override
classes loaded with that loader.</p>
<p>The following function can be declared to access the static method
<code>getProperty</code> on the <code>java.lang.System</code> class:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION getsysprop(VARCHAR)
RETURNS VARCHAR
AS 'java.lang.System.getProperty'
LANGUAGE java;
SELECT getsysprop('java.version');"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">getsysprop</span>(<span class="pl-k">VARCHAR</span>)
RETURNS <span class="pl-k">VARCHAR</span>
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>java.lang.System.getProperty<span class="pl-pds">'</span></span>
LANGUAGE java;
<span class="pl-k">SELECT</span> getsysprop(<span class="pl-s"><span class="pl-pds">'</span>java.version<span class="pl-pds">'</span></span>);</pre></div>
<p>Both the parameters and the return value can be explicitly stated so the above
example could also have been written:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION getsysprop(VARCHAR)
RETURNS VARCHAR
AS 'java.lang.String=java.lang.System.getProperty(java.lang.String)'
LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">getsysprop</span>(<span class="pl-k">VARCHAR</span>)
RETURNS <span class="pl-k">VARCHAR</span>
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>java.lang.String=java.lang.System.getProperty(java.lang.String)<span class="pl-pds">'</span></span>
LANGUAGE java;</pre></div>
<p>This way of declaring the function is useful when the default mapping is
inadequate. PL/Java will use a standard PostgreSQL explicit cast when the SQL
type of the parameter or return value does not correspond to the Java type
defined in the mapping.</p>
<p><em>Note: the "explicit cast" here referred to is not accomplished by creating
an actual SQL CAST expression, but by (mostly) equivalent means. At the time
of this writing, two special cases are not yet implemented.</em></p>
<div class="markdown-heading"><h2 class="heading-element">SQL generation</h2><a id="user-content-sql-generation" class="anchor" aria-label="Permalink: SQL generation" href="#sql-generation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The simplest way to write the SQL function declaration that corresponds to
your Java code is to have the Java compiler do it for you:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="public class Hello {
@Function
public static String hello(String toWhom) {
return "Hello, " + toWhom + "!";
}
}"><pre><span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Hello</span> {
<span class="pl-c1">@</span><span class="pl-c1">Function</span>
<span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">String</span> <span class="pl-en">hello</span>(<span class="pl-smi">String</span> <span class="pl-s1">toWhom</span>) {
<span class="pl-k">return</span> <span class="pl-s">"Hello, "</span> + <span class="pl-s1">toWhom</span> + <span class="pl-s">"!"</span>;
}
}</pre></div>
<p>When this function is compiled, a "deployment descriptor" containing the right
SQL function declaration is also produced. When it is included in a <code>jar</code> file
with the compiled code, PL/Java's <code>sqlj.install_jar</code> function will create the
SQL function declaration at the same time it loads the jar. See the full
<a href="https://tada.github.io/pljava/use/hello.html" rel="nofollow">hello world example</a> for more.</p>
https://github.com/tada/pljava/wiki/Technology-in-brief/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Technology in briefjcflack
<p>A function or trigger in SQL resolves to a static method in a Java class. In
order for the function to execute, the appointed class must be installed in the
database. PL/Java adds a set of functions that helps installing and maintaining
the java classes. Classes are loaded into the database from normal Java
archives (AKA jars). A Jar may optionally contain a deployment descriptor that
in turn contains SQL commands to be executed when the jar is
deployed/undeployed. The functions are modeled after the standards proposed for
SQL 2003.</p>
<p>PL/Java implements a standardized way of passing parameters and return values.
Complex types and sets are passed using the standard JDBC ResultSet class.
Great care has been taken not to introduce any proprietary interfaces unless
absolutely necessary so that Java code written using PL/Java becomes as
database agnostic as possible.</p>
<p>A JDBC driver is included in PL/Java. This driver is written directly on top of
the PostgreSQL internal SPI routines. This driver is essential since it's very
common for functions and triggers to reuse the database. When they do, they
must use the same transactional boundaries that where used by the caller.</p>
<p>PL/Java is optimized for performance. The Java virtual machine executes within
the same process as the backend itself. This vouches for a very low call
overhead. PL/Java is designed with the objective to enable the power of Java to
the database itself so that database intensive business logic can execute as
close to the actual data as possible.</p>
<p>The standard Java Native Interface (JNI) is used when bridging calls from the
backend into the Java VM and vice versa. Please read the rationale behind
<a class="internal present" href="/tada/pljava/wiki/The-choice-of-JNI">The choice of JNI</a> and a more in-depth discussion about some
implementation details.</p>
<p>The versions of PostgreSQL and Java targeted by current PL/Java development
can be reviewed on <a href="https://tada.github.io/pljava/build/versions.html" rel="nofollow">the versions page</a>.</p>
https://github.com/tada/pljava/wiki/Running-the-pl-java-sample-tests/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Running the pl java sample testsjcflack
<div class="markdown-heading"><h1 class="heading-element">Running PL/Java sample tests</h1><a id="user-content-running-pljava-sample-tests" class="anchor" aria-label="Permalink: Running PL/Java sample tests" href="#running-pljava-sample-tests"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The PL/Java Source distribution contains a couple of rudimentary tests. The
tests are divided into two jar files. One is the client part found in the
test.jar. It contains some methods that executes SQL statements and prints the
output (all contained there can of course also be executed from psql or any
other client). The other is the examples.jar which contains the sample code
that runs in the backend. The latter must be installed in the database in order
to function. An easy way to do this is to use psql and issue the command:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT sqlj.install_jar('file:///some/directory/examples.jar', 'samples', true);"><pre><span class="pl-k">SELECT</span> <span class="pl-c1">sqlj</span>.<span class="pl-c1">install_jar</span>(<span class="pl-s"><span class="pl-pds">'</span>file:///some/directory/examples.jar<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>samples<span class="pl-pds">'</span></span>, true);</pre></div>
<p>Please note that the deployment descriptor stored in examples.jar will attempt
to create the schema javatest so the user that executes the sqlj.install_jar
command must have permission to do that. A number of tests now run from the
deployment descriptor itself, so by the time <code>install_jar</code> finishes, PL/Java
will have completed those tests.</p>
<p>Once loaded, you must also set the classpath used by the PL/Java runtime. This
classpath is set per schema (namespace). A schema that lacks a classpath will
default to the classpath that has been set for the public schema. The tests
will use the schema javatest. To define the classpath for this schema, simply
use psql and issue the command:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT sqlj.set_classpath('javatest', 'samples');"><pre><span class="pl-k">SELECT</span> <span class="pl-c1">sqlj</span>.<span class="pl-c1">set_classpath</span>(<span class="pl-s"><span class="pl-pds">'</span>javatest<span class="pl-pds">'</span></span>, <span class="pl-s"><span class="pl-pds">'</span>samples<span class="pl-pds">'</span></span>);</pre></div>
<p>The first argument is the name of the schema, the second is a colon separated
list of jar names. The names must reflect jars that are installed in the
system.</p>
<p>NOTE: If you don't use schemas, you must still issue the set_classpath command
to assign a correct classpath to the 'public' schema. This can only be done by
a super user.</p>
<p>Now, you should be able to run the client test application:</p>
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="java -cp <path including the jdbc driver and test.jar> org.postgresql.pljava.test.Tester"><pre>java -cp <span class="pl-k"><</span>path including the jdbc driver and test.jar<span class="pl-k">></span> org.postgresql.pljava.test.Tester</pre></div>
https://github.com/tada/pljava/wiki/Returning-complex-types/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Returning complex typesjcflack
<div class="markdown-heading"><h1 class="heading-element">Returning complex types</h1><a id="user-content-returning-complex-types" class="anchor" aria-label="Permalink: Returning complex types" href="#returning-complex-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The SQL-2003 draft suggest that a complex return value is handled as an IN/OUT
parameter and PL/Java implements it that way. If you declare a function that
returns a complex type, you will need to use a Java method with boolean return
type with a last parameter of type <code>java.sql.ResultSet</code> added after all of
the method's visible parameters. The output parameter
will be initialized to an updatable ResultSet that contains exactly one row.</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION createComplexTest(int, int)
RETURNS complexTest
AS 'foo.fee.Fum.createComplexTest'
IMMUTABLE LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">createComplexTest</span>(<span class="pl-k">int</span>, <span class="pl-k">int</span>)
RETURNS complexTest
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>foo.fee.Fum.createComplexTest<span class="pl-pds">'</span></span>
IMMUTABLE LANGUAGE java;</pre></div>
<p>The PL/Java method resolver will now find the following method in class foo.fee.Fum:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="public static boolean complexReturn(int base, int increment, ResultSet receiver)
throws SQLException
{
receiver.updateInt(1, base);
receiver.updateInt(2, base + increment);
receiver.updateTimestamp(3, new Timestamp(System.currentTimeMillis()));
return true;
}"><pre><span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">boolean</span> <span class="pl-en">complexReturn</span>(<span class="pl-smi">int</span> <span class="pl-s1">base</span>, <span class="pl-smi">int</span> <span class="pl-s1">increment</span>, <span class="pl-smi">ResultSet</span> <span class="pl-s1">receiver</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-s1">receiver</span>.<span class="pl-en">updateInt</span>(<span class="pl-c1">1</span>, <span class="pl-s1">base</span>);
<span class="pl-s1">receiver</span>.<span class="pl-en">updateInt</span>(<span class="pl-c1">2</span>, <span class="pl-s1">base</span> + <span class="pl-s1">increment</span>);
<span class="pl-s1">receiver</span>.<span class="pl-en">updateTimestamp</span>(<span class="pl-c1">3</span>, <span class="pl-k">new</span> <span class="pl-smi">Timestamp</span>(<span class="pl-smi">System</span>.<span class="pl-en">currentTimeMillis</span>()));
<span class="pl-k">return</span> <span class="pl-c1">true</span>;
}</pre></div>
<p>The return value denotes if the receiver should be considered as a valid tuple
(true) or NULL (false).</p>
https://github.com/tada/pljava/wiki/Exception-handling/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Exception handlingjcflack
<div class="markdown-heading"><h1 class="heading-element">Exception handling</h1><a id="user-content-exception-handling" class="anchor" aria-label="Permalink: Exception handling" href="#exception-handling"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>You can catch and handle an exception in the PostgreSQL back-end just like any
other exception. The back-end <code>ErrorData</code> structure is exposed as a property in
a <code>ServerException</code> class derived from <code>java.sql.SQLException</code>, and the Java
try/catch mechanism is synchronized with the back-end mechanism.</p>
<p><em>Note: for several reasons (see <a class="internal present" href="/tada/pljava/wiki/Thoughts-on-logging">Thoughts on logging</a> for background),
referring to <code>ServerException</code> and <code>ErrorData</code> from your code is not
currently recommended, and in the future may become impossible. An improved
mechanism is expected in a future release. Until then, using only the
standard Java API of <code>java.sql.SQLException</code> and its standard attributes
(such as <code>SQLState</code>) is recommended wherever possible.</em></p>
<p>PL/Java will always catch exceptions that you don't. They will cause a
PostgreSQL error and the message is logged using the PostgreSQL logging
utilities. The stack trace of the exception will also be printed if the
PostgreSQL configuration parameter <code>log_min_messages</code> is set to <code>DEBUG1</code>
or lower.</p>
<div class="markdown-heading"><h3 class="heading-element">Important Note:</h3><a id="user-content-important-note" class="anchor" aria-label="Permalink: Important Note:" href="#important-note"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>You will not be able to continue executing back-end functions until your
function has returned and the error has been propagated when the back-end has
generated an exception unless you have used a save-point. When a save-point is
rolled back, the exceptional condition is reset and execution can continue.</p>
https://github.com/tada/pljava/wiki/Default-type-mapping/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Default type mappingjcflack
<div class="markdown-heading"><h2 class="heading-element">Scalar types</h2><a id="user-content-scalar-types" class="anchor" aria-label="Permalink: Scalar types" href="#scalar-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Scalar types are mapped in a straight forward way. Here's a table of the
current mappings (will be updated as more mappings are implemented).</p>
<table role="table">
<tbody><tr>
<th>PostgreSQL</th>
<th>Java</th>
</tr>
<tr>
<td>bool</td>
<td>boolean</td>
</tr>
<tr>
<td>"char"</td>
<td>byte</td>
</tr>
<tr>
<td>int2</td>
<td>short</td>
</tr>
<tr>
<td>int4</td>
<td>int</td>
</tr>
<tr>
<td>int8</td>
<td>long</td>
</tr>
<tr>
<td>float4</td>
<td>float</td>
</tr>
<tr>
<td>float8</td>
<td>double</td>
</tr>
<tr>
<td>char</td>
<td>java.lang.String</td>
</tr>
<tr>
<td>varchar</td>
<td>java.lang.String</td>
</tr>
<tr>
<td>text</td>
<td>java.lang.String</td>
</tr>
<tr>
<td>name</td>
<td>java.lang.String</td>
</tr>
<tr>
<td>bytea</td>
<td>byte[]</td>
</tr>
<tr>
<td>date</td>
<td>java.sql.Date</td>
</tr>
<tr>
<td>time</td>
<td>java.sql.Time (stored value treated as local time)</td>
</tr>
<tr>
<td>timetz</td>
<td>java.sql.Time</td>
</tr>
<tr>
<td>timestamp</td>
<td>java.sql.Timestamp (stored value treated as local time)</td>
</tr>
<tr>
<td>timestamptz</td>
<td>java.sql.Timestamp</td>
</tr>
</tbody></table>
<div class="markdown-heading"><h2 class="heading-element">Array scalar types</h2><a id="user-content-array-scalar-types" class="anchor" aria-label="Permalink: Array scalar types" href="#array-scalar-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>All scalar types can be represented as an array. Although PostgreSQL will allow
that you declare multi dimensional arrays with fixed sizes, PL/Java will still
treat all arrays as having one dimension (with the exception of the bytea[]
which maps to byte[][]). The reason for this is that the information about
dimensions and sizes is not stored anywhere and not enforced in any way. You
can read more about this in the <a href="http://www.postgresql.org/docs/8.4/static/arrays.html" rel="nofollow">PostgreSQL Documentation</a>.</p>
<p>However, the current implementation does not enforce the array size limits —
the behavior is the same as for arrays of unspecified length.</p>
<p>Actually, the current implementation does not enforce the declared number of
dimensions either. Arrays of a particular element type are all considered to be
of the same type, regardless of size or number of dimensions. So, declaring
number of dimensions or sizes in CREATE TABLE is simply documentation, it does
not affect run-time behavior.</p>
<table role="table">
<tbody><tr>
<th>PostgreSQL</th>
<th>Java</th>
</tr>
<tr>
<td>bool[]</td>
<td>boolean[]</td>
</tr>
<tr>
<td>"char"[]</td>
<td>byte[]</td>
</tr>
<tr>
<td>int2[]</td>
<td>short[]</td>
</tr>
<tr>
<td>int4[]</td>
<td>int[]</td>
</tr>
<tr>
<td>int8[]</td>
<td>long []</td>
</tr>
<tr>
<td>float4[]</td>
<td>float[]</td>
</tr>
<tr>
<td>float8[]</td>
<td>double[]</td>
</tr>
<tr>
<td>char[]</td>
<td>java.lang.String[]</td>
</tr>
<tr>
<td>varchar[]</td>
<td>java.lang.String[]</td>
</tr>
<tr>
<td>text[]</td>
<td>java.lang.String[]</td>
</tr>
<tr>
<td>name[]</td>
<td>java.lang.String[]</td>
</tr>
<tr>
<td>bytea[]</td>
<td>byte[][]</td>
</tr>
<tr>
<td>date[]</td>
<td>java.sql.Date[]</td>
</tr>
<tr>
<td>time[]</td>
<td>java.sql.Time[] (stored value treated as local time)</td>
</tr>
<tr>
<td>timetz[]</td>
<td>java.sql.Time[]</td>
</tr>
<tr>
<td>timestamp[]</td>
<td>java.sql.Timestamp[] (stored value treated as local time)</td>
</tr>
<tr>
<td>timestamptz[]</td>
<td>java.sql.Timestamp[]</td>
</tr>
</tbody></table>
<div class="markdown-heading"><h2 class="heading-element">Domain types</h2><a id="user-content-domain-types" class="anchor" aria-label="Permalink: Domain types" href="#domain-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A domain type will be mapped in accordance with the type that it extends unless
you have installed a specific mapping to override that behavior.</p>
<div class="markdown-heading"><h2 class="heading-element">Pseudo types</h2><a id="user-content-pseudo-types" class="anchor" aria-label="Permalink: Pseudo types" href="#pseudo-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<table role="table">
<tbody><tr>
<th>PostgreSQL</th>
<th>Java</th>
</tr>
<tr>
<td>"any"</td>
<td>java.lang.Object</td>
</tr>
<tr>
<td>anyelement</td>
<td>java.lang.Object</td>
</tr>
<tr>
<td>anyarray</td>
<td>java.lang.Object[]</td>
</tr>
<tr>
<td>cstring</td>
<td>java.lang.String</td>
</tr>
<tr>
<td>record</td>
<td>java.sql.ResultSet</td>
</tr>
<tr>
<td>trigger</td>
<td>org.postgresql.pljava.TriggerData (see <a class="internal present" href="/tada/pljava/wiki/Triggers">Triggers</a>)</td>
</tr>
</tbody></table>
<div class="markdown-heading"><h2 class="heading-element">NULL handling of primitives</h2><a id="user-content-null-handling-of-primitives" class="anchor" aria-label="Permalink: NULL handling of primitives" href="#null-handling-of-primitives"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The scalar types that map to Java primitives can not be passed as null values.
To enable this, those types can have an alternative mapping. You enable this
mapping by explicitly denoting it in the method reference.</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE FUNCTION trueIfEvenOrNull(integer)
RETURNS bool
AS 'foo.fee.Fum.trueIfEvenOrNull(java.lang.Integer)'
LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">trueIfEvenOrNull</span>(<span class="pl-k">integer</span>)
RETURNS bool
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>foo.fee.Fum.trueIfEvenOrNull(java.lang.Integer)<span class="pl-pds">'</span></span>
LANGUAGE java;</pre></div>
<p>In java, you would have something like:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="package foo.fee;
public class Fum
{
static boolean trueIfEvenOrNull(Integer value)
{
return (value == null)
? true
: (value.intValue() % 1) == 0;
}
}"><pre><span class="pl-k">package</span> <span class="pl-s1">foo</span>.<span class="pl-s1">fee</span>;
<span class="pl-k">public</span> <span class="pl-k">class</span> <span class="pl-smi">Fum</span>
{
<span class="pl-k">static</span> <span class="pl-smi">boolean</span> <span class="pl-en">trueIfEvenOrNull</span>(<span class="pl-smi">Integer</span> <span class="pl-s1">value</span>)
{
<span class="pl-k">return</span> (<span class="pl-s1">value</span> == <span class="pl-c1">null</span>)
? <span class="pl-c1">true</span>
: (<span class="pl-s1">value</span>.<span class="pl-en">intValue</span>() % <span class="pl-c1">1</span>) == <span class="pl-c1">0</span>;
}
}</pre></div>
<p>The following two statements should both yield true:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT trueIfEvenOrNull(NULL);
SELECT trueIfEvenOrNull(4);"><pre><span class="pl-k">SELECT</span> trueIfEvenOrNull(<span class="pl-k">NULL</span>);
<span class="pl-k">SELECT</span> trueIfEvenOrNull(<span class="pl-c1">4</span>);</pre></div>
<p>In order to return null values from a Java method, you simply use the object
type that corresponds to the primitive (i.e. you return java.lang.Integer
instead of int). The PL/Java resolver mechanism will find the method
regardless. Since Java cannot have different return types for methods with the
same name, this does not introduce any ambiguities.</p>
<p>Starting with PostgreSQL version 8.2 it will be possible to have NULL values in
arrays. PL/Java will handle that the same way as with normal primitives, i.e.
you can declare methods that use a java.lang.Integer[] parameter instead of an
int[] parameter.</p>
<div class="markdown-heading"><h2 class="heading-element">Composite types</h2><a id="user-content-composite-types" class="anchor" aria-label="Permalink: Composite types" href="#composite-types"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A composite type will be passed as a read-only java.sql.ResultSet with exactly
one row by default. The ResultSet will be positioned on its row so no call to
next() should be made. The values of the composite type are retrieved using the
standard getter methods of the ResultSet.
Example:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE TYPE compositeTest
AS(base integer, incbase integer, ctime timestamptz);
CREATE FUNCTION useCompositeTest(compositeTest)
RETURNS VARCHAR
AS 'foo.fee.Fum.useCompositeTest'
IMMUTABLE LANGUAGE java;"><pre><span class="pl-k">CREATE</span> <span class="pl-k">TYPE</span> <span class="pl-en">compositeTest</span>
<span class="pl-k">AS</span>(base <span class="pl-k">integer</span>, incbase <span class="pl-k">integer</span>, ctime <span class="pl-k">timestamptz</span>);
<span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">useCompositeTest</span>(compositeTest)
RETURNS <span class="pl-k">VARCHAR</span>
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>foo.fee.Fum.useCompositeTest<span class="pl-pds">'</span></span>
IMMUTABLE LANGUAGE java;</pre></div>
<p>In class Fum we add the static following static method
The foo.fee.Fum.useCompositeTest method:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="public static String useCompositeTest(ResultSet compositeTest)
throws SQLException
{
int base = compositeTest.getInt(1);
int incbase = compositeTest.getInt(2);
Timestamp ctime = compositeTest.getTimestamp(3);
return "Base = \\"" + base +
"\\", incbase = \\"" + incbase +
"\\", ctime = \\"" + ctime + "\\"";
}"><pre><span class="pl-k">public</span> <span class="pl-k">static</span> <span class="pl-smi">String</span> <span class="pl-en">useCompositeTest</span>(<span class="pl-smi">ResultSet</span> <span class="pl-s1">compositeTest</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-smi">int</span> <span class="pl-s1">base</span> = <span class="pl-s1">compositeTest</span>.<span class="pl-en">getInt</span>(<span class="pl-c1">1</span>);
<span class="pl-smi">int</span> <span class="pl-s1">incbase</span> = <span class="pl-s1">compositeTest</span>.<span class="pl-en">getInt</span>(<span class="pl-c1">2</span>);
<span class="pl-smi">Timestamp</span> <span class="pl-s1">ctime</span> = <span class="pl-s1">compositeTest</span>.<span class="pl-en">getTimestamp</span>(<span class="pl-c1">3</span>);
<span class="pl-k">return</span> <span class="pl-s">"Base = <span class="pl-cce">\\</span>"</span>" + <span class="pl-s1">base</span> +
<span class="pl-s">"<span class="pl-cce">\\</span>"</span>, <span class="pl-s1">incbase</span> = \<span class="pl-cce">\"</span><span class="pl-s">" + incbase +</span>
<span class="pl-s"> "</span><span class="pl-cce">\\</span><span class="pl-s">", ctime = <span class="pl-cce">\\</span>"</span>" + <span class="pl-s1">ctime</span> + <span class="pl-s">"<span class="pl-cce">\\</span>"</span>";
}</pre></div>
<div class="markdown-heading"><h2 class="heading-element">Default mapping</h2><a id="user-content-default-mapping" class="anchor" aria-label="Permalink: Default mapping" href="#default-mapping"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Types that have no mapping are currently mapped to java.lang.String. The
standard PostgreSQL textin/textout routines registered for respective type will
be used when the values are converted.</p>
https://github.com/tada/pljava/wiki/Using-jdbc/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Using jdbcjcflack
<div class="markdown-heading"><h1 class="heading-element">Using JDBC</h1><a id="user-content-using-jdbc" class="anchor" aria-label="Permalink: Using JDBC" href="#using-jdbc"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>PL/Java contains a JDBC driver that maps to the PostgreSQL SPI functions. A
connection that maps to the current transaction can be obtained using the
following statement:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="Connection conn = DriverManager.getConnection("jdbc:default:connection");"><pre><span class="pl-smi">Connection</span> <span class="pl-s1">conn</span> = <span class="pl-smi">DriverManager</span>.<span class="pl-en">getConnection</span>(<span class="pl-s">"jdbc:default:connection"</span>);</pre></div>
<p>From there on, you can prepare and execute statements just like with any other
JDBC connection. There are a couple of limitations though:</p>
<ul>
<li>The transaction cannot be managed in any way. Thus, you cannot use
methods on the connection such as:
<ul>
<li>commit()</li>
<li>rollback()</li>
<li>setAutoCommit()</li>
<li>setTransactionIsolation()</li>
</ul>
</li>
<li>A savepoint cannot outlive the function in which it was set and it must
also be rolled back or released by that same function.</li>
<li>
<code>ResultSet</code>s returned from <code>executeQuery()</code> are always <code>FETCH_FORWARD</code> and
<code>CONCUR_READ_ONLY</code>.</li>
<li>Meta-data became available in PL/Java 1.1.</li>
<li>
<code>CallableStatement</code> (for stored procedures) is not yet implemented.</li>
<li>Clob/Blob types need more work. byte[] and String works fine for bytea/text
respectively. A more efficient mapping is planned where the actual array is
not copied.</li>
</ul>
https://github.com/tada/pljava/wiki/Triggers/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Triggersjcflack
<div class="markdown-heading"><h1 class="heading-element">Triggers</h1><a id="user-content-triggers" class="anchor" aria-label="Permalink: Triggers" href="#triggers"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>The method signature of a trigger is predefined. A trigger method must always
return void and have a org.postgresql.pljava.TriggerData parameter. No more, no
less. The TriggerData interface provides access to two java.sql.ResultSet
instances; one representing the old row and one representing the new. The old
row is read-only and the new row is updateable.</p>
<p>The ResultSets are only available for triggers that are fired ON EACH ROW.
Delete triggers have no new row, and insert triggers have no old row. Only
update triggers have both.</p>
<p>In addition to the sets, several boolean methods exists to gain more
information about the trigger.</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="CREATE TABLE mdt (
id int4,
idesc text,
moddate timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL);
CREATE FUNCTION moddatetime()
RETURNS trigger
AS 'org.postgresql.pljava.example.Triggers.moddatetime'
LANGUAGE java;
CREATE TRIGGER mdt_moddatetime
BEFORE UPDATE ON mdt
FOR EACH ROW
EXECUTE PROCEDURE moddatetime (moddate);"><pre><span class="pl-k">CREATE</span> <span class="pl-k">TABLE</span> <span class="pl-en">mdt</span> (
id int4,
idesc <span class="pl-k">text</span>,
moddate <span class="pl-k">timestamp</span> DEFAULT <span class="pl-c1">CURRENT_TIMESTAMP</span> <span class="pl-k">NOT NULL</span>);
<span class="pl-k">CREATE</span> <span class="pl-k">FUNCTION</span> <span class="pl-en">moddatetime</span>()
RETURNS trigger
<span class="pl-k">AS</span> <span class="pl-s"><span class="pl-pds">'</span>org.postgresql.pljava.example.Triggers.moddatetime<span class="pl-pds">'</span></span>
LANGUAGE java;
<span class="pl-k">CREATE</span> <span class="pl-k">TRIGGER</span> <span class="pl-en">mdt_moddatetime</span>
BEFORE <span class="pl-k">UPDATE</span> <span class="pl-k">ON</span> mdt
FOR EACH ROW
EXECUTE PROCEDURE moddatetime (moddate);</pre></div>
<p>And here is the corresponding Java code:</p>
<div class="highlight highlight-source-java notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="/**
* Update a modification time when the row is updated.
*/
static void moddatetime(TriggerData td)
throws SQLException
{
if(td.isFiredForStatement())
throw new TriggerException(td, "can't process STATEMENT events");
if(td.isFiredAfter())
throw new TriggerException(td, "must be fired before event");
if(!td.isFiredByUpdate())
throw new TriggerException(td, "can only process UPDATE events");
ResultSet _new = td.getNew();
String[] args = td.getArguments();
if(args.length != 1)
throw new TriggerException(td, "one argument was expected");
_new.updateTimestamp(args[0], new Timestamp(System.currentTimeMillis()));
}"><pre><span class="pl-c">/**</span>
<span class="pl-c"> * Update a modification time when the row is updated.</span>
<span class="pl-c"> */</span>
<span class="pl-k">static</span> <span class="pl-smi">void</span> <span class="pl-en">moddatetime</span>(<span class="pl-smi">TriggerData</span> <span class="pl-s1">td</span>)
<span class="pl-k">throws</span> <span class="pl-smi">SQLException</span>
{
<span class="pl-k">if</span>(<span class="pl-s1">td</span>.<span class="pl-en">isFiredForStatement</span>())
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">TriggerException</span>(<span class="pl-s1">td</span>, <span class="pl-s">"can't process STATEMENT events"</span>);
<span class="pl-k">if</span>(<span class="pl-s1">td</span>.<span class="pl-en">isFiredAfter</span>())
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">TriggerException</span>(<span class="pl-s1">td</span>, <span class="pl-s">"must be fired before event"</span>);
<span class="pl-k">if</span>(!<span class="pl-s1">td</span>.<span class="pl-en">isFiredByUpdate</span>())
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">TriggerException</span>(<span class="pl-s1">td</span>, <span class="pl-s">"can only process UPDATE events"</span>);
<span class="pl-smi">ResultSet</span> <span class="pl-s1">_new</span> = <span class="pl-s1">td</span>.<span class="pl-en">getNew</span>();
<span class="pl-smi">String</span>[] <span class="pl-s1">args</span> = <span class="pl-s1">td</span>.<span class="pl-en">getArguments</span>();
<span class="pl-k">if</span>(<span class="pl-s1">args</span>.<span class="pl-s1">length</span> != <span class="pl-c1">1</span>)
<span class="pl-k">throw</span> <span class="pl-k">new</span> <span class="pl-smi">TriggerException</span>(<span class="pl-s1">td</span>, <span class="pl-s">"one argument was expected"</span>);
<span class="pl-s1">_new</span>.<span class="pl-en">updateTimestamp</span>(<span class="pl-s1">args</span>[<span class="pl-c1">0</span>], <span class="pl-k">new</span> <span class="pl-smi">Timestamp</span>(<span class="pl-smi">System</span>.<span class="pl-en">currentTimeMillis</span>()));
}</pre></div>
https://github.com/tada/pljava/wiki/Installation-guide/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Installation guidejcflack
<div class="markdown-heading"><h1 class="heading-element">Installing PL/Java</h1><a id="user-content-installing-pljava" class="anchor" aria-label="Permalink: Installing PL/Java" href="#installing-pljava"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>For the most current information on installing PL/Java,
see the <a href="https://tada.github.io/pljava/install/install.html" rel="nofollow">installation guide</a> on the <a href="https://tada.github.io/pljava/" rel="nofollow">project information site</a>.</p>
https://github.com/tada/pljava/wiki/Complete-uninstall/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00Complete uninstalljcflack
<p>In order to completely uninstall PL/Java you need to have super user privileges on the database. Here's how you do it.</p>
<ol start="0">
<li>
<p>Get rid of the <code>sqlj</code> schema and all objects depending on it.</p>
<ul>
<li>If you installed PL/Java with <code>CREATE EXTENSION pljava</code> then drop it
with <code>DROP EXTENSION pljava CASCADE</code>
</li>
<li>If you installed PL/Java with a <code>LOAD</code> command, then drop it with
<code>DROP SCHEMA sqlj CASCADE</code>
</li>
</ul>
<p><strong>Caution:</strong> Either command will drop the PL/Java schema and language
declarations, all jars you may have loaded, all functions and types
they provided, <em>and everything else in your database that depends on
any of those things</em>.</p>
<p>You can try either command <em>without</em> <code>CASCADE</code> first, to see a list
of what would be dropped.</p>
</li>
<li>
<p>Remove any settings of PL/Java variables (configuration variables with
names starting with <code>pljava.</code>) that you may have changed from their
defaults.</p>
<ul>
<li>
<p>If you had set a variable <em>var</em> for a particular database using
<code>ALTER DATABASE dbname SET var ...</code> then reset it using
<code>ALTER DATABASE dbname RESET var</code>.</p>
</li>
<li>
<p>If you had set it for the whole cluster using
<code>ALTER SYSTEM SET var ...</code> then reset it using
<code>ALTER SYSTEM RESET var</code> and, when you have reset all, use
<code>SELECT pg_reload_conf()</code>.</p>
</li>
<li>
<p>If you had set PL/Java variables by editing the configuration file
(particularly on PostgreSQL before 9.2, where this is the only
available method), remove the settings from the file, then use
<code>SELECT pg_reload_conf()</code> in SQL.</p>
</li>
<li>
<p>The variable <code>dynamic_library_path</code> is not specific to PL/Java, but
if you added a directory to it for the sake of PL/Java, undo that.</p>
</li>
</ul>
</li>
<li>
<p>Remove the PL/Java files from the file system.</p>
<ul>
<li>If you installed PL/Java with a package manager, uninstall it
the same way.</li>
<li>Otherwise, remove the installed files from wherever you installed them.</li>
</ul>
</li>
</ol>
https://github.com/tada/pljava/wiki/The-choice-of-JNI/a0ee185ef1c51d4946d3221223424915b13597962015-12-22T20:48:35-05:002015-12-22T00:41:02-05:00The choice of JNIjcflack
<div class="markdown-heading"><h2 class="heading-element">Rationale behind using JNI as opposed to threads in a remote JVM process.</h2><a id="user-content-rationale-behind-using-jni-as-opposed-to-threads-in-a-remote-jvm-process" class="anchor" aria-label="Permalink: Rationale behind using JNI as opposed to threads in a remote JVM process." href="#rationale-behind-using-jni-as-opposed-to-threads-in-a-remote-jvm-process"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<div class="markdown-heading"><h3 class="heading-element">Reasons to use a high level language like Java™ in the backend</h3><a id="user-content-reasons-to-use-a-high-level-language-like-java-in-the-backend" class="anchor" aria-label="Permalink: Reasons to use a high level language like Java™ in the backend" href="#reasons-to-use-a-high-level-language-like-java-in-the-backend"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>A large part of the reason why JNI was chosen in favor of an RPC based, single
JVM solution was due to the expected use-cases. Enterprise systems today are
almost always 3-tier or n-tier. Database functions, triggers, and stored
procedures are mechanisms that extend the functionality of the backend tier.
They typically rely on a tight integration with the database due to a very high
rate of interactions and execute inside of the database largely to limit the
number of interactions between the middle tier and the backend tier. Some
typical use-cases:</p>
<ul>
<li>Referential integrity enforcement. Using Java, referential integrity can be
implemented that goes beyond what can be done using the standard SQL
semantics. It may involve checking XML documents, enforcing some
meta-driven rule system, or other complex tasks that put high demands on
the implementation language.</li>
<li>Advanced pattern recognition. Soundex, image comparison, etc.</li>
<li>XML support functions. Java comes with a lot of XML support. Parsers etc.
are readily available.</li>
<li>Support functions for O/R mappers. A variety of support can be implemented
depending on design. One example is an O/R mapper that allows methods on
persistent objects. A lot can be gained if such methods are pushed down and
executed within the database. Consider the following (OQL):</li>
</ul>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT AVG(x.salary - x.computeTax()) FROM Employee x WHERE x.salary > 120000;"><pre><span class="pl-k">SELECT</span> <span class="pl-c1">AVG</span>(<span class="pl-c1">x</span>.<span class="pl-c1">salary</span> <span class="pl-k">-</span> <span class="pl-c1">x</span>.<span class="pl-c1">computeTax</span>()) <span class="pl-k">FROM</span> Employee x <span class="pl-k">WHERE</span> <span class="pl-c1">x</span>.<span class="pl-c1">salary</span> <span class="pl-k">></span> <span class="pl-c1">120000</span>;</pre></div>
<p>Pushing the computeTax logic down to the database instead of computing it in
the middle tier (where much or the O/R logic resides) is a huge gain from a
performance standpoint. The statement could be transformed into SQL as:</p>
<div class="highlight highlight-source-sql notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="SELECT AVG(x.salary - computeTax(x.salary)) FROM Employee x WHERE x.salary > 120000;"><pre><span class="pl-k">SELECT</span> <span class="pl-c1">AVG</span>(<span class="pl-c1">x</span>.<span class="pl-c1">salary</span> <span class="pl-k">-</span> computeTax(<span class="pl-c1">x</span>.<span class="pl-c1">salary</span>)) <span class="pl-k">FROM</span> Employee x <span class="pl-k">WHERE</span> <span class="pl-c1">x</span>.<span class="pl-c1">salary</span> <span class="pl-k">></span> <span class="pl-c1">120000</span>;</pre></div>
<p>As a result, very few interactions (typically only one) need to be made between
the middle and the backend tier.</p>
<ul>
<li>Views and indexes making use of computed values. In the above example and
index could be created on computeTax(x.salary) and a view could express
that as net_income.</li>
<li>Message queue management. Delivering or fetching things using message queues
or other delivery mechanisms. As with most interactions with other
processes, this requires transaction coordination of some kind.</li>
</ul>
<p>One might argue that since a JVM often is present running an app-server in the
middle tier, would it not be more efficient if that JVM also executed the
database functions and triggers? In my opinion, this would be very bad. One
major reason for moving execution down to the database is performance (by
minimizing the number of roundtrips between the app-server and the database)
another is separation of concern. Referential data integrity and other ways to
extend the functionality of the database should not be the app-servers concern,
it belongs in the backend tier. Other aspects like database versus app-server
administration, replication of code and permission changes for functions, and
running different tiers on different servers, makes it even worse.</p>
<div class="markdown-heading"><h3 class="heading-element">Resource consumption</h3><a id="user-content-resource-consumption" class="anchor" aria-label="Permalink: Resource consumption" href="#resource-consumption"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Having one JVM per connection instead of one thread per connection running in
the same JVM will undoubtedly consume more resources. There are however a
couple of facts that must be remembered:</p>
<ul>
<li>The overhead of multiple processes is already present due to the fact that
each connection is a process in a PostgreSQL system.</li>
<li>In order to keep connections separated in case they run in the same JVM,
some kind of "compartments" must be created. Either you create them using
parallel class loader chains (similar to how EAR files are managed in an
EJB server) or you use a less protective model similar to a servlet engine.
In order to get a separation that is comparable to what you get using
separate JVM's, you must chose the former. That consumes some resources.</li>
<li>The JVM has undergone a series of improvements in order to reduce footprint
and startup time. Some significant improvements where made in Java 1.4 and
Java 1.5 introduces Java Heap Self Tuning, Class Data Sharing, and Garbage
Collector Ergonomics (read more here), technologies that will minimize the
startup time and make the JVM adopt its resource consumption in a much
improved way.</li>
<li>PL/Java can make use of the GCJ. Using this technology, all core classes
will be compiled into binaries and optionally pre-loaded by the postmaster.
It also means that all modules that are loaded using the
install_jar/replace_jar can be compiled into real shared objects. Finally,
it means that the footprint for each "JVM" will be significantly decreased.</li>
</ul>
<p><em>Note: GCJ is no longer targeted by current PL/Java development.</em></p>
<div class="markdown-heading"><h3 class="heading-element">Connection pooling</h3><a id="user-content-connection-pooling" class="anchor" aria-label="Permalink: Connection pooling" href="#connection-pooling"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In the Java community you are very likely to use a connection pool. The pool
will ensure that the number of connections stays as low as possible and that
connections are reused (instead of closed and reestablished). New JVMs are
started rarely.</p>
<div class="markdown-heading"><h3 class="heading-element">Connection isolation</h3><a id="user-content-connection-isolation" class="anchor" aria-label="Permalink: Connection isolation" href="#connection-isolation"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Separate JVMs gives you a much higher degree of isolation. This brings a number
of advantages:</p>
<ul>
<li>There's no problem attaching a debugger to one connection (one JVM) while
the others run unaffected.</li>
<li>There's no chance that one connection manages to accidentally
(or maliciously) exchange dirty data with another connection.</li>
<li>A process that performs tasks that consume a lot of CPU under a long
period of time can be scheduled with a lower priority using a simple OS
command.</li>
<li>The JVMs can be brought down and restarted individually.</li>
<li>Security policies are much easier to enforce.</li>
</ul>
<div class="markdown-heading"><h3 class="heading-element">Transaction visibility</h3><a id="user-content-transaction-visibility" class="anchor" aria-label="Permalink: Transaction visibility" href="#transaction-visibility"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>In order to maintain the correct visibility, the transaction must somehow be
propagated to the Java layer. I can see two solutions for this using RPC.
Either an XA aware JDBC-driver is used (requires XA support from PostgreSQL) or
a JDBC driver is written so that it calls back to the SPI functions in the
invoking process. Both choices results in an increased number of RPC calls and
a negative performance impact.</p>
<p>The PL/Java approach is to use the underlying SPI interfaces directly through
JNI by providing a "pseudo connection" that implements the JDBC interfaces. The
mapping is thus very direct. Data need never be serialized nor duplicated.</p>
<div class="markdown-heading"><h3 class="heading-element">RPC performance</h3><a id="user-content-rpc-performance" class="anchor" aria-label="Permalink: RPC performance" href="#rpc-performance"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>Remote procedure calls are extremely expensive compared to in-process calls.
Relying on an RPC mechanism for Java calls will cripple the usefulness of such
an implementation a great deal. Here are two examples:</p>
<ul>
<li>In order for an update trigger to function using RPC, you can choose one of
two approaches. Either you limit the number of RPC calls and send two full
Tuples (old and new) and a Tuple Descriptor to the remote JVM, and then
pass a third Tuple (the modified new) back to the original, or you pass
those structures by reference (as CORBA remote objects) and perform one RPC
call each time you access them. You have a tradeoff between on one hand,
limited functionality and poor performance, and on the other, good
functionality and really bad performance.</li>
<li>When one or several Java functions are used in the projection or filter
of a SELECT statement on a query processing several thousand rows, each row
will cause at least one call to Java. In case of RPC, this implies that the
OS needs to do at least two context switches (back and forth) for each row
in the query.</li>
</ul>
<p>Using JNI to directly access structures like TriggerData, Relation, TupleDesc,
and HeapTuple minimizes the amount of data that needs to be copied. Parameters
and return values that are primitives need not even become Java objects. A
32-bit int4 Datum can be directly passed as a Java int (jint in JNI).</p>
<div class="markdown-heading"><h3 class="heading-element">Simplicity</h3><a id="user-content-simplicity" class="anchor" aria-label="Permalink: Simplicity" href="#simplicity"><svg data-component="Octicon" class="octicon octicon-link" viewBox="0 0 16 16" version="1.1" width="16" height="16" aria-hidden="true"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg></a></div>
<p>I've have some experience of work involving CORBA and other RPCs. They add a
fair amount of complexity to the process. JNI however, is invisible to the
user.</p>