Class Node
- java.lang.Object
-
- org.gjt.cuspy.JarX
-
- org.postgresql.pljava.packaging.Node
-
public class Node extends JarX
Subclass the JarX extraction tool to provide aresolve
method that replaces prefixespljava/foo/
in path names stored in the archive with the result ofpg_config --foo
.As this represents a second extra
.class
file that has to be added to the installer jar anyway, it will also contain some methods intended to be useful for tasks related to installation and testing. The idea is not to go overboard, but supply a few methods largely modeled on the most basic ones of PostgreSQL'sPostgresNode.pm
, with the idea that they can be invoked fromjshell
if its classpath includes the installer jar (and pgjdbc-ng).An introduction with examples is available.
Unlike the many capabilities of
PostgresNode.pm
, this only deals in TCP sockets bound tolocalhost
(Java doesn't have Unix sockets out of the box yet) and only a few of the most basic operations.As in JarX itself, some liberties with coding style may be taken here to keep this one extra
.class
file from proliferating into a bunch of them.As the testing-related methods here are intended for ad-hoc or scripted use in
jshell
, they are typically declared to throw any checked exception, without further specifics. There are many overloads of methods namedq
andqp
(mnemonic of query and query-print), to make interactive use injshell
comfortable with just a few static imports.
-
-
Nested Class Summary
-
Nested classes/interfaces inherited from class org.gjt.cuspy.JarX
JarX.Build
-
-
Field Summary
Fields Modifier and Type Field Description static boolean
s_isWindows
True if the platform is determined to be Windows.-
Fields inherited from class org.gjt.cuspy.JarX
ALL, ARCHIVE_CHARSET, archiveCharset, ATOM, BYTES, CHARACTERS, COMMENT, defaultArchiveCharset, defaultExecutePermission, defaultReadPermission, defaultTreatment, defaultUnpackedCharset, defaultWritePermission, DOMAINLITERAL, executePermission, LINES, mainAttributes, manifestCode, manifestName, NONE, OWNER, PATHRESOLVER, PERMISSIONS, QUOTEDSTRING, readPermission, resolverEngine, resolverScript, treatment, TSPECIAL, type, UNPACKED_CHARSET, unpackedCharset, value, writePermission
-
-
Method Summary
Modifier and Type Method Description static <T> T
as(Class<T> clazz, Object o)
Casts o to class clazz, testing it also for null.static ProcessBuilder
asPgCtlInvocation(ProcessBuilder pb)
Adjust the command arguments of aProcessBuilder
that would directly invokepostgres
to start a server, so that it will instead startpostgres
viapg_ctl
.static String[]
classify(Throwable t)
Return an array of threeString
s, element, sqlState, and message, as would be printed byqp(Throwable)
.void
clean_node()
Recursively remove the basedir and its descendants.void
clean_node(boolean keepRoot)
Recursively remove the basedir and its descendants.Connection
connect()
Return aConnection
to the server associated with this Node, using default properties appropriate for this setting.Connection
connect(Map<String,String> suppliedProperties)
Return aConnection
to the server associated with this Node, with suppliedProperties overriding or supplementing the ones that would be passed by default.Connection
connect(Properties p)
Return aConnection
to the server associated with this Node, with supplied properties p overriding or supplementing the ones that would be passed by default.Path
data_dir()
Return the directory name to be used as the PostgreSQL data directory for this node.static boolean
examplesNeedSaxon()
Return true if the examples jar includes theorg.postgresql.pljava.example.saxon.S9
class (meaning the appropriate Saxon jar must be installed and on the classpath first before the examples jar can be deployed, unlesscheck_function_bodies
isoff
to skip dependency checking).void
extract()
Extract the jar contents, just as done in the normal case of running this class withjava -jar
.static Stream<Object>
flattenDiagnostics(Object oneResult)
A flat-mapping function to expand anySQLException
orSQLWarning
instance in a result stream into the stream of possibly multiple linked diagnostics and causes in the encounter order of theSQLException
iterator.static ProcessBuilder
forWindowsCRuntime(ProcessBuilder pb)
Adjust the command arguments of aProcessBuilder
so that they will be recovered correctly on Windows by a target C/C++ program using the argument parsing algorithm of the usual C run-time code, when it is known that the command will not be handled first bycmd
.static int
get_free_port()
Return a TCP port on the loopback interface that is free at the moment this method is called.static Node
get_new_node(String name)
Return a newNode
that can be used to initialize and start a PostgreSQL instance.void
init()
Invokeinitdb
for the node, passing default options appropriate for this setting.void
init(UnaryOperator<ProcessBuilder> tweaks)
Invokeinitdb
for the node, passing default options appropriate for this setting, and tweaks to be applied to theProcessBuilder
before it is started.void
init(Map<String,String> suppliedOptions)
Invokeinitdb
for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default.void
init(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks)
Invokeinitdb
for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default, and tweaks to be applied to theProcessBuilder
before it is started.AutoCloseable
initialized_cluster()
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.AutoCloseable
initialized_cluster(UnaryOperator<ProcessBuilder> tweaks)
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.AutoCloseable
initialized_cluster(Map<String,String> suppliedOptions)
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.AutoCloseable
initialized_cluster(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks)
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.static Stream<Object>
installExamples(Connection c, boolean deploy)
Install the examples jar, under the nameexamples
.static Stream<Object>
installExamplesAndPath(Connection c, boolean deploy)
Install the examples jar, under the nameexamples
, and place it on the class path for schemapublic
.static Stream<Object>
installJar(Connection c, String uri, String jarName, boolean deploy)
Install a jar.static Stream<Object>
installSaxon(Connection c, String repo, String version)
Install a Saxon jar under the namesaxon
, given the path to a local Maven repo and the needed version of Saxon, assuming the jar has been downloaded there already.static Stream<Object>
installSaxonAndExamplesAndPath(Connection c, String repo, String version, boolean deploy)
A four-fer: install Saxon, add it to the class path, then install the examples jar, and update the classpath to include both.static Stream<Object>
installSaxonAndPath(Connection c, String repo, String version)
Install a Saxon jar under the namesaxon
, and place it on the class path for schemapublic
.static boolean
isVoidResultSet(Object o, int rows, int columns)
Predicate testing that an object is aResultSet
that has only columns ofvoid
type, and the expected number of rows and columns.static Stream<Object>
loadPLJava(Connection c)
Load PL/Java (with aLOAD
command, notCREATE EXTENSION
).static void
main(String[] args)
Perform an ordinary installation, usingpg_config
or the corresponding system properties to learn where the files belong, and unpacking the files (not including this class or its ancestors) there.static void
peek(Object o)
Prints an object in the manner ofqp
, but in a way suitable for use inStream.peek
.void
prepareResolver(String v)
Prepare the resolver, ignoring the passed string (ordinarily a script or rules); this resolver's rules are hardcoded.static Stream<Object>
q(Connection c, String sql)
Execute some arbitrary SQLstatic Stream<Object>
q(ParameterMetaData pmd)
Produces aStream
with an element for each parameter of aPreparedStatement
.static Stream<Object>
q(ResultSet rs)
Analogously toq(Statement,...)
, produces aStream
with an element for each row of aResultSet
, interleaved with anySQLWarning
s reported on the result set, or anSQLException
if one is thrown.static Stream<Object>
q(ResultSetMetaData rsmd)
Produces aStream
with an element for each column of aResultSet
.static Stream<Object>
q(Statement s, Callable<Boolean> work)
Produces aStream
of the (in JDBC, possibly multiple) results from someexecute
method on aStatement
.static void
qp(Object o)
Overload ofqp
for direct application to any oneObject
obtained from a result stream.static void
qp(Throwable t)
Print aThrowable
retrieved from a result stream, with special handling forSQLException
andSQLWarning
.static void
qp(Connection c, String sql)
Execute some arbitrary SQL and pass theresult stream
toqp(Stream)
for printing to standard output.static void
qp(ParameterMetaData md)
Overload ofqp
for examiningParameterMetaData
.static void
qp(ResultSet rs)
Overload ofqp
for direct application to aResultSet
.static void
qp(ResultSetMetaData md)
Overload ofqp
for examiningResultSetMetaData
.static void
qp(Statement s, Callable<Boolean> work)
Invoke someexecute
method on aStatement
and pass theresult stream
toqp(Stream)
for printing to standard output.static void
qp(Stream<Object> s)
Print streamed results of aStatement
in (somewhat) readable fashion.static void
qp(Stream<Object> s, Function<Object,Stream<Object>> flattener)
Print streamed results of aStatement
in (somewhat) readable fashion, with a choice of flattener for diagnostics.static Stream<Object>
removeJar(Connection c, String jarName, boolean undeploy)
Remove a jar.String
resolve(String storedPath, String platformPath)
Replaces a prefixpljava/
key in a path to be extracted with the value of thepgconfig.
key system property, or the result of invokingpg_config
(or the exact executable named in thepgconfig
system property, if present) with the option--
key.static Stream<Object>
semiFlattenDiagnostics(Object oneResult)
A flat-mapping function to expand anySQLException
orSQLWarning
instance in a result stream into the stream of possibly multiple linked diagnostics in the order produced bygetNextException
orgetNextWarning
.static Stream<Object>
setClasspath(Connection c, String schema, String... jarNames)
Set the class path for a schema.static Stream<Object>
setConfig(Connection c, String settingName, String newValue, boolean isLocal)
Set a configuration variable on the server.void
start()
Start a PostgreSQL server for the node with default options appropriate for this setting.void
start(UnaryOperator<ProcessBuilder> tweaks)
Start a PostgreSQL server for the node, passing default options appropriate for this setting, and tweaks to be applied to theProcessBuilder
before it is started.void
start(Map<String,String> suppliedOptions)
Start a PostgreSQL server for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default.void
start(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks)
Start a PostgreSQL server for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default, and tweaks to be applied to theProcessBuilder
before it is started.AutoCloseable
started_server()
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.AutoCloseable
started_server(UnaryOperator<ProcessBuilder> tweaks)
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.AutoCloseable
started_server(Map<String,String> suppliedOptions)
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.AutoCloseable
started_server(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks)
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.static boolean
stateMachine(String name, Consumer<String> reporter, Stream<Object> input, InvocationHandler... states)
Executes a state machine specified in the form of a list of lambdas representing its states, to verify that aresult stream
is as expected.void
stop()
Stop the server instance associated with this Node.void
stop(UnaryOperator<ProcessBuilder> tweaks)
Stop the server instance associated with this Node.String
toString()
Identifying information for a "node" instance, or for the singleton extractor instance.void
use_pg_ctl(boolean setting)
Indicate whether to usepg_ctl
to start and stop the server (if true), or startpostgres
and stop it directly (if false, the default).static int[]
voidResultSetDims(Object o)
Determines whether an object is aResultSet
with no columns of any type other thanvoid
, to allow abbreviated output of result sets produced by the common case of queries that callvoid
functions.-
Methods inherited from class org.gjt.cuspy.JarX
archiveCharsetFromType, classify, describeTranscoding, extract, holds, holdsIgnoreCase, is, notMe, setDefaults, shovel, shovelBytes, shovelChars, shovelLines, shovelText, structuredFieldBody
-
-
-
-
Field Detail
-
s_isWindows
public static final boolean s_isWindows
True if the platform is determined to be Windows.On Windows,
forWindowsCRuntime
should be applied to anyProcessBuilder
before invoking it; the details of the transformation applied byasPgCtlInvocation
change, anduse_pg_ctl
may prove useful, aspg_ctl
on Windows is able to drop administrative privileges that would otherwise preventpostgres
from starting.
-
-
Method Detail
-
main
public static void main(String[] args) throws Exception
Perform an ordinary installation, usingpg_config
or the corresponding system properties to learn where the files belong, and unpacking the files (not including this class or its ancestors) there.- Throws:
Exception
-
extract
public void extract() throws Exception
Extract the jar contents, just as done in the normal case of running this class withjava -jar
.Only to be called on the singleton instance
s_jarxHelper
.For a version that doesn't really extract anything, but still primes the
resolve
method to know where things should be extracted, seedryExtract()
.
-
prepareResolver
public void prepareResolver(String v) throws Exception
Prepare the resolver, ignoring the passed string (ordinarily a script or rules); this resolver's rules are hardcoded.- Overrides:
prepareResolver
in classJarX
- Parameters:
v
- value of the _JarX_PathResolver main attribute- Throws:
Exception
- this implementation throws no checked exceptions, but an overriding implementation may
-
resolve
public String resolve(String storedPath, String platformPath) throws Exception
Replaces a prefixpljava/
key in a path to be extracted with the value of thepgconfig.
key system property, or the result of invokingpg_config
(or the exact executable named in thepgconfig
system property, if present) with the option--
key.- Overrides:
resolve
in classJarX
- Parameters:
storedPath
- The path as stored in the archive, always /-separatedplatformPath
- The path after only replacing / with the platform separator- Returns:
- plat unchanged, or a corrected location for extracting the entry, or null to suppress extracting the entry
- Throws:
Exception
- this implementation may throw ScriptException, an overriding implementation may throw others
-
toString
public String toString()
Identifying information for a "node" instance, or for the singleton extractor instance.
-
get_new_node
public static Node get_new_node(String name) throws Exception
Return a newNode
that can be used to initialize and start a PostgreSQL instance.Establishes a VM shutdown hook that will stop the server (if started) and recursively remove the basedir before the VM exits.
- Throws:
Exception
-
get_free_port
public static int get_free_port() throws Exception
Return a TCP port on the loopback interface that is free at the moment this method is called.- Throws:
Exception
-
clean_node
public void clean_node() throws Exception
Recursively remove the basedir and its descendants.- Throws:
Exception
-
clean_node
public void clean_node(boolean keepRoot) throws Exception
Recursively remove the basedir and its descendants.- Parameters:
keepRoot
- if true, the descendants are removed, but not the basedir itself.- Throws:
Exception
-
data_dir
public Path data_dir()
Return the directory name to be used as the PostgreSQL data directory for this node.
-
initialized_cluster
public AutoCloseable initialized_cluster() throws Exception
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.- Throws:
Exception
-
initialized_cluster
public AutoCloseable initialized_cluster(Map<String,String> suppliedOptions) throws Exception
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.- Throws:
Exception
-
initialized_cluster
public AutoCloseable initialized_cluster(UnaryOperator<ProcessBuilder> tweaks) throws Exception
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.- Throws:
Exception
-
initialized_cluster
public AutoCloseable initialized_cluster(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks) throws Exception
Likeinit()
but returns anAutoCloseable
that will recursively remove the files and directories under the basedir (but not the basedir itself) on the exit of a calling try-with-resources scope.- Throws:
Exception
-
init
public void init() throws Exception
Invokeinitdb
for the node, passing default options appropriate for this setting.- Throws:
Exception
-
init
public void init(Map<String,String> suppliedOptions) throws Exception
Invokeinitdb
for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default.- Throws:
Exception
-
init
public void init(UnaryOperator<ProcessBuilder> tweaks) throws Exception
Invokeinitdb
for the node, passing default options appropriate for this setting, and tweaks to be applied to theProcessBuilder
before it is started.- Throws:
Exception
-
init
public void init(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks) throws Exception
Invokeinitdb
for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default, and tweaks to be applied to theProcessBuilder
before it is started.By default,
postgres
will be the name of the superuser, UTF-8 will be the encoding,auth-local
will bepeer
andauth-host
will bemd5
. The initialization will skipfsync
for speed rather than safety (if something goes wrong, justclean_node()
and start over).The
initdb
that will be run is the one in thebindir
reported bypg_config
(or set by-Dpgconfig.bindir
).- Parameters:
suppliedOptions
- a Map where each key is an option to initdb (for example, --encoding), and the value corresponds.tweaks
- a lambda applicable to theProcessBuilder
to further configure it.- Throws:
Exception
-
started_server
public AutoCloseable started_server() throws Exception
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.- Throws:
Exception
-
started_server
public AutoCloseable started_server(Map<String,String> suppliedOptions) throws Exception
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.- Throws:
Exception
-
started_server
public AutoCloseable started_server(UnaryOperator<ProcessBuilder> tweaks) throws Exception
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.- Throws:
Exception
-
started_server
public AutoCloseable started_server(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks) throws Exception
Likestart()
but returns anAutoCloseable
that will stop the server on the exit of a calling try-with-resources scope.Supplied tweaks will be applied to the
ProcessBuilder
used to start the server; ifpg_ctl
is being used, they will also be applied when runningpg_ctl stop
to stop it.- Throws:
Exception
-
start
public void start() throws Exception
Start a PostgreSQL server for the node with default options appropriate for this setting.- Throws:
Exception
-
start
public void start(Map<String,String> suppliedOptions) throws Exception
Start a PostgreSQL server for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default.- Throws:
Exception
-
start
public void start(UnaryOperator<ProcessBuilder> tweaks) throws Exception
Start a PostgreSQL server for the node, passing default options appropriate for this setting, and tweaks to be applied to theProcessBuilder
before it is started.- Throws:
Exception
-
start
public void start(Map<String,String> suppliedOptions, UnaryOperator<ProcessBuilder> tweaks) throws Exception
Start a PostgreSQL server for the node, with suppliedOptions overriding or supplementing the ones that would be passed by default, and tweaks to be applied to theProcessBuilder
before it is started.By default, the server will listen only on the loopback interface and not on any Unix-domain socket, on the port selected when this Node was created, and for a maximum of 16 connections. Its cluster name will be the name given to this Node, and fsync will be off to favor speed over durability. The log line prefix will be shortened to just the node name and (when connected) the
application_name
.The server that will be run is the one in the
bindir
reported bypg_config
(or set by-Dpgconfig.bindir
).If the server is PostgreSQL 10 or later, it is definitely ready to accept connections when this method returns. If not, it is highly likely to be ready, but no test connection has been made to confirm it.
- Parameters:
suppliedOptions
- a Map where the key is a configuration variable name as seen inpostgresql.conf
or passed to the server with-c
and the value corresponds.tweaks
- a lambda applicable to theProcessBuilder
to further configure it.- Throws:
Exception
-
stop
public void stop() throws Exception
Stop the server instance associated with this Node.Has the effect of
stop(tweaks)
without any tweaks.- Throws:
Exception
-
stop
public void stop(UnaryOperator<ProcessBuilder> tweaks) throws Exception
Stop the server instance associated with this Node.No effect if it has not been started or has already been stopped, but a message to standard error is logged if the server had been started and the process is found to have exited unexpectedly.
- Parameters:
tweaks
- tweaks to apply to a ProcessBuilder; unused unless pg_ctl will be used to stop the server- Throws:
Exception
-
use_pg_ctl
public void use_pg_ctl(boolean setting)
Indicate whether to usepg_ctl
to start and stop the server (if true), or startpostgres
and stop it directly (if false, the default).On Windows,
pg_ctl
is able to drop administrator rights and start the server from an account that would otherwise trigger the server's refusal to start from a privileged account.
-
connect
public Connection connect() throws Exception
Return aConnection
to the server associated with this Node, using default properties appropriate for this setting.- Throws:
Exception
-
connect
public Connection connect(Map<String,String> suppliedProperties) throws Exception
Return aConnection
to the server associated with this Node, with suppliedProperties overriding or supplementing the ones that would be passed by default.- Throws:
Exception
-
connect
public Connection connect(Properties p) throws Exception
Return aConnection
to the server associated with this Node, with supplied properties p overriding or supplementing the ones that would be passed by default.By default, the connection is to the
postgres
database as thepostgres
user, using the password internally generated for this node, and with anapplication_name
generated from a counter of connections for this node.- Throws:
Exception
-
setConfig
public static Stream<Object> setConfig(Connection c, String settingName, String newValue, boolean isLocal) throws Exception
Set a configuration variable on the server.This deserves a convenience method because the most familiar PostgreSQL syntax for SET doesn't lend itself to parameterization.
- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
loadPLJava
public static Stream<Object> loadPLJava(Connection c) throws Exception
Load PL/Java (with aLOAD
command, notCREATE EXTENSION
).This was standard procedure in PostgreSQL versions that pre-dated the extension support. It is largely obsolete with the advent of
CREATE EXTENSION
, but still has one distinct use case: this is what will work if you do not have administrative access to install PL/Java's files in the standard directories whereCREATE EXTENSION
expects them, but can only place them in some other location the server can read. Then you simply have to make sure thatpljava.module_path
is set correctly to locate the jar files, and give the correct shared-object path toLOAD
(which this method does).- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
installJar
public static Stream<Object> installJar(Connection c, String uri, String jarName, boolean deploy) throws Exception
Install a jar.- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
removeJar
public static Stream<Object> removeJar(Connection c, String jarName, boolean undeploy) throws Exception
Remove a jar.- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
setClasspath
public static Stream<Object> setClasspath(Connection c, String schema, String... jarNames) throws Exception
Set the class path for a schema.- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
q
public static Stream<Object> q(Connection c, String sql) throws Exception
Execute some arbitrary SQL- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
q
public static Stream<Object> q(Statement s, Callable<Boolean> work) throws Exception
Produces aStream
of the (in JDBC, possibly multiple) results from someexecute
method on aStatement
.This is how, for example, to prepare, then examine the results of, a
PreparedStatement
:PreparedStatement ps = conn.prepareStatement("select foo(?,?)"); ps.setInt(1, 42); ps.setString(2, "surprise!"); q(ps, ps::execute);
Each result in the stream will be an instance of one of:
ResultSet
,Long
(an update count, positive or zero),SQLWarning
, or some otherSQLException
. A warning or exception may have others chained to it, which its owniterator
orforEach
methods should be used to traverse; or, useflatMap(
Node::flattenDiagnostics
) to obtain a stream presenting each diagnostic in a chain in turn. TheCallable
interface supplying the work to be done allows any checked exception, but anyThrowable
outside theSQLException
hierarchy will simply be rethrown from here rather than delivered in the stream. AnyThrowable
thrown by work will result in theStatement
being closed. Otherwise, it remains open until the returned stream is closed.Exists mainly to encapsulate the rather fiddly logic of extracting that sequence of results using the
Statement
API.- Parameters:
s
- the Statement from which to extract resultswork
- a Callable that will invoke one of the Statement's execute methods returning a boolean that indicates whether the first result is a ResultSet. Although the Callable interface requires the boolean result to be boxed, it must not return null.- Returns:
- a Stream as described above.
- Throws:
Exception
-
q
public static Stream<Object> q(ResultSet rs) throws Exception
Analogously toq(Statement,...)
, produces aStream
with an element for each row of aResultSet
, interleaved with anySQLWarning
s reported on the result set, or anSQLException
if one is thrown.This is supplied chiefly for use driving a
state machine
to verify contents of a result set. For each row, the element in the stream will be an instance ofLong
, counting up from 1 (intended to match the result set'sgetRow
but without relying on it, as JDBC does not require every implementation to support it). By itself, of course, this does not convey any of the content of the row; the lambdas representing the machine states should close over the result set and query it for content, perhaps not even using the object supplied here (except to detect when it is a warning or exception rather than a row number). The row position of the result set will have been updated, and should not be otherwise modified when this method is being used to walk through the results.For the same reason, don't try any funny business like sorting the stream in any way. The
ResultSet
will only be read forward, and each row only once. Simple filtering,dropWhile
/takeWhile
, and so on will work, but may be more conveniently rolled into the design of astate machine
, as nearly any use of aResultSet
can throwSQLException
and therefore isn't convenient in the stream API.Passing this result to
qp
as if it came from aStatement
could lead to confusion, as theLong
elements would be printed as update counts rather than row numbers.- Parameters:
rs
- a ResultSet- Returns:
- a Stream as described above
- Throws:
Exception
-
q
public static Stream<Object> q(ResultSetMetaData rsmd) throws Exception
Produces aStream
with an element for each column of aResultSet
.This is another convenience method for use chiefly in driving a
state machine
to check per-column values or metadata for aResultSet
. It is, in fact, nothing other thanIntStream.rangeClosed(1, rsmd.getColumnCount()).boxed()
but typed asStream<Object>
.As with
q(ResultSet)
, the column number supplied here conveys no actual column data or metadata. The lambdas representing the machine states should close over theResultSetMetaData
or correspondingResultSet
object, or both, and use the column number from this stream to index them.- Parameters:
rsmd
- a ResultSetMetaData object- Returns:
- a Stream as described above
- Throws:
Exception
-
q
public static Stream<Object> q(ParameterMetaData pmd) throws Exception
Produces aStream
with an element for each parameter of aPreparedStatement
.This is another convenience method for use chiefly in driving a
state machine
to check per-parameter metadata. It is, in fact, nothing other thanIntStream.rangeClosed(1, rsmd.getParameterCount()).boxed()
but typed asStream<Object>
.As with
q(ResultSet)
, the column number supplied here conveys no actual parameter metadata. The lambdas representing the machine states should close over theParameterMetaData
object and use the parameter number from this stream to index it.- Parameters:
pmd
- a ParameterMetaData object- Returns:
- a Stream as described above
- Throws:
Exception
-
qp
public static void qp(Connection c, String sql) throws Exception
Execute some arbitrary SQL and pass theresult stream
toqp(Stream)
for printing to standard output.- Throws:
Exception
-
qp
public static void qp(Statement s, Callable<Boolean> work) throws Exception
Invoke someexecute
method on aStatement
and pass theresult stream
toqp(Stream)
for printing to standard output.This is how, for example, to prepare, then print the results of, a
PreparedStatement
:PreparedStatement ps = conn.prepareStatement("select foo(?,?)"); ps.setInt(1, 42); ps.setString(2, "surprise!"); qp(ps, ps::execute);
TheStatement
will be closed.- Throws:
Exception
-
examplesNeedSaxon
public static boolean examplesNeedSaxon() throws Exception
Return true if the examples jar includes theorg.postgresql.pljava.example.saxon.S9
class (meaning the appropriate Saxon jar must be installed and on the classpath first before the examples jar can be deployed, unlesscheck_function_bodies
isoff
to skip dependency checking).- Throws:
Exception
-
installExamples
public static Stream<Object> installExamples(Connection c, boolean deploy) throws Exception
Install the examples jar, under the nameexamples
.The jar is specified by a
file:
URI and the path is the one where this installer installed (or would have installed) it.- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
installExamplesAndPath
public static Stream<Object> installExamplesAndPath(Connection c, boolean deploy) throws Exception
Install the examples jar, under the nameexamples
, and place it on the class path for schemapublic
.The return of a concatenated result stream from two consecutive statements might be likely to fail in cases where the first statement has any appreciable data to return, but pgjdbc-ng seems to handle it at least in this case where each statement just returns one row / one column of
void
. And it is convenient.- Returns:
- a combined
result stream
from executing the statements - Throws:
Exception
-
installSaxon
public static Stream<Object> installSaxon(Connection c, String repo, String version) throws Exception
Install a Saxon jar under the namesaxon
, given the path to a local Maven repo and the needed version of Saxon, assuming the jar has been downloaded there already.- Returns:
- a
result stream
from executing the statement - Throws:
Exception
-
installSaxonAndPath
public static Stream<Object> installSaxonAndPath(Connection c, String repo, String version) throws Exception
Install a Saxon jar under the namesaxon
, and place it on the class path for schemapublic
.- Returns:
- a combined
result stream
from executing the statements - Throws:
Exception
-
installSaxonAndExamplesAndPath
public static Stream<Object> installSaxonAndExamplesAndPath(Connection c, String repo, String version, boolean deploy) throws Exception
A four-fer: install Saxon, add it to the class path, then install the examples jar, and update the classpath to include both.- Parameters:
repo
- the base directory of a local Maven repository into which the Saxon jar has been downloadedversion
- the needed version of Saxondeploy
- whether to run the example jar's deployment code- Returns:
- a combined
result stream
from executing the statements - Throws:
Exception
-
flattenDiagnostics
public static Stream<Object> flattenDiagnostics(Object oneResult)
A flat-mapping function to expand anySQLException
orSQLWarning
instance in a result stream into the stream of possibly multiple linked diagnostics and causes in the encounter order of theSQLException
iterator.Any other object is returned in a singleton stream.
To flatten just the chain of
SQLWarning
orSQLException
but with each of those retaining its own list ofcause
s, seesemiFlattenDiagnostics
.
-
semiFlattenDiagnostics
public static Stream<Object> semiFlattenDiagnostics(Object oneResult)
A flat-mapping function to expand anySQLException
orSQLWarning
instance in a result stream into the stream of possibly multiple linked diagnostics in the order produced bygetNextException
orgetNextWarning
.Unlike
flattenDiagnostics
, this method does not descend into chains of causes; those may be retrieved in the usual way from the throwables returned on this stream.Any other object is returned in a singleton stream.
-
qp
public static void qp(Stream<Object> s) throws Exception
Print streamed results of aStatement
in (somewhat) readable fashion.Uses
writeXml
ofWebRowSet
, which is very verbose, but about the easiest way to readably dump aResultSet
in just a couple lines of code.The supplied stream is flattened (see
semiFlattenDiagnostics
) so that any chainedSQLException
s orSQLWarning
s are printed in sequence.- Throws:
Exception
-
qp
public static void qp(Stream<Object> s, Function<Object,Stream<Object>> flattener) throws Exception
Print streamed results of aStatement
in (somewhat) readable fashion, with a choice of flattener for diagnostics.For flattener, see
flattenDiagnostics
orsemiFlattenDiagnostics
.- Throws:
Exception
-
qp
public static void qp(Object o) throws Exception
Overload ofqp
for direct application to any oneObject
obtained from a result stream.Simply applies the specialized treatment appropriate to the class of the object.
- Throws:
Exception
-
peek
public static void peek(Object o)
Prints an object in the manner ofqp
, but in a way suitable for use inStream.peek
.If o is a
ResultSet
, only its metadata will be printed; its position will not be disturbed and it will not be closed. This method throws no checked exceptions, as theStream
API requires; any that is caught will be printed as if byqp
.
-
qp
public static void qp(ResultSet rs) throws Exception
Overload ofqp
for direct application to aResultSet
.Sometimes one has a
ResultSet
that didn't come from executing a query, such as from a JDBC metadata method. This prints it the same wayqp
on a query result would. TheResultSet
is not closed (but will have been read through the last row).A result set with no columns of type other than
void
will be printed in an abbreviated form, showing its number of rows and columns as reported byvoidResultSetDims
.- Throws:
Exception
-
qp
public static void qp(ParameterMetaData md) throws Exception
Overload ofqp
for examiningParameterMetaData
.Continuing in the spirit of getting something reasonably usable without a lot of code, this fakes up a
ResultSetMetaData
with the same values present in theParameterMetaData
(and nothing for the ones that aren't, like names), and then usesWebRowSet.writeXml
as if dumping a result set.For getting a quick idea what the parameters are, it's good enough.
- Throws:
Exception
-
qp
public static void qp(ResultSetMetaData md) throws Exception
Overload ofqp
for examiningResultSetMetaData
.This makes an empty
WebRowSet
with the copied metadata, and dumps it withwriteXml
. Owing to a few missing setters on Java'sRowSetMetaDataImpl
, a fewResultSetMetaData
attributes will not have been copied; they'll be wrong (unless the real values happen to match the defaults). That could be fixed by extending that class, but that would require yet another extra class file added to the installer jar.- Throws:
Exception
-
qp
public static void qp(Throwable t)
Print aThrowable
retrieved from a result stream, with special handling forSQLException
andSQLWarning
.In keeping with the XMLish vibe established by
qp
for other items in a result stream, this will render aThrowable
as anerror
,warning
, orinfo
element (PostgreSQL's finer distinctions of severity are not exposed by pgjdbc-ng's API.)An element will have a
message
attribute if it has a message. It will have acode
attribute containing the SQLState, if it is an instance ofSQLException
, unless it is rendered as aninfo
element and the state is00000
. An instance ofSQLWarning
will be rendered as awarning
unless its class (two leftmost code positions) is00
, in which case it will beinfo
. Anything else is anerror
.
-
classify
public static String[] classify(Throwable t)
Return an array of threeString
s, element, sqlState, and message, as would be printed byqp(Throwable)
.The first string will be: (1) if the throwable is an
SQLWarning
, "info" if its class (leftmost two positions of SQLState) is 00, otherwise "warning"; (2) for any other throwable, "error". These are constant strings and therefore interned.The second string will be null if the throwable is outside the
SQLException
hierarchy, or if the first string is "info" and the SQLState is exactly 00000; otherwise it will be the SQLState.The third string will be as returned by
getMessage
, and may be null if the throwable was not constructed with a message.
-
voidResultSetDims
public static int[] voidResultSetDims(Object o) throws Exception
Determines whether an object is aResultSet
with no columns of any type other thanvoid
, to allow abbreviated output of result sets produced by the common case of queries that callvoid
functions.Returns null if o is not a
ResultSet
, or if its columns are not all ofvoid
type. Otherwise, returns a two-element integer array giving the rows (index 0 in the array) and columns (index 1) of the result set.If this method returns non-null, the result set is left positioned on its last row.
- Parameters:
o
- Object to check- Returns:
- null or a two-element int[], as described above
- Throws:
Exception
-
isVoidResultSet
public static boolean isVoidResultSet(Object o, int rows, int columns) throws Exception
Predicate testing that an object is aResultSet
that has only columns ofvoid
type, and the expected number of rows and columns.The expected result of a query that calls one
void
-typed, non-set-returning function could be checked withisVoidResultSet(rs, 1, 1)
.- Throws:
Exception
-
stateMachine
public static boolean stateMachine(String name, Consumer<String> reporter, Stream<Object> input, InvocationHandler... states) throws Exception
Executes a state machine specified in the form of a list of lambdas representing its states, to verify that aresult stream
is as expected.Treats the list of lambdas as a set of consecutively-numbered states (the first in the list is state number 1, and is the initial state). At each step of the machine, the current state is applied to the current input object, and may return an
Integer
or aBoolean
.If an integer, its absolute value selects the next state. A positive integer consumes the current input item, so the next state will be applied to the next item of input. A negative integer transitions to the selected next state without consuming the current input item, so it will be examined again in the newly selected state.
If boolean,
false
indicates that the machine cannot proceed; the supplied reporter will be passed an explanatory string and this method returns false. A state that returnstrue
indicates the machine has reached an accepting state.No item of input is allowed to be null; null is reserved to be the end-of-input symbol. If a state returns
true
(accept) when applied to null at the end of input, the machine has matched and this method returns true. A state may also return a negative integer in this case, to shift to another state while looking at the end of input. A positive integer (attempting to consume the end of input), or a false, return will cause an explanatory message to the reporter and a false return from this method.A state may return
true
(accept) when looking at a non-null input item, but the input will be checked to confirm it has no more elements. Otherwise, the machine has tried to accept before matching all the input, and this method will return false.To avoid defining a new functional interface, each state is represented by
InvocationHandler
, an existing functional interface with a versatile argument list and permissivethrows
clause. Each state must be represented as a lambda with three parameters (the convention(o,p,q)
is suggested), of which only the first is used. If Java ever completes the transition to_
as an unused-parameter marker, the suggested convention will be(o,_,_)
.As the input item passed to each state is typed
Object
, and as null can only represent the end of input, it may be common for a state to both cast an input to an expected type and confirm it is not null. Theas
method combines those operations. If its argument either is null or cannot be cast to the wanted type,as
will throw a specific instance ofClassCastException
, which will be treated, when caught bystateMachine
, just as if the state had returnedfalse
.- Parameters:
name
- A name for this state machine, used only in exception messages if it fails to match all the inputreporter
- a Consumer to accept a diagnostic string if the machine fails to match, defaulting if null to System.err::printlninput
- A Stream of input items, of which none may be nullstates
- Lambdas representing states of the machine- Returns:
- true if an accepting state was reached coinciding with the end of input
- Throws:
Exception
- Anything that could be thrown during evaluation of the input stream or any state
-
as
public static <T> T as(Class<T> clazz, Object o)
Casts o to class clazz, testing it also for null.This is meant as a shorthand in implementing states for
stateMachine
. If o either is null or is not castable to the desired type, a distinguished instance ofClassCastException
will be thrown, which is treated specially if caught bystateMachine
while evaluating a state.
-
forWindowsCRuntime
public static ProcessBuilder forWindowsCRuntime(ProcessBuilder pb)
Adjust the command arguments of aProcessBuilder
so that they will be recovered correctly on Windows by a target C/C++ program using the argument parsing algorithm of the usual C run-time code, when it is known that the command will not be handled first bycmd
.This transformation must account for the way the C runtime will ultimately parse the parameters apart, and also for the behavior of Java's runtime in assembling the command line that the invoked process will receive.
- Parameters:
pb
- a ProcessBuilder whose command has been set to an executable that parses parameters using the C runtime rules, and arguments as they should result from parsing.- Returns:
- The same ProcessBuilder, with the argument list rewritten as necessary to produce the original list as a result of Windows C runtime parsing,
- Throws:
IllegalArgumentException
- if the ProcessBuilder does not have at least the first command element (the executable to run)UnsupportedOperationException
- if the arguments passed, or system properties in effect, produce a case this transformation cannot handle
-
asPgCtlInvocation
public static ProcessBuilder asPgCtlInvocation(ProcessBuilder pb)
Adjust the command arguments of aProcessBuilder
that would directly invokepostgres
to start a server, so that it will instead startpostgres
viapg_ctl
.pg_ctl
constructs a command line forcmd.exe
(on Windows) or/bin/sh
(elsewhere), which in turn will launchpostgres
. The waypg_ctl
handles options (-o
) requires this transformation to be platform-aware and quote them correctly forsh
orcmd
as appropriate.The result of this transformation still has to be received intact by
pg_ctl
itself, which requires (on Windows) a subsequent application offorWindowsCRuntime
as well.- Parameters:
pb
- a ProcessBuilder whose command has been set to an executable path forpostgres
, with only-D
and-c
options.- Returns:
- The same ProcessBuilder, with the argument list rewritten to
invoke
pg_ctl start
with the same-D
and any other options supplied by-o
. - Throws:
IllegalArgumentException
- if the ProcessBuilder does not have at least the first command element (the executable to run)UnsupportedOperationException
- if the arguments passed produce a case this transformation cannot handle
-
-