tag:github.com,2008:/tada/pljava/wiki pljava: Recent Wiki Updates 2025-09-29T12:51:54-04:00 https://github.com/tada/pljava/wiki/c68e24c235759ab05a1174c53e1ebeaed0dd9f48 2025-09-29T12:51:54-04:00 2025-09-29T12:51:54-04:00 Home jcflack <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&amp;sort=newest" rel="nofollow">on Stack Overflow</a> (Atom <a href="https://stackoverflow.com/feeds/tag?tagnames=pljava&amp;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/91d866470738bf46435d0f3e0f2a9e203341354f 2025-05-31T17:15:34-04:00 2025-05-31T17:15:34-04:00 Contribution guide jcflack <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 &amp;&amp; git pull &amp;&amp; git checkout -b bug/master/my_contribution"><pre class="notranslate"><code>git checkout master &amp;&amp; git pull &amp;&amp; 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/a7e9f97ec5e87f43f4e757b79965a3512d9efa11 2025-03-23T18:01:03-04:00 2025-03-23T18:01:03-04:00 JEP 411 jcflack <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&amp;pg=PA35&amp;lpg=PA35&amp;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/0675a25a8203022d0deeeb7565395eb5a01cd2aa 2024-04-12T11:26:27-04:00 2024-04-12T11:26:27-04:00 Build tips jcflack <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/1313d82a7f246f3f4ddbca73ee20f286808672a8 2023-09-19T15:40:06-04:00 2023-09-19T15:40:06-04:00 Prebuilt packages jcflack <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,&quot;11.1 (Debian 11.1-1.pgdg+1)&quot;,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,&quot;11.11 (Debian 11.11-1.pgdg90+1)&quot;,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/7449c3076d747ba39dde9ae5c84f1c8f55380d4c 2021-09-25T17:38:28-04:00 2021-09-25T17:38:28-04:00 Security jcflack <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/1b9e023a740a6a79ded03c4dbbd231990242a043 2020-07-01T00:43:13-04:00 2020-07-01T00:43:13-04:00 Build process custom Maven plugin jcflack <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 &quot;inside-out&quot;" 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/eb59e0eceaf848811be322e03be6e9a990445a96 2020-05-12T22:16:54-04:00 2020-05-12T22:16:54-04:00 Sql deployment descriptor jcflack <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="&lt;descriptor file&gt; ::= SQLActions &lt;left bracket&gt; &lt;rightbracket&gt; &lt;equal sign&gt; { [ &lt;double quote&gt; &lt;action group&gt; &lt;double quote&gt; [ &lt;comma&gt; &lt;double quote&gt; &lt;action group&gt; &lt;double quote&gt; ] ] } &lt;action group&gt; ::= &lt;install actions&gt; | &lt;remove actions&gt; &lt;install actions&gt; ::= BEGIN INSTALL [ &lt;command&gt; &lt;semicolon&gt; ]... END INSTALL &lt;remove actions&gt; ::= BEGIN REMOVE [ &lt;command&gt; &lt;semicolon&gt; ]... END REMOVE &lt;command&gt; ::= &lt;SQL statement&gt; | &lt;implementor block&gt; &lt;SQL statement&gt; ::= &lt;SQL token&gt;... &lt;implementor block&gt; ::= BEGIN &lt;implementor name&gt; &lt;SQL token&gt;... END &lt;implementor name&gt; &lt;implementor name&gt; ::= &lt;identifier&gt; &lt;SQL token&gt; ::= ! an SQL lexical unit specified by the term &quot;&lt;token&gt;&quot; in Sub clause 5.2, &quot;&lt;token&gt; and &lt;separator&gt;&quot;, in ISO/IEC 9075-2."><pre lang="bnf" class="notranslate"><code>&lt;descriptor file&gt; ::= SQLActions &lt;left bracket&gt; &lt;rightbracket&gt; &lt;equal sign&gt; { [ &lt;double quote&gt; &lt;action group&gt; &lt;double quote&gt; [ &lt;comma&gt; &lt;double quote&gt; &lt;action group&gt; &lt;double quote&gt; ] ] } &lt;action group&gt; ::= &lt;install actions&gt; | &lt;remove actions&gt; &lt;install actions&gt; ::= BEGIN INSTALL [ &lt;command&gt; &lt;semicolon&gt; ]... END INSTALL &lt;remove actions&gt; ::= BEGIN REMOVE [ &lt;command&gt; &lt;semicolon&gt; ]... END REMOVE &lt;command&gt; ::= &lt;SQL statement&gt; | &lt;implementor block&gt; &lt;SQL statement&gt; ::= &lt;SQL token&gt;... &lt;implementor block&gt; ::= BEGIN &lt;implementor name&gt; &lt;SQL token&gt;... END &lt;implementor name&gt; &lt;implementor name&gt; ::= &lt;identifier&gt; &lt;SQL token&gt; ::= ! an SQL lexical unit specified by the term "&lt;token&gt;" in Sub clause 5.2, "&lt;token&gt; and &lt;separator&gt;", 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[] = { &quot;BEGIN INSTALL CREATE FUNCTION javatest.java_getTimestamp() RETURNS timestamp AS 'org.postgresql.pljava.example.Parameters.getTimestamp' LANGUAGE java; END INSTALL&quot;, &quot;BEGIN REMOVE DROP FUNCTION javatest.java_getTimestamp(); END REMOVE&quot; }"><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/651934a0ff31911c4af914518df88a4038046f30 2019-01-27T20:50:14-05:00 2019-01-27T20:50:14-05:00 Thoughts on logging jcflack <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 &quot;ITU-T bulletin 994&quot; 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(&quot;You''ve tried to divide {0} by zero&quot;, 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/537b40c0e180bfa2d9a35191e64aae2ac9edc9e6 2018-10-17T02:02:42-04:00 2018-10-17T02:02:42-04:00 Performance tuning jcflack <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 &quot;dbname=postgres options='-c pljava.libjvm_location=/path/to/oracle/.../libjvm.so'&quot; EXPLAIN ANALYZE SELECT functionOfInterest(); \c &quot;dbname=postgres options='-c pljava.libjvm_location=/path/to/openj9/.../libjvm.so'&quot; 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 &quot;.&quot;) AS p, &quot;xmltable&quot;('//*[string-length(.) eq 6]', PASSING =&gt; p, COLUMNS =&gt; 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">=&gt;</span> p, COLUMNS <span class="pl-k">=&gt;</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 &quot;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'&quot; \c &quot;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'&quot; \c &quot;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'&quot; \c &quot;dbname=postgres options='-c pljava.libjvm_location=/var/tmp/jdk8u162-b12_openj9-0.8.0/jre/lib/amd64/j9vm/libjvm.so'&quot; \c &quot;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'&quot; \c &quot;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'&quot; \c &quot;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'&quot;"><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 =&gt; 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 &quot;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'&quot; \c &quot;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'&quot;"><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: &quot;De-signing&quot; 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 &lt;&lt;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">&lt;&lt;</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 &gt;$i/cpuset.mems done echo 0 &gt;/sys/fs/cgroup/cpuset/1c1t/cpuset.cpus echo 0,1 &gt;/sys/fs/cgroup/cpuset/1c2t/cpuset.cpus echo 0,2 &gt;/sys/fs/cgroup/cpuset/2c2t/cpuset.cpus echo 0-3 &gt;/sys/fs/cgroup/cpuset/2c4t/cpuset.cpus echo 0,2,4,6 &gt;/sys/fs/cgroup/cpuset/4c4t/cpuset.cpus echo 0-7 &gt;/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">&gt;</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">&gt;</span>/sys/fs/cgroup/cpuset/1c1t/cpuset.cpus <span class="pl-c1">echo</span> 0,1 <span class="pl-k">&gt;</span>/sys/fs/cgroup/cpuset/1c2t/cpuset.cpus <span class="pl-c1">echo</span> 0,2 <span class="pl-k">&gt;</span>/sys/fs/cgroup/cpuset/2c2t/cpuset.cpus <span class="pl-c1">echo</span> 0-3 <span class="pl-k">&gt;</span>/sys/fs/cgroup/cpuset/2c4t/cpuset.cpus <span class="pl-c1">echo</span> 0,2,4,6 <span class="pl-k">&gt;</span>/sys/fs/cgroup/cpuset/4c4t/cpuset.cpus <span class="pl-c1">echo</span> 0-7 <span class="pl-k">&gt;</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/97420ffeb82f42147069fc5d074a3b542f16ccdd 2017-07-15T19:24:21-04:00 2017-07-15T19:24:21-04:00 Mapping an sql type to a java class jcflack <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=&quot;javatest&quot;, name=&quot;complextuple&quot;, structure={&quot;x float8&quot;, &quot;y float8&quot;}) 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/d7f1e3e92a11385dda2a89d77901d81a87e0315b 2017-06-20T20:42:57-04:00 2017-06-20T20:42:57-04:00 Packaging tips jcflack <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/e7790d89d177d72b84ff98f5e159d883d7d7cabd 2017-06-20T01:15:33-04:00 2017-06-20T01:15:33-04:00 SQL functions jcflack <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(&lt;jar_url&gt;, &lt;jar_name&gt;, &lt;deploy&gt;);</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(&lt;jar_url&gt;, &lt;jar_name&gt;, &lt;redeploy&gt;);</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(&lt;jar_name&gt;, &lt;undeploy&gt;);</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(&lt;schema&gt;);</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(&lt;schema&gt;, &lt;classpath&gt;);</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(&lt;sql type&gt;, &lt;java class&gt;);</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(&lt;sql type&gt;);</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/4e62c4b3f146ab7de5683fc0f1229e0765b57e65 2017-06-19T21:53:51-04:00 2017-06-19T21:53:51-04:00 Logging jcflack <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( &quot;Time is &quot; + 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/f156fa50ab0c5dee749a647ce36ab120ce081a1e 2017-04-19T22:30:04-04:00 2017-04-19T22:30:04-04:00 Functions returning sets jcflack <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 &lt;type&gt;</code> to do. The <code>&lt;type&gt;</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 &lt;scalar type&gt;</h3><a id="user-content-returning-a-setof-scalar-type" class="anchor" aria-label="Permalink: Returning a SETOF &lt;scalar type&gt;" 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=&quot;javatest&quot;, effects=IMMUTABLE) public static Iterator&lt;String&gt; getNames() { ArrayList&lt;String&gt; names = new ArrayList&lt;&gt;(); names.add(&quot;Lisa&quot;); names.add(&quot;Bob&quot;); names.add(&quot;Bill&quot;); names.add(&quot;Sally&quot;); 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>&lt;<span class="pl-smi">String</span>&gt; <span class="pl-en">getNames</span>() { <span class="pl-smi">ArrayList</span>&lt;<span class="pl-smi">String</span>&gt; <span class="pl-s1">names</span> = <span class="pl-k">new</span> <span class="pl-smi">ArrayList</span>&lt;&gt;(); <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 &lt;complex type&gt;</h3><a id="user-content-returning-a-setof-complex-type" class="anchor" aria-label="Permalink: Returning a SETOF &lt;complex type&gt;" 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 &lt;complex type&gt;</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 &gt;= 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=&quot;javatest&quot;, type=&quot;complexTest&quot;) 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> &gt;= <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(&quot;jdbc:default:connection&quot;) .createStatement(); return m_statement.executeQuery(&quot;SELECT * FROM pg_user WHERE &quot; + m_filter); } public void close() throws SQLException { m_statement.close(); } @Function(schema=&quot;javatest&quot;, type=&quot;pg_user&quot;) public static ResultSetHandle listSupers() { return new Users(&quot;usesuper = true&quot;); } @Function(schema=&quot;javatest&quot;, type=&quot;pg_user&quot;) public static ResultSetHandle listNonSupers() { return new Users(&quot;usesuper = false&quot;); } }"><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/74ececf28f0b7f08ddd1598b09a75ad75f04414b 2016-10-30T18:15:44-04:00 2016-10-30T18:15:44-04:00 Parallel query and PLJava jcflack <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/17f03a14ae689539a5893b31617bc11b32841883 2016-01-29T22:41:22-05:00 2016-01-29T22:41:22-05:00 Creating a scalar udt in java jcflack <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=&quot;javatest&quot;, name=&quot;complex&quot;, 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() == '(' &amp;&amp; tz.nextToken() == StreamTokenizer.TT_NUMBER) { double x = tz.nval; if(tz.nextToken() == ',' &amp;&amp; tz.nextToken() == StreamTokenizer.TT_NUMBER) { double y = tz.nval; if(tz.nextToken() == ')') { return new ComplexScalar(x, y, typeName); } } } throw new SQLException(&quot;Unable to parse complex from string \&quot;&quot; + input + '&quot;'); } 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 + &quot; toString&quot;); 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> &amp;&amp; <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> &amp;&amp; <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/9270215cbf4cc2271c4691f533d33eb69c8d908e 2015-12-22T20:53:04-05:00 2015-12-22T20:47:12-05:00 User guide jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Savepoints jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Function mapping jcflack <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 &quot;Hello, &quot; + toWhom + &quot;!&quot;; } }"><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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Technology in brief jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Running the pl java sample tests jcflack <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 &lt;path including the jdbc driver and test.jar&gt; org.postgresql.pljava.test.Tester"><pre>java -cp <span class="pl-k">&lt;</span>path including the jdbc driver and test.jar<span class="pl-k">&gt;</span> org.postgresql.pljava.test.Tester</pre></div> https://github.com/tada/pljava/wiki/Returning-complex-types/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Returning complex types jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Exception handling jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Default type mapping jcflack <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 &quot;Base = \\&quot;&quot; + base + &quot;\\&quot;, incbase = \\&quot;&quot; + incbase + &quot;\\&quot;, ctime = \\&quot;&quot; + ctime + &quot;\\&quot;&quot;; }"><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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Using jdbc jcflack <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(&quot;jdbc:default:connection&quot;);"><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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Triggers jcflack <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, &quot;can't process STATEMENT events&quot;); if(td.isFiredAfter()) throw new TriggerException(td, &quot;must be fired before event&quot;); if(!td.isFiredByUpdate()) throw new TriggerException(td, &quot;can only process UPDATE events&quot;); ResultSet _new = td.getNew(); String[] args = td.getArguments(); if(args.length != 1) throw new TriggerException(td, &quot;one argument was expected&quot;); _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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Installation guide jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 Complete uninstall jcflack <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/a0ee185ef1c51d4946d3221223424915b1359796 2015-12-22T20:48:35-05:00 2015-12-22T00:41:02-05:00 The choice of JNI jcflack <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 &gt; 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">&gt;</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 &gt; 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">&gt;</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>