All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.postgresql.fastpath.Fastpath Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2003, PostgreSQL Global Development Group
 * See the LICENSE file in the project root for more information.
 */

package org.postgresql.fastpath;

import static org.postgresql.util.internal.Nullness.castNonNull;

import org.postgresql.core.BaseConnection;
import org.postgresql.core.ParameterList;
import org.postgresql.core.QueryExecutor;
import org.postgresql.util.ByteConverter;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

/**
 * 

This class implements the Fastpath api.

* *

This is a means of executing functions embedded in the backend from within a java application.

* *

It is based around the file src/interfaces/libpq/fe-exec.c

* * @deprecated This API is somewhat obsolete, as one may achieve similar performance * and greater functionality by setting up a prepared statement to define * the function call. Then, executing the statement with binary transmission of parameters * and results substitutes for a fast-path function call. */ @Deprecated public class Fastpath { // Java passes oids around as longs, but in the backend // it's an unsigned int, so we use this to make the conversion // of long -> signed int which the backend interprets as unsigned. private static final long NUM_OIDS = 4294967296L; // 2^32 // This maps the functions names to their id's (possible unique just // to a connection). private final Map func = new HashMap(); private final QueryExecutor executor; private final BaseConnection connection; /** * Initialises the fastpath system. * * @param conn BaseConnection to attach to */ public Fastpath(BaseConnection conn) { this.connection = conn; this.executor = conn.getQueryExecutor(); } /** * Send a function call to the PostgreSQL backend. * * @param fnId Function id * @param resultType True if the result is a numeric (Integer or Long) * @param args FastpathArguments to pass to fastpath * @return null if no data, Integer if an integer result, Long if a long result, or byte[] * otherwise * @throws SQLException if a database-access error occurs. * @deprecated please use {@link #fastpath(int, FastpathArg[])} */ @Deprecated public @Nullable Object fastpath(int fnId, boolean resultType, FastpathArg[] args) throws SQLException { // Run it. byte[] returnValue = fastpath(fnId, args); // Interpret results. if (!resultType || returnValue == null) { return returnValue; } if (returnValue.length == 4) { return ByteConverter.int4(returnValue, 0); } else if (returnValue.length == 8) { return ByteConverter.int8(returnValue, 0); } else { throw new PSQLException( GT.tr("Fastpath call {0} - No result was returned and we expected a numeric.", fnId), PSQLState.NO_DATA); } } /** * Send a function call to the PostgreSQL backend. * * @param fnId Function id * @param args FastpathArguments to pass to fastpath * @return null if no data, byte[] otherwise * @throws SQLException if a database-access error occurs. */ public byte @Nullable [] fastpath(int fnId, FastpathArg[] args) throws SQLException { // Turn fastpath array into a parameter list. ParameterList params = executor.createFastpathParameters(args.length); for (int i = 0; i < args.length; ++i) { args[i].populateParameter(params, i + 1); } // Run it. return executor.fastpathCall(fnId, params, connection.getAutoCommit()); } /** * @param name Function name * @param resulttype True if the result is a numeric (Integer or Long) * @param args FastpathArguments to pass to fastpath * @return null if no data, Integer if an integer result, Long if a long result, or byte[] * otherwise * @throws SQLException if something goes wrong * @see #fastpath(int, FastpathArg[]) * @see #fastpath(String, FastpathArg[]) * @deprecated Use {@link #getData(String, FastpathArg[])} if you expect a binary result, or one * of {@link #getInteger(String, FastpathArg[])} or * {@link #getLong(String, FastpathArg[])} if you expect a numeric one */ @Deprecated public @Nullable Object fastpath(String name, boolean resulttype, FastpathArg[] args) throws SQLException { connection.getLogger().log(Level.FINEST, "Fastpath: calling {0}", name); return fastpath(getID(name), resulttype, args); } /** *

Send a function call to the PostgreSQL backend by name.

* *

Note: the mapping for the procedure name to function id needs to exist, usually to an earlier * call to addfunction().

* *

This is the preferred method to call, as function id's can/may change between versions of the * backend.

* *

For an example of how this works, refer to org.postgresql.largeobject.LargeObject

* * @param name Function name * @param args FastpathArguments to pass to fastpath * @return null if no data, byte[] otherwise * @throws SQLException if name is unknown or if a database-access error occurs. * @see org.postgresql.largeobject.LargeObject */ public byte @Nullable [] fastpath(String name, FastpathArg[] args) throws SQLException { connection.getLogger().log(Level.FINEST, "Fastpath: calling {0}", name); return fastpath(getID(name), args); } /** * This convenience method assumes that the return value is an integer. * * @param name Function name * @param args Function arguments * @return integer result * @throws SQLException if a database-access error occurs or no result */ public int getInteger(String name, FastpathArg[] args) throws SQLException { byte[] returnValue = fastpath(name, args); if (returnValue == null) { throw new PSQLException( GT.tr("Fastpath call {0} - No result was returned and we expected an integer.", name), PSQLState.NO_DATA); } if (returnValue.length == 4) { return ByteConverter.int4(returnValue, 0); } else { throw new PSQLException(GT.tr( "Fastpath call {0} - No result was returned or wrong size while expecting an integer.", name), PSQLState.NO_DATA); } } /** * This convenience method assumes that the return value is a long (bigint). * * @param name Function name * @param args Function arguments * @return long result * @throws SQLException if a database-access error occurs or no result */ public long getLong(String name, FastpathArg[] args) throws SQLException { byte[] returnValue = fastpath(name, args); if (returnValue == null) { throw new PSQLException( GT.tr("Fastpath call {0} - No result was returned and we expected a long.", name), PSQLState.NO_DATA); } if (returnValue.length == 8) { return ByteConverter.int8(returnValue, 0); } else { throw new PSQLException( GT.tr("Fastpath call {0} - No result was returned or wrong size while expecting a long.", name), PSQLState.NO_DATA); } } /** * This convenience method assumes that the return value is an oid. * * @param name Function name * @param args Function arguments * @return oid of the given call * @throws SQLException if a database-access error occurs or no result */ public long getOID(String name, FastpathArg[] args) throws SQLException { long oid = getInteger(name, args); if (oid < 0) { oid += NUM_OIDS; } return oid; } /** * This convenience method assumes that the return value is not an Integer. * * @param name Function name * @param args Function arguments * @return byte[] array containing result * @throws SQLException if a database-access error occurs or no result */ public byte @Nullable [] getData(String name, FastpathArg[] args) throws SQLException { return fastpath(name, args); } /** *

This adds a function to our lookup table.

* *

User code should use the addFunctions method, which is based upon a query, rather than hard * coding the oid. The oid for a function is not guaranteed to remain static, even on different * servers of the same version.

* * @param name Function name * @param fnid Function id */ public void addFunction(String name, int fnid) { func.put(name, fnid); } /** *

This takes a ResultSet containing two columns. Column 1 contains the function name, Column 2 * the oid.

* *

It reads the entire ResultSet, loading the values into the function table.

* *

REMEMBER to close() the resultset after calling this!!

* *

Implementation note about function name lookups:

* *

PostgreSQL stores the function id's and their corresponding names in the pg_proc table. To * speed things up locally, instead of querying each function from that table when required, a * HashMap is used. Also, only the function's required are entered into this table, keeping * connection times as fast as possible.

* *

The org.postgresql.largeobject.LargeObject class performs a query upon it's startup, and passes * the returned ResultSet to the addFunctions() method here.

* *

Once this has been done, the LargeObject api refers to the functions by name.

* *

Don't think that manually converting them to the oid's will work. Ok, they will for now, but * they can change during development (there was some discussion about this for V7.0), so this is * implemented to prevent any unwarranted headaches in the future.

* * @param rs ResultSet * @throws SQLException if a database-access error occurs. * @see org.postgresql.largeobject.LargeObjectManager */ public void addFunctions(ResultSet rs) throws SQLException { while (rs.next()) { func.put(castNonNull(rs.getString(1)), rs.getInt(2)); } } /** *

This returns the function id associated by its name.

* *

If addFunction() or addFunctions() have not been called for this name, then an SQLException is * thrown.

* * @param name Function name to lookup * @return Function ID for fastpath call * @throws SQLException is function is unknown. */ public int getID(String name) throws SQLException { Integer id = func.get(name); // may be we could add a lookup to the database here, and store the result // in our lookup table, throwing the exception if that fails. // We must, however, ensure that if we do, any existing ResultSet is // unaffected, otherwise we could break user code. // // so, until we know we can do this (needs testing, on the TODO list) // for now, we throw the exception and do no lookups. if (id == null) { throw new PSQLException(GT.tr("The fastpath function {0} is unknown.", name), PSQLState.UNEXPECTED_ERROR); } return id; } /** * Creates a FastpathArg with an oid parameter. This is here instead of a constructor of * FastpathArg because the constructor can't tell the difference between an long that's really * int8 and a long thats an oid. * * @param oid input oid * @return FastpathArg with an oid parameter */ public static FastpathArg createOIDArg(long oid) { if (oid > Integer.MAX_VALUE) { oid -= NUM_OIDS; } return new FastpathArg((int) oid); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy