mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-09 08:10:09 +08:00
Enhancements to how queries with bind values are stored internally and sent to
the server. Previously we allocated a new String object for the entire final query we were sending to the database. If you had a big query, or especially if you had large bind values you ended up with essentially two copies in memory. This change will reuse the existing objects and therefore should take 1/2 the memory it does today for a given query. This restructuring will also allow in the future the ability to stream bytea data to the server instead of the current approach of pulling it all into memory. I also fixed a test that was failing on a 7.2 database. Also renamed some internal variables and some minor cleanup. Modified Files: jdbc/org/postgresql/core/QueryExecutor.java jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java jdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java jdbc/org/postgresql/test/jdbc2/DatabaseMetaDataTest.java
This commit is contained in:
parent
a2a3192802
commit
fe2dec75a9
@ -13,24 +13,26 @@ import org.postgresql.util.PSQLException;
|
|||||||
* <p>The lifetime of a QueryExecutor object is from sending the query
|
* <p>The lifetime of a QueryExecutor object is from sending the query
|
||||||
* until the response has been received from the backend.
|
* until the response has been received from the backend.
|
||||||
*
|
*
|
||||||
* $Id: QueryExecutor.java,v 1.13 2002/07/23 03:59:55 barry Exp $
|
* $Id: QueryExecutor.java,v 1.14 2002/08/23 20:45:49 barry Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class QueryExecutor
|
public class QueryExecutor
|
||||||
{
|
{
|
||||||
|
|
||||||
private final String sql;
|
private final String[] m_sqlFrags;
|
||||||
|
private final Object[] m_binds;
|
||||||
private final java.sql.Statement statement;
|
private final java.sql.Statement statement;
|
||||||
private final PG_Stream pg_stream;
|
private final PG_Stream pg_stream;
|
||||||
private final org.postgresql.jdbc1.AbstractJdbc1Connection connection;
|
private final org.postgresql.jdbc1.AbstractJdbc1Connection connection;
|
||||||
|
|
||||||
public QueryExecutor(String sql,
|
public QueryExecutor(String[] p_sqlFrags, Object[] p_binds,
|
||||||
java.sql.Statement statement,
|
java.sql.Statement statement,
|
||||||
PG_Stream pg_stream,
|
PG_Stream pg_stream,
|
||||||
java.sql.Connection connection)
|
java.sql.Connection connection)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
this.sql = sql;
|
this.m_sqlFrags = p_sqlFrags;
|
||||||
|
this.m_binds = p_binds;
|
||||||
this.statement = statement;
|
this.statement = statement;
|
||||||
this.pg_stream = pg_stream;
|
this.pg_stream = pg_stream;
|
||||||
this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection;
|
this.connection = (org.postgresql.jdbc1.AbstractJdbc1Connection)connection;
|
||||||
@ -60,7 +62,7 @@ public class QueryExecutor
|
|||||||
synchronized (pg_stream)
|
synchronized (pg_stream)
|
||||||
{
|
{
|
||||||
|
|
||||||
sendQuery(sql);
|
sendQuery();
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
boolean l_endQuery = false;
|
boolean l_endQuery = false;
|
||||||
@ -129,12 +131,18 @@ public class QueryExecutor
|
|||||||
/*
|
/*
|
||||||
* Send a query to the backend.
|
* Send a query to the backend.
|
||||||
*/
|
*/
|
||||||
private void sendQuery(String query) throws SQLException
|
private void sendQuery() throws SQLException
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pg_stream.SendChar('Q');
|
pg_stream.SendChar('Q');
|
||||||
pg_stream.Send(connection.getEncoding().encode(query));
|
for (int i = 0 ; i < m_binds.length ; ++i) {
|
||||||
|
if (m_binds[i] == null)
|
||||||
|
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
|
||||||
|
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[i]));
|
||||||
|
pg_stream.Send(connection.getEncoding().encode(m_binds[i].toString()));
|
||||||
|
}
|
||||||
|
pg_stream.Send(connection.getEncoding().encode(m_sqlFrags[m_binds.length]));
|
||||||
pg_stream.SendChar(0);
|
pg_stream.SendChar(0);
|
||||||
pg_stream.flush();
|
pg_stream.flush();
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ import org.postgresql.largeobject.LargeObjectManager;
|
|||||||
import org.postgresql.util.*;
|
import org.postgresql.util.*;
|
||||||
|
|
||||||
|
|
||||||
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.4 2002/08/16 19:34:57 davec Exp $
|
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.5 2002/08/23 20:45:49 barry Exp $
|
||||||
* This class defines methods of the jdbc1 specification. This class is
|
* This class defines methods of the jdbc1 specification. This class is
|
||||||
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
|
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
|
||||||
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
|
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
|
||||||
@ -426,7 +426,26 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
|
|||||||
*/
|
*/
|
||||||
public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException
|
public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException
|
||||||
{
|
{
|
||||||
return new QueryExecutor(sql, stat, pg_stream, (java.sql.Connection)this).execute();
|
return new QueryExecutor(new String[] {sql}, EMPTY_OBJECT_ARRAY, stat, pg_stream, (java.sql.Connection)this).execute();
|
||||||
|
}
|
||||||
|
private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send a query to the backend. Returns one of the ResultSet
|
||||||
|
* objects.
|
||||||
|
*
|
||||||
|
* <B>Note:</B> there does not seem to be any method currently
|
||||||
|
* in existance to return the update count.
|
||||||
|
*
|
||||||
|
* @param p_sqlFragmentss the SQL statement parts to be executed
|
||||||
|
* @param p_binds the SQL bind values
|
||||||
|
* @param stat The Statement associated with this query (may be null)
|
||||||
|
* @return a ResultSet holding the results
|
||||||
|
* @exception SQLException if a database error occurs
|
||||||
|
*/
|
||||||
|
public java.sql.ResultSet ExecSQL(String[] p_sqlFragments, Object[] p_binds, java.sql.Statement stat) throws SQLException
|
||||||
|
{
|
||||||
|
return new QueryExecutor(p_sqlFragments, p_binds, stat, pg_stream, (java.sql.Connection)this).execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -8,7 +8,7 @@ import java.util.Vector;
|
|||||||
import org.postgresql.largeobject.*;
|
import org.postgresql.largeobject.*;
|
||||||
import org.postgresql.util.*;
|
import org.postgresql.util.*;
|
||||||
|
|
||||||
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.4 2002/08/16 17:51:38 barry Exp $
|
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.5 2002/08/23 20:45:49 barry Exp $
|
||||||
* This class defines methods of the jdbc1 specification. This class is
|
* This class defines methods of the jdbc1 specification. This class is
|
||||||
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
|
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
|
||||||
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
|
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
|
||||||
@ -28,12 +28,12 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
/** Timeout (in seconds) for a query (not used) */
|
/** Timeout (in seconds) for a query (not used) */
|
||||||
protected int timeout = 0;
|
protected int timeout = 0;
|
||||||
|
|
||||||
protected boolean escapeProcessing = true;
|
protected boolean replaceProcessingEnabled = true;
|
||||||
|
|
||||||
/** The current results */
|
/** The current results */
|
||||||
protected java.sql.ResultSet result = null;
|
protected java.sql.ResultSet result = null;
|
||||||
|
|
||||||
// Static variables for parsing SQL when escapeProcessing is true.
|
// Static variables for parsing SQL when replaceProcessing is true.
|
||||||
private static final short IN_SQLCODE = 0;
|
private static final short IN_SQLCODE = 0;
|
||||||
private static final short IN_STRING = 1;
|
private static final short IN_STRING = 1;
|
||||||
private static final short BACKSLASH = 2;
|
private static final short BACKSLASH = 2;
|
||||||
@ -43,9 +43,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
private StringBuffer sbuf = new StringBuffer(32);
|
private StringBuffer sbuf = new StringBuffer(32);
|
||||||
|
|
||||||
//Used by the preparedstatement style methods
|
//Used by the preparedstatement style methods
|
||||||
protected String sql;
|
protected String[] m_sqlFragments;
|
||||||
protected String[] templateStrings;
|
protected Object[] m_binds = new Object[0];
|
||||||
protected String[] inStrings;
|
|
||||||
|
|
||||||
//Used by the callablestatement style methods
|
//Used by the callablestatement style methods
|
||||||
private static final String JDBC_SYNTAX = "{[? =] call <some_function> ([? [,?]*]) }";
|
private static final String JDBC_SYNTAX = "{[? =] call <some_function> ([? [,?]*]) }";
|
||||||
@ -68,42 +67,46 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public AbstractJdbc1Statement (AbstractJdbc1Connection connection, String sql) throws SQLException
|
public AbstractJdbc1Statement (AbstractJdbc1Connection connection, String p_sql) throws SQLException
|
||||||
{
|
{
|
||||||
this.sql = sql;
|
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
parseSqlStmt(); // this allows Callable stmt to override
|
parseSqlStmt(p_sql); // this allows Callable stmt to override
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void parseSqlStmt () throws SQLException {
|
protected void parseSqlStmt (String p_sql) throws SQLException {
|
||||||
|
String l_sql = p_sql;
|
||||||
|
|
||||||
|
l_sql = replaceProcessing(l_sql);
|
||||||
|
|
||||||
if (this instanceof CallableStatement) {
|
if (this instanceof CallableStatement) {
|
||||||
modifyJdbcCall();
|
l_sql = modifyJdbcCall(l_sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector v = new Vector();
|
Vector v = new Vector();
|
||||||
boolean inQuotes = false;
|
boolean inQuotes = false;
|
||||||
int lastParmEnd = 0, i;
|
int lastParmEnd = 0, i;
|
||||||
|
|
||||||
for (i = 0; i < sql.length(); ++i)
|
for (i = 0; i < l_sql.length(); ++i)
|
||||||
{
|
{
|
||||||
int c = sql.charAt(i);
|
int c = l_sql.charAt(i);
|
||||||
|
|
||||||
if (c == '\'')
|
if (c == '\'')
|
||||||
inQuotes = !inQuotes;
|
inQuotes = !inQuotes;
|
||||||
if (c == '?' && !inQuotes)
|
if (c == '?' && !inQuotes)
|
||||||
{
|
{
|
||||||
v.addElement(sql.substring (lastParmEnd, i));
|
v.addElement(l_sql.substring (lastParmEnd, i));
|
||||||
lastParmEnd = i + 1;
|
lastParmEnd = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
v.addElement(sql.substring (lastParmEnd, sql.length()));
|
v.addElement(l_sql.substring (lastParmEnd, l_sql.length()));
|
||||||
|
|
||||||
templateStrings = new String[v.size()];
|
m_sqlFragments = new String[v.size()];
|
||||||
inStrings = new String[v.size() - 1];
|
m_binds = new String[v.size() - 1];
|
||||||
|
//BJL why if binds is new???
|
||||||
clearParameters();
|
clearParameters();
|
||||||
|
|
||||||
for (i = 0 ; i < templateStrings.length; ++i)
|
for (i = 0 ; i < m_sqlFragments.length; ++i)
|
||||||
templateStrings[i] = (String)v.elementAt(i);
|
m_sqlFragments[i] = (String)v.elementAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -114,14 +117,11 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
* @return a ResulSet that contains the data produced by the query
|
* @return a ResulSet that contains the data produced by the query
|
||||||
* @exception SQLException if a database access error occurs
|
* @exception SQLException if a database access error occurs
|
||||||
*/
|
*/
|
||||||
public java.sql.ResultSet executeQuery(String sql) throws SQLException
|
public java.sql.ResultSet executeQuery(String p_sql) throws SQLException
|
||||||
{
|
{
|
||||||
this.execute(sql);
|
String l_sql = replaceProcessing(p_sql);
|
||||||
while (result != null && !((AbstractJdbc1ResultSet)result).reallyResultSet())
|
m_sqlFragments = new String[] {l_sql};
|
||||||
result = ((AbstractJdbc1ResultSet)result).getNext();
|
return executeQuery();
|
||||||
if (result == null)
|
|
||||||
throw new PSQLException("postgresql.stat.noresult");
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -133,7 +133,12 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
*/
|
*/
|
||||||
public java.sql.ResultSet executeQuery() throws SQLException
|
public java.sql.ResultSet executeQuery() throws SQLException
|
||||||
{
|
{
|
||||||
return executeQuery(compileQuery());
|
this.execute();
|
||||||
|
while (result != null && !((AbstractJdbc1ResultSet)result).reallyResultSet())
|
||||||
|
result = ((AbstractJdbc1ResultSet)result).getNext();
|
||||||
|
if (result == null)
|
||||||
|
throw new PSQLException("postgresql.stat.noresult");
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -145,12 +150,11 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
* @return either a row count, or 0 for SQL commands
|
* @return either a row count, or 0 for SQL commands
|
||||||
* @exception SQLException if a database access error occurs
|
* @exception SQLException if a database access error occurs
|
||||||
*/
|
*/
|
||||||
public int executeUpdate(String sql) throws SQLException
|
public int executeUpdate(String p_sql) throws SQLException
|
||||||
{
|
{
|
||||||
this.execute(sql);
|
String l_sql = replaceProcessing(p_sql);
|
||||||
if (((AbstractJdbc1ResultSet)result).reallyResultSet())
|
m_sqlFragments = new String[] {l_sql};
|
||||||
throw new PSQLException("postgresql.stat.result");
|
return executeUpdate();
|
||||||
return this.getUpdateCount();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -164,7 +168,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
*/
|
*/
|
||||||
public int executeUpdate() throws SQLException
|
public int executeUpdate() throws SQLException
|
||||||
{
|
{
|
||||||
return executeUpdate(compileQuery());
|
this.execute();
|
||||||
|
if (((AbstractJdbc1ResultSet)result).reallyResultSet())
|
||||||
|
throw new PSQLException("postgresql.stat.result");
|
||||||
|
return this.getUpdateCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -178,10 +185,30 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
* an update count or there are no more results
|
* an update count or there are no more results
|
||||||
* @exception SQLException if a database access error occurs
|
* @exception SQLException if a database access error occurs
|
||||||
*/
|
*/
|
||||||
public boolean execute(String sql) throws SQLException
|
public boolean execute(String p_sql) throws SQLException
|
||||||
{
|
{
|
||||||
if (escapeProcessing)
|
String l_sql = replaceProcessing(p_sql);
|
||||||
sql = escapeSQL(sql);
|
m_sqlFragments = new String[] {l_sql};
|
||||||
|
return execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some prepared statements return multiple results; the execute method
|
||||||
|
* handles these complex statements as well as the simpler form of
|
||||||
|
* statements handled by executeQuery and executeUpdate
|
||||||
|
*
|
||||||
|
* @return true if the next result is a ResultSet; false if it is an
|
||||||
|
* * update count or there are no more results
|
||||||
|
* @exception SQLException if a database access error occurs
|
||||||
|
*/
|
||||||
|
public boolean execute() throws SQLException
|
||||||
|
{
|
||||||
|
if (isFunction && !returnTypeSet)
|
||||||
|
throw new PSQLException("postgresql.call.noreturntype");
|
||||||
|
if (isFunction) { // set entry 1 to dummy entry..
|
||||||
|
m_binds[0] = ""; // dummy entry which ensured that no one overrode
|
||||||
|
// and calls to setXXX (2,..) really went to first arg in a function call..
|
||||||
|
}
|
||||||
|
|
||||||
// New in 7.1, if we have a previous resultset then force it to close
|
// New in 7.1, if we have a previous resultset then force it to close
|
||||||
// This brings us nearer to compliance, and helps memory management.
|
// This brings us nearer to compliance, and helps memory management.
|
||||||
@ -195,7 +222,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
|
|
||||||
|
|
||||||
// New in 7.1, pass Statement so that ExecSQL can customise to it
|
// New in 7.1, pass Statement so that ExecSQL can customise to it
|
||||||
result = ((AbstractJdbc1Connection)connection).ExecSQL(sql, (java.sql.Statement)this);
|
result = ((AbstractJdbc1Connection)connection).ExecSQL(m_sqlFragments, m_binds, (java.sql.Statement)this);
|
||||||
|
|
||||||
//If we are executing a callable statement function set the return data
|
//If we are executing a callable statement function set the return data
|
||||||
if (isFunction) {
|
if (isFunction) {
|
||||||
@ -216,20 +243,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Some prepared statements return multiple results; the execute method
|
|
||||||
* handles these complex statements as well as the simpler form of
|
|
||||||
* statements handled by executeQuery and executeUpdate
|
|
||||||
*
|
|
||||||
* @return true if the next result is a ResultSet; false if it is an
|
|
||||||
* * update count or there are no more results
|
|
||||||
* @exception SQLException if a database access error occurs
|
|
||||||
*/
|
|
||||||
public boolean execute() throws SQLException
|
|
||||||
{
|
|
||||||
return execute(compileQuery());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setCursorName defines the SQL cursor name that will be used by
|
* setCursorName defines the SQL cursor name that will be used by
|
||||||
* subsequent execute methods. This name can then be used in SQL
|
* subsequent execute methods. This name can then be used in SQL
|
||||||
@ -336,7 +349,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
*/
|
*/
|
||||||
public void setEscapeProcessing(boolean enable) throws SQLException
|
public void setEscapeProcessing(boolean enable) throws SQLException
|
||||||
{
|
{
|
||||||
escapeProcessing = enable;
|
replaceProcessingEnabled = enable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -494,18 +507,19 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
* So, something like "select * from x where d={d '2001-10-09'}" would
|
* So, something like "select * from x where d={d '2001-10-09'}" would
|
||||||
* return "select * from x where d= '2001-10-09'".
|
* return "select * from x where d= '2001-10-09'".
|
||||||
*/
|
*/
|
||||||
protected static String escapeSQL(String sql)
|
protected String replaceProcessing(String p_sql)
|
||||||
{
|
{
|
||||||
|
if (replaceProcessingEnabled) {
|
||||||
// Since escape codes can only appear in SQL CODE, we keep track
|
// Since escape codes can only appear in SQL CODE, we keep track
|
||||||
// of if we enter a string or not.
|
// of if we enter a string or not.
|
||||||
StringBuffer newsql = new StringBuffer(sql.length());
|
StringBuffer newsql = new StringBuffer(p_sql.length());
|
||||||
short state = IN_SQLCODE;
|
short state = IN_SQLCODE;
|
||||||
|
|
||||||
int i = -1;
|
int i = -1;
|
||||||
int len = sql.length();
|
int len = p_sql.length();
|
||||||
while (++i < len)
|
while (++i < len)
|
||||||
{
|
{
|
||||||
char c = sql.charAt(i);
|
char c = p_sql.charAt(i);
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
case IN_SQLCODE:
|
case IN_SQLCODE:
|
||||||
@ -514,7 +528,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
else if (c == '{') // start of an escape code?
|
else if (c == '{') // start of an escape code?
|
||||||
if (i + 1 < len)
|
if (i + 1 < len)
|
||||||
{
|
{
|
||||||
char next = sql.charAt(i + 1);
|
char next = p_sql.charAt(i + 1);
|
||||||
if (next == 'd')
|
if (next == 'd')
|
||||||
{
|
{
|
||||||
state = ESC_TIMEDATE;
|
state = ESC_TIMEDATE;
|
||||||
@ -524,7 +538,7 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
else if (next == 't')
|
else if (next == 't')
|
||||||
{
|
{
|
||||||
state = ESC_TIMEDATE;
|
state = ESC_TIMEDATE;
|
||||||
i += (i + 2 < len && sql.charAt(i + 2) == 's') ? 2 : 1;
|
i += (i + 2 < len && p_sql.charAt(i + 2) == 's') ? 2 : 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -556,6 +570,9 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
}
|
}
|
||||||
|
|
||||||
return newsql.toString();
|
return newsql.toString();
|
||||||
|
} else {
|
||||||
|
return p_sql;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1113,8 +1130,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0 ; i < inStrings.length ; i++)
|
for (i = 0 ; i < m_binds.length ; i++)
|
||||||
inStrings[i] = null;
|
m_binds[i] = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1532,8 +1549,6 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
/*
|
/*
|
||||||
* Returns the SQL statement with the current template values
|
* Returns the SQL statement with the current template values
|
||||||
* substituted.
|
* substituted.
|
||||||
* NB: This is identical to compileQuery() except instead of throwing
|
|
||||||
* SQLException if a parameter is null, it places ? instead.
|
|
||||||
*/
|
*/
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
@ -1542,15 +1557,15 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
sbuf.setLength(0);
|
sbuf.setLength(0);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0 ; i < inStrings.length ; ++i)
|
for (i = 0 ; i < m_binds.length ; ++i)
|
||||||
{
|
{
|
||||||
if (inStrings[i] == null)
|
if (m_binds[i] == null)
|
||||||
sbuf.append( '?' );
|
sbuf.append( '?' );
|
||||||
else
|
else
|
||||||
sbuf.append (templateStrings[i]);
|
sbuf.append (m_sqlFragments[i]);
|
||||||
sbuf.append (inStrings[i]);
|
sbuf.append (m_binds[i]);
|
||||||
}
|
}
|
||||||
sbuf.append(templateStrings[inStrings.length]);
|
sbuf.append(m_sqlFragments[m_binds.length]);
|
||||||
return sbuf.toString();
|
return sbuf.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1566,39 +1581,11 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
*/
|
*/
|
||||||
protected void set(int paramIndex, String s) throws SQLException
|
protected void set(int paramIndex, String s) throws SQLException
|
||||||
{
|
{
|
||||||
if (paramIndex < 1 || paramIndex > inStrings.length)
|
if (paramIndex < 1 || paramIndex > m_binds.length)
|
||||||
throw new PSQLException("postgresql.prep.range");
|
throw new PSQLException("postgresql.prep.range");
|
||||||
if (paramIndex == 1 && isFunction) // need to registerOut instead
|
if (paramIndex == 1 && isFunction) // need to registerOut instead
|
||||||
throw new PSQLException ("postgresql.call.funcover");
|
throw new PSQLException ("postgresql.call.funcover");
|
||||||
inStrings[paramIndex - 1] = s;
|
m_binds[paramIndex - 1] = s;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Helper - this compiles the SQL query from the various parameters
|
|
||||||
* This is identical to toString() except it throws an exception if a
|
|
||||||
* parameter is unused.
|
|
||||||
*/
|
|
||||||
protected synchronized String compileQuery()
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
sbuf.setLength(0);
|
|
||||||
int i;
|
|
||||||
|
|
||||||
if (isFunction && !returnTypeSet)
|
|
||||||
throw new PSQLException("postgresql.call.noreturntype");
|
|
||||||
if (isFunction) { // set entry 1 to dummy entry..
|
|
||||||
inStrings[0] = ""; // dummy entry which ensured that no one overrode
|
|
||||||
// and calls to setXXX (2,..) really went to first arg in a function call..
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0 ; i < inStrings.length ; ++i)
|
|
||||||
{
|
|
||||||
if (inStrings[i] == null)
|
|
||||||
throw new PSQLException("postgresql.prep.param", new Integer(i + 1));
|
|
||||||
sbuf.append (templateStrings[i]).append (inStrings[i]);
|
|
||||||
}
|
|
||||||
sbuf.append(templateStrings[inStrings.length]);
|
|
||||||
return sbuf.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1630,26 +1617,27 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
* select <some_function> (?, [?, ...]) as result
|
* select <some_function> (?, [?, ...]) as result
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private void modifyJdbcCall() throws SQLException {
|
private String modifyJdbcCall(String p_sql) throws SQLException {
|
||||||
// syntax checking is not complete only a few basics :(
|
// syntax checking is not complete only a few basics :(
|
||||||
originalSql = sql; // save for error msgs..
|
originalSql = p_sql; // save for error msgs..
|
||||||
int index = sql.indexOf ("="); // is implied func or proc?
|
String l_sql = p_sql;
|
||||||
|
int index = l_sql.indexOf ("="); // is implied func or proc?
|
||||||
boolean isValid = true;
|
boolean isValid = true;
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
isFunction = true;
|
isFunction = true;
|
||||||
isValid = sql.indexOf ("?") < index; // ? before =
|
isValid = l_sql.indexOf ("?") < index; // ? before =
|
||||||
}
|
}
|
||||||
sql = sql.trim ();
|
l_sql = l_sql.trim ();
|
||||||
if (sql.startsWith ("{") && sql.endsWith ("}")) {
|
if (l_sql.startsWith ("{") && l_sql.endsWith ("}")) {
|
||||||
sql = sql.substring (1, sql.length() -1);
|
l_sql = l_sql.substring (1, l_sql.length() -1);
|
||||||
} else isValid = false;
|
} else isValid = false;
|
||||||
index = sql.indexOf ("call");
|
index = l_sql.indexOf ("call");
|
||||||
if (index == -1 || !isValid)
|
if (index == -1 || !isValid)
|
||||||
throw new PSQLException ("postgresql.call.malformed",
|
throw new PSQLException ("postgresql.call.malformed",
|
||||||
new Object[]{sql, JDBC_SYNTAX});
|
new Object[]{l_sql, JDBC_SYNTAX});
|
||||||
sql = sql.replace ('{', ' '); // replace these characters
|
l_sql = l_sql.replace ('{', ' '); // replace these characters
|
||||||
sql = sql.replace ('}', ' ');
|
l_sql = l_sql.replace ('}', ' ');
|
||||||
sql = sql.replace (';', ' ');
|
l_sql = l_sql.replace (';', ' ');
|
||||||
|
|
||||||
// this removes the 'call' string and also puts a hidden '?'
|
// this removes the 'call' string and also puts a hidden '?'
|
||||||
// at the front of the line for functions, this will
|
// at the front of the line for functions, this will
|
||||||
@ -1658,9 +1646,10 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
|
|||||||
// value that is not needed by the postgres syntax. But to make
|
// value that is not needed by the postgres syntax. But to make
|
||||||
// sure that the parameter numbers are the same as in the original
|
// sure that the parameter numbers are the same as in the original
|
||||||
// sql we add a dummy parameter in this case
|
// sql we add a dummy parameter in this case
|
||||||
sql = (isFunction ? "?" : "") + sql.substring (index + 4);
|
l_sql = (isFunction ? "?" : "") + l_sql.substring (index + 4);
|
||||||
|
|
||||||
sql = "select " + sql + " as " + RESULT_COLUMN + ";";
|
l_sql = "select " + l_sql + " as " + RESULT_COLUMN + ";";
|
||||||
|
return l_sql;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** helperfunction for the getXXX calls to check isFunction and index == 1
|
/** helperfunction for the getXXX calls to check isFunction and index == 1
|
||||||
|
@ -15,15 +15,13 @@ import org.postgresql.util.PGbytea;
|
|||||||
import org.postgresql.util.PSQLException;
|
import org.postgresql.util.PSQLException;
|
||||||
|
|
||||||
|
|
||||||
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.4 2002/08/14 20:35:39 barry Exp $
|
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.5 2002/08/23 20:45:49 barry Exp $
|
||||||
* This class defines methods of the jdbc2 specification. This class extends
|
* This class defines methods of the jdbc2 specification. This class extends
|
||||||
* org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
|
* org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1
|
||||||
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
|
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
|
public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.AbstractJdbc1ResultSet {
|
||||||
|
|
||||||
protected String sqlQuery = null;
|
|
||||||
|
|
||||||
//needed for updateable result set support
|
//needed for updateable result set support
|
||||||
protected boolean updateable = false;
|
protected boolean updateable = false;
|
||||||
protected boolean doingUpdates = false;
|
protected boolean doingUpdates = false;
|
||||||
@ -1254,7 +1252,9 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
|
|||||||
|
|
||||||
|
|
||||||
public void parseQuery() {
|
public void parseQuery() {
|
||||||
StringTokenizer st = new StringTokenizer(sqlQuery, " \r\t");
|
String[] l_sqlFragments = ((AbstractJdbc2Statement)statement).getSqlFragments();
|
||||||
|
String l_sql = l_sqlFragments[0];
|
||||||
|
StringTokenizer st = new StringTokenizer(l_sql, " \r\t");
|
||||||
boolean tableFound = false, tablesChecked = false;
|
boolean tableFound = false, tablesChecked = false;
|
||||||
String name = "";
|
String name = "";
|
||||||
|
|
||||||
@ -1326,11 +1326,6 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void setSQLQuery(String sqlQuery) {
|
|
||||||
this.sqlQuery = sqlQuery;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private class PrimaryKey {
|
private class PrimaryKey {
|
||||||
int index; // where in the result set is this primaryKey
|
int index; // where in the result set is this primaryKey
|
||||||
String name; // what is the columnName of this primary Key
|
String name; // what is the columnName of this primary Key
|
||||||
|
@ -8,7 +8,7 @@ import java.util.Vector;
|
|||||||
import org.postgresql.largeobject.*;
|
import org.postgresql.largeobject.*;
|
||||||
import org.postgresql.util.PSQLException;
|
import org.postgresql.util.PSQLException;
|
||||||
|
|
||||||
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.3 2002/07/25 22:45:28 barry Exp $
|
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2Statement.java,v 1.4 2002/08/23 20:45:49 barry Exp $
|
||||||
* This class defines methods of the jdbc2 specification. This class extends
|
* This class defines methods of the jdbc2 specification. This class extends
|
||||||
* org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
|
* org.postgresql.jdbc1.AbstractJdbc1Statement which provides the jdbc1
|
||||||
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement
|
* methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2Statement
|
||||||
@ -43,32 +43,28 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
|
|||||||
* an update count or there are no more results
|
* an update count or there are no more results
|
||||||
* @exception SQLException if a database access error occurs
|
* @exception SQLException if a database access error occurs
|
||||||
*/
|
*/
|
||||||
public boolean execute(String sql) throws SQLException
|
public boolean execute() throws SQLException
|
||||||
{
|
{
|
||||||
boolean l_return = super.execute(sql);
|
boolean l_return = super.execute();
|
||||||
//Now do the jdbc2 specific stuff
|
//Now do the jdbc2 specific stuff
|
||||||
//required for ResultSet.getStatement() to work and updateable resultsets
|
//required for ResultSet.getStatement() to work and updateable resultsets
|
||||||
((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
|
((AbstractJdbc2ResultSet)result).setStatement((Statement)this);
|
||||||
|
|
||||||
// Added this so that the Updateable resultset knows the query that gave this
|
|
||||||
((AbstractJdbc2ResultSet)result).setSQLQuery(sql);
|
|
||||||
|
|
||||||
return l_return;
|
return l_return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ** JDBC 2 Extensions **
|
// ** JDBC 2 Extensions **
|
||||||
|
|
||||||
public void addBatch(String sql) throws SQLException
|
public void addBatch(String p_sql) throws SQLException
|
||||||
{
|
{
|
||||||
if (batch == null)
|
if (batch == null)
|
||||||
batch = new Vector();
|
batch = new Vector();
|
||||||
batch.addElement(sql);
|
batch.addElement(p_sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clearBatch() throws SQLException
|
public void clearBatch() throws SQLException
|
||||||
{
|
{
|
||||||
if (batch != null)
|
batch = null;
|
||||||
batch.removeAllElements();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int[] executeBatch() throws SQLException
|
public int[] executeBatch() throws SQLException
|
||||||
@ -155,7 +151,7 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
|
|||||||
|
|
||||||
public void addBatch() throws SQLException
|
public void addBatch() throws SQLException
|
||||||
{
|
{
|
||||||
addBatch(compileQuery());
|
addBatch(this.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public java.sql.ResultSetMetaData getMetaData() throws SQLException
|
public java.sql.ResultSetMetaData getMetaData() throws SQLException
|
||||||
@ -388,4 +384,9 @@ public abstract class AbstractJdbc2Statement extends org.postgresql.jdbc1.Abstra
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//This is needed by AbstractJdbc2ResultSet to determine if the query is updateable or not
|
||||||
|
protected String[] getSqlFragments() {
|
||||||
|
return m_sqlFragments;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ import java.sql.*;
|
|||||||
*
|
*
|
||||||
* PS: Do you know how difficult it is to type on a train? ;-)
|
* PS: Do you know how difficult it is to type on a train? ;-)
|
||||||
*
|
*
|
||||||
* $Id: DatabaseMetaDataTest.java,v 1.11 2002/08/14 20:35:40 barry Exp $
|
* $Id: DatabaseMetaDataTest.java,v 1.12 2002/08/23 20:45:49 barry Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class DatabaseMetaDataTest extends TestCase
|
public class DatabaseMetaDataTest extends TestCase
|
||||||
@ -102,7 +102,10 @@ public class DatabaseMetaDataTest extends TestCase
|
|||||||
assertTrue(dbmd.supportsMinimumSQLGrammar());
|
assertTrue(dbmd.supportsMinimumSQLGrammar());
|
||||||
assertTrue(!dbmd.supportsCoreSQLGrammar());
|
assertTrue(!dbmd.supportsCoreSQLGrammar());
|
||||||
assertTrue(!dbmd.supportsExtendedSQLGrammar());
|
assertTrue(!dbmd.supportsExtendedSQLGrammar());
|
||||||
|
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3"))
|
||||||
assertTrue(dbmd.supportsANSI92EntryLevelSQL());
|
assertTrue(dbmd.supportsANSI92EntryLevelSQL());
|
||||||
|
else
|
||||||
|
assertTrue(!dbmd.supportsANSI92EntryLevelSQL());
|
||||||
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
|
assertTrue(!dbmd.supportsANSI92IntermediateSQL());
|
||||||
assertTrue(!dbmd.supportsANSI92FullSQL());
|
assertTrue(!dbmd.supportsANSI92FullSQL());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user