Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
7ecb6ede
Commit
7ecb6ede
authored
Oct 29, 2003
by
Dave Cramer
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Patches from Oliver Jowett to fix CursorFetchTest, 7.4 now does not automatically delete cursors
parent
15c6764b
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
416 additions
and
235 deletions
+416
-235
src/interfaces/jdbc/org/postgresql/core/BaseConnection.java
src/interfaces/jdbc/org/postgresql/core/BaseConnection.java
+2
-2
src/interfaces/jdbc/org/postgresql/core/BaseStatement.java
src/interfaces/jdbc/org/postgresql/core/BaseStatement.java
+3
-3
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
...es/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
+2
-3
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
...ces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
+46
-25
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
...ces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
+250
-187
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
...ces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
+1
-15
src/interfaces/jdbc/org/postgresql/test/jdbc2/CursorFetchTest.java
...faces/jdbc/org/postgresql/test/jdbc2/CursorFetchTest.java
+112
-0
No files found.
src/interfaces/jdbc/org/postgresql/core/BaseConnection.java
View file @
7ecb6ede
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
* Copyright (c) 2003, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseConnection.java,v 1.
3 2003/05/29 03:21:32 barry
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseConnection.java,v 1.
4 2003/10/29 02:39:09 davec
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -26,7 +26,7 @@ public interface BaseConnection extends PGConnection
...
@@ -26,7 +26,7 @@ public interface BaseConnection extends PGConnection
public
void
cancelQuery
()
throws
SQLException
;
public
void
cancelQuery
()
throws
SQLException
;
public
Statement
createStatement
()
throws
SQLException
;
public
Statement
createStatement
()
throws
SQLException
;
public
BaseResultSet
execSQL
(
String
s
)
throws
SQLException
;
public
BaseResultSet
execSQL
(
String
s
)
throws
SQLException
;
public
boolean
getAutoCommit
()
throws
SQLException
;
public
boolean
getAutoCommit
();
public
String
getCursorName
()
throws
SQLException
;
public
String
getCursorName
()
throws
SQLException
;
public
Encoding
getEncoding
()
throws
SQLException
;
public
Encoding
getEncoding
()
throws
SQLException
;
public
DatabaseMetaData
getMetaData
()
throws
SQLException
;
public
DatabaseMetaData
getMetaData
()
throws
SQLException
;
...
...
src/interfaces/jdbc/org/postgresql/core/BaseStatement.java
View file @
7ecb6ede
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
* Copyright (c) 2003, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseStatement.java,v 1.
5 2003/08/24 22:10:09 barry
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseStatement.java,v 1.
6 2003/10/29 02:39:09 davec
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -30,11 +30,11 @@ public interface BaseStatement extends org.postgresql.PGStatement
...
@@ -30,11 +30,11 @@ public interface BaseStatement extends org.postgresql.PGStatement
*/
*/
public
void
addWarning
(
String
p_warning
)
throws
SQLException
;
public
void
addWarning
(
String
p_warning
)
throws
SQLException
;
public
void
close
()
throws
SQLException
;
public
void
close
()
throws
SQLException
;
public
int
getFetchSize
()
throws
SQLException
;
public
int
getFetchSize
();
public
int
getMaxFieldSize
()
throws
SQLException
;
public
int
getMaxFieldSize
()
throws
SQLException
;
public
int
getMaxRows
()
throws
SQLException
;
public
int
getMaxRows
()
throws
SQLException
;
public
int
getResultSetConcurrency
()
throws
SQLException
;
public
int
getResultSetConcurrency
()
throws
SQLException
;
public
String
get
Statement
Name
();
public
String
get
FetchingCursor
Name
();
public
SQLWarning
getWarnings
()
throws
SQLException
;
public
SQLWarning
getWarnings
()
throws
SQLException
;
public
void
setMaxFieldSize
(
int
max
)
throws
SQLException
;
public
void
setMaxFieldSize
(
int
max
)
throws
SQLException
;
...
...
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Connection.java
View file @
7ecb6ede
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
* Copyright (c) 2003, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.2
6 2003/09/13 04:02:15 barry
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.2
7 2003/10/29 02:39:09 davec
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -1270,10 +1270,9 @@ public abstract class AbstractJdbc1Connection implements BaseConnection
...
@@ -1270,10 +1270,9 @@ public abstract class AbstractJdbc1Connection implements BaseConnection
* gets the current auto-commit state
* gets the current auto-commit state
*
*
* @return Current state of the auto-commit mode
* @return Current state of the auto-commit mode
* @exception SQLException (why?)
* @see setAutoCommit
* @see setAutoCommit
*/
*/
public
boolean
getAutoCommit
()
throws
SQLException
public
boolean
getAutoCommit
()
{
{
return
this
.
autoCommit
;
return
this
.
autoCommit
;
}
}
...
...
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
View file @
7ecb6ede
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
* Copyright (c) 2003, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.2
1 2003/09/22 04:54:59 barry
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.2
2 2003/10/29 02:39:09 davec
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -61,6 +61,9 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
...
@@ -61,6 +61,9 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
private
SimpleDateFormat
m_tstzFormat
=
null
;
private
SimpleDateFormat
m_tstzFormat
=
null
;
private
SimpleDateFormat
m_dateFormat
=
null
;
private
SimpleDateFormat
m_dateFormat
=
null
;
private
int
fetchSize
;
// Fetch size for next read (might be 0).
private
int
lastFetchSize
;
// Fetch size of last read (might be 0).
public
abstract
ResultSetMetaData
getMetaData
()
throws
SQLException
;
public
abstract
ResultSetMetaData
getMetaData
()
throws
SQLException
;
public
AbstractJdbc1ResultSet
(
BaseStatement
statement
,
public
AbstractJdbc1ResultSet
(
BaseStatement
statement
,
...
@@ -82,6 +85,8 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
...
@@ -82,6 +85,8 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
this
.
this_row
=
null
;
this
.
this_row
=
null
;
this
.
current_row
=
-
1
;
this
.
current_row
=
-
1
;
this
.
binaryCursor
=
binaryCursor
;
this
.
binaryCursor
=
binaryCursor
;
this
.
lastFetchSize
=
this
.
fetchSize
=
(
statement
==
null
?
0
:
statement
.
getFetchSize
());
}
}
public
BaseStatement
getPGStatement
()
{
public
BaseStatement
getPGStatement
()
{
...
@@ -111,7 +116,21 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
...
@@ -111,7 +116,21 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
this
.
current_row
=
-
1
;
this
.
current_row
=
-
1
;
this
.
binaryCursor
=
binaryCursor
;
this
.
binaryCursor
=
binaryCursor
;
}
}
//
// Part of the JDBC2 support, but convenient to implement here.
//
public
void
setFetchSize
(
int
rows
)
throws
SQLException
{
fetchSize
=
rows
;
}
public
int
getFetchSize
()
throws
SQLException
{
return
fetchSize
;
}
public
boolean
next
()
throws
SQLException
public
boolean
next
()
throws
SQLException
{
{
...
@@ -120,30 +139,32 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
...
@@ -120,30 +139,32 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet
if
(++
current_row
>=
rows
.
size
())
if
(++
current_row
>=
rows
.
size
())
{
{
int
fetchSize
=
statement
.
getFetchSize
();
String
cursorName
=
statement
.
getFetchingCursorName
();
// Must be false if we weren't batching.
if
(
cursorName
==
null
||
lastFetchSize
==
0
||
rows
.
size
()
<
lastFetchSize
)
if
(
fetchSize
==
0
)
return
false
;
// Not doing a cursor-based fetch or the last fetch was the end of the query
return
false
;
// Use the ref to the statement to get
// Use the ref to the statement to get
// the details we need to do another cursor
// the details we need to do another cursor
// query - it will use reinit() to repopulate this
// query - it will use reinit() to repopulate this
// with the right data.
// with the right data.
String
[]
sql
=
new
String
[
1
];
String
[]
binds
=
new
String
[
0
];
// NB: We can reach this point with fetchSize == 0
// Is this the correct query???
// if the fetch size is changed halfway through reading results.
String
cursorName
=
statement
.
getStatementName
();
// Use "FETCH FORWARD ALL" in that case to complete the query.
//if cursorName is null, we are not batching (likely because the
String
[]
sql
=
new
String
[]
{
//query itself can't be batched)
fetchSize
==
0
?
(
"FETCH FORWARD ALL FROM "
+
cursorName
)
:
if
(
cursorName
==
null
)
(
"FETCH FORWARD "
+
fetchSize
+
" FROM "
+
cursorName
)
return
false
;
};
sql
[
0
]
=
"FETCH FORWARD "
+
fetchSize
+
" FROM "
+
cursorName
;
QueryExecutor
.
execute
(
sql
,
QueryExecutor
.
execute
(
sql
,
binds
,
new
String
[
0
],
this
);
this
);
// Test the new rows array.
// Test the new rows array.
if
(
rows
.
size
()
==
0
)
lastFetchSize
=
fetchSize
;
return
false
;
if
(
rows
.
size
()
==
0
)
return
false
;
// Otherwise reset the counter and let it go on...
// Otherwise reset the counter and let it go on...
current_row
=
0
;
current_row
=
0
;
}
}
...
...
src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java
View file @
7ecb6ede
...
@@ -26,7 +26,7 @@ import java.sql.Timestamp;
...
@@ -26,7 +26,7 @@ import java.sql.Timestamp;
import
java.sql.Types
;
import
java.sql.Types
;
import
java.util.Vector
;
import
java.util.Vector
;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.4
0 2003/10/09 01:17:07 wieck
Exp $
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.4
1 2003/10/29 02:39:09 davec
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
...
@@ -62,15 +62,25 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -62,15 +62,25 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
// Some performance caches
// Some performance caches
private
StringBuffer
sbuf
=
new
StringBuffer
(
32
);
private
StringBuffer
sbuf
=
new
StringBuffer
(
32
);
//Used by the preparedstatement style methods
protected
String
[]
m_sqlFragments
;
// Query fragments.
protected
String
[]
m_sqlFragments
;
private
String
[]
m_executeSqlFragments
;
// EXECUTE(...) if useServerPrepare
private
String
[]
m_origSqlFragments
;
protected
Object
[]
m_binds
=
new
Object
[
0
];
// Parameter values
private
String
[]
m_executeSqlFragments
;
protected
Object
[]
m_binds
=
new
Object
[
0
];
protected
String
[]
m_bindTypes
=
new
String
[
0
];
// Parameter types, for PREPARE(...)
protected
String
m_statementName
=
null
;
// Allocated PREPARE statement name for server-prepared statements
protected
String
[]
m_bindTypes
=
new
String
[
0
];
protected
String
m_cursorName
=
null
;
// Allocated DECLARE cursor name for cursor-based fetch
protected
String
m_statementName
=
null
;
protected
boolean
m_statementIsCursor
=
false
;
// Constants for allowXXX and m_isSingleStatement vars, below.
// The idea is to defer the cost of examining the query until we really need to know,
// but don't reexamine it every time thereafter.
private
static
final
short
UNKNOWN
=
0
;
// Don't know yet, examine the query.
private
static
final
short
NO
=
1
;
// Don't use feature
private
static
final
short
YES
=
2
;
// Do use feature
private
short
m_isSingleDML
=
UNKNOWN
;
// Is the query a single SELECT/UPDATE/INSERT/DELETE?
private
short
m_isSingleSelect
=
UNKNOWN
;
// Is the query a single SELECT?
private
short
m_isSingleStatement
=
UNKNOWN
;
// Is the query a single statement?
private
boolean
m_useServerPrepare
=
false
;
private
boolean
m_useServerPrepare
=
false
;
...
@@ -115,11 +125,11 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -115,11 +125,11 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
return
connection
;
return
connection
;
}
}
public
String
get
Statement
Name
()
{
public
String
get
FetchingCursor
Name
()
{
return
m_
statement
Name
;
return
m_
cursor
Name
;
}
}
public
int
getFetchSize
()
throws
SQLException
{
public
int
getFetchSize
()
{
return
fetchSize
;
return
fetchSize
;
}
}
...
@@ -138,6 +148,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -138,6 +148,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
boolean
inQuotes
=
false
;
boolean
inQuotes
=
false
;
int
lastParmEnd
=
0
,
i
;
int
lastParmEnd
=
0
,
i
;
m_isSingleSelect
=
m_isSingleDML
=
UNKNOWN
;
m_isSingleStatement
=
YES
;
for
(
i
=
0
;
i
<
l_sql
.
length
();
++
i
)
for
(
i
=
0
;
i
<
l_sql
.
length
();
++
i
)
{
{
int
c
=
l_sql
.
charAt
(
i
);
int
c
=
l_sql
.
charAt
(
i
);
...
@@ -149,6 +162,8 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -149,6 +162,8 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
v
.
addElement
(
l_sql
.
substring
(
lastParmEnd
,
i
));
v
.
addElement
(
l_sql
.
substring
(
lastParmEnd
,
i
));
lastParmEnd
=
i
+
1
;
lastParmEnd
=
i
+
1
;
}
}
if
(
c
==
';'
&&
!
inQuotes
)
m_isSingleStatement
=
m_isSingleSelect
=
m_isSingleDML
=
NO
;
}
}
v
.
addElement
(
l_sql
.
substring
(
lastParmEnd
,
l_sql
.
length
()));
v
.
addElement
(
l_sql
.
substring
(
lastParmEnd
,
l_sql
.
length
()));
...
@@ -161,39 +176,46 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -161,39 +176,46 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
}
}
/*
/*
* Execute a SQL statement that retruns a single ResultSet
* Deallocate resources allocated for the current query
*
* in preparation for replacing it with a new query.
* @param sql typically a static SQL SELECT statement
* @return a ResulSet that contains the data produced by the query
* @exception SQLException if a database access error occurs
*/
*/
public
java
.
sql
.
ResultSet
executeQuery
(
String
p_sql
)
throws
SQLException
private
void
deallocateQuery
()
{
{
String
l_sql
=
replaceProcessing
(
p_sql
);
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_binds
=
new
Object
[
0
];
//If we have already created a server prepared statement, we need
//If we have already created a server prepared statement, we need
//to deallocate the existing one
//to deallocate the existing one
if
(
m_statementName
!=
null
)
if
(
m_statementName
!=
null
)
{
{
try
try
{
{
if
(!
m_statementIsCursor
)
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
}
}
catch
(
Exception
e
)
catch
(
Exception
e
)
{
{
}
}
finally
{
m_statementName
=
null
;
m_statementIsCursor
=
false
;
m_origSqlFragments
=
null
;
m_executeSqlFragments
=
null
;
}
}
}
m_statementName
=
null
;
m_cursorName
=
null
;
// automatically closed at end of txn anyway
m_executeSqlFragments
=
null
;
m_isSingleStatement
=
m_isSingleSelect
=
m_isSingleDML
=
UNKNOWN
;
}
/*
* Execute a SQL statement that retruns a single ResultSet
*
* @param sql typically a static SQL SELECT statement
* @return a ResulSet that contains the data produced by the query
* @exception SQLException if a database access error occurs
*/
public
java
.
sql
.
ResultSet
executeQuery
(
String
p_sql
)
throws
SQLException
{
deallocateQuery
();
String
l_sql
=
replaceProcessing
(
p_sql
);
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_binds
=
new
Object
[
0
];
return
executeQuery
();
return
executeQuery
();
}
}
...
@@ -226,17 +248,12 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -226,17 +248,12 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
*/
*/
public
int
executeUpdate
(
String
p_sql
)
throws
SQLException
public
int
executeUpdate
(
String
p_sql
)
throws
SQLException
{
{
deallocateQuery
();
String
l_sql
=
replaceProcessing
(
p_sql
);
String
l_sql
=
replaceProcessing
(
p_sql
);
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_binds
=
new
Object
[
0
];
m_binds
=
new
Object
[
0
];
//If we have already created a server prepared statement, we need
//to deallocate the existing one
if
(
m_statementName
!=
null
)
{
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
m_statementName
=
null
;
m_origSqlFragments
=
null
;
m_executeSqlFragments
=
null
;
}
return
executeUpdate
();
return
executeUpdate
();
}
}
...
@@ -270,28 +287,199 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -270,28 +287,199 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
*/
*/
public
boolean
execute
(
String
p_sql
)
throws
SQLException
public
boolean
execute
(
String
p_sql
)
throws
SQLException
{
{
deallocateQuery
();
String
l_sql
=
replaceProcessing
(
p_sql
);
String
l_sql
=
replaceProcessing
(
p_sql
);
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_sqlFragments
=
new
String
[]
{
l_sql
};
m_binds
=
new
Object
[
0
];
m_binds
=
new
Object
[
0
];
//If we have already created a server prepared statement, we need
//to deallocate the existing one
if
(
m_statementName
!=
null
)
{
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
m_statementName
=
null
;
m_origSqlFragments
=
null
;
m_executeSqlFragments
=
null
;
}
return
execute
();
return
execute
();
}
}
/*
* Check if the current query is a single statement.
*/
private
boolean
isSingleStatement
()
{
if
(
m_isSingleStatement
!=
UNKNOWN
)
return
m_isSingleStatement
==
YES
;
// Crude detection of multiple statements. This could be
// improved by parsing the whole query for quotes, but is
// it worth it given that the only queries that get here are
// unparameterized queries?
for
(
int
i
=
0
;
i
<
m_sqlFragments
.
length
;
++
i
)
{
// a bit redundant, but ..
if
(
m_sqlFragments
[
i
].
indexOf
(
';'
)
!=
-
1
)
{
m_isSingleStatement
=
NO
;
return
false
;
}
}
m_isSingleStatement
=
YES
;
return
true
;
}
/*
* Helper for isSingleSelect() and isSingleDML(): computes values
* of m_isSingleDML and m_isSingleSelect.
*/
private
void
analyzeStatementType
()
{
if
(!
isSingleStatement
())
{
m_isSingleSelect
=
m_isSingleDML
=
NO
;
return
;
}
String
compare
=
m_sqlFragments
[
0
].
trim
().
toLowerCase
();
if
(
compare
.
startsWith
(
"select"
))
{
m_isSingleSelect
=
m_isSingleDML
=
YES
;
return
;
}
m_isSingleSelect
=
NO
;
if
(!
compare
.
startsWith
(
"update"
)
&&
!
compare
.
startsWith
(
"delete"
)
&&
!
compare
.
startsWith
(
"insert"
))
{
m_isSingleDML
=
NO
;
return
;
}
m_isSingleDML
=
YES
;
}
/*
* Check if the current query is a single SELECT.
*/
private
boolean
isSingleSelect
()
{
if
(
m_isSingleSelect
==
UNKNOWN
)
analyzeStatementType
();
return
m_isSingleSelect
==
YES
;
}
/*
* Check if the current query is a single SELECT/UPDATE/INSERT/DELETE.
*/
private
boolean
isSingleDML
()
{
if
(
m_isSingleDML
==
UNKNOWN
)
analyzeStatementType
();
return
m_isSingleDML
==
YES
;
}
/*
* Return the query fragments to use for a server-prepared statement.
* The first query executed will include a PREPARE and EXECUTE;
* subsequent queries will just be an EXECUTE.
*/
private
String
[]
transformToServerPrepare
()
{
if
(
m_statementName
!=
null
)
return
m_executeSqlFragments
;
// First time through.
m_statementName
=
"JDBC_STATEMENT_"
+
m_preparedCount
++;
// Set up m_executeSqlFragments
m_executeSqlFragments
=
new
String
[
m_sqlFragments
.
length
];
m_executeSqlFragments
[
0
]
=
"EXECUTE "
+
m_statementName
;
if
(
m_sqlFragments
.
length
>
1
)
{
m_executeSqlFragments
[
0
]
+=
"("
;
for
(
int
i
=
1
;
i
<
m_bindTypes
.
length
;
i
++)
m_executeSqlFragments
[
i
]
=
", "
;
m_executeSqlFragments
[
m_bindTypes
.
length
]
=
")"
;
}
// Set up the PREPARE.
String
[]
prepareSqlFragments
=
new
String
[
m_sqlFragments
.
length
];
System
.
arraycopy
(
m_sqlFragments
,
0
,
prepareSqlFragments
,
0
,
m_sqlFragments
.
length
);
synchronized
(
sbuf
)
{
sbuf
.
setLength
(
0
);
sbuf
.
append
(
"PREPARE "
);
sbuf
.
append
(
m_statementName
);
if
(
m_sqlFragments
.
length
>
1
)
{
sbuf
.
append
(
"("
);
for
(
int
i
=
0
;
i
<
m_bindTypes
.
length
;
i
++)
{
if
(
i
!=
0
)
sbuf
.
append
(
", "
);
sbuf
.
append
(
m_bindTypes
[
i
]);
}
sbuf
.
append
(
")"
);
}
sbuf
.
append
(
" AS "
);
sbuf
.
append
(
m_sqlFragments
[
0
]);
for
(
int
i
=
1
;
i
<
m_sqlFragments
.
length
;
i
++)
{
sbuf
.
append
(
" $"
);
sbuf
.
append
(
i
);
sbuf
.
append
(
" "
);
sbuf
.
append
(
m_sqlFragments
[
i
]);
}
sbuf
.
append
(
"; "
);
sbuf
.
append
(
m_executeSqlFragments
[
0
]);
prepareSqlFragments
[
0
]
=
sbuf
.
toString
();
}
System
.
arraycopy
(
m_executeSqlFragments
,
1
,
prepareSqlFragments
,
1
,
prepareSqlFragments
.
length
-
1
);
return
prepareSqlFragments
;
}
/*
* Return the current query transformed into a cursor-based statement.
* This uses a new cursor on each query.
*/
private
String
[]
transformToCursorFetch
()
{
// Pinch the prepared count for our own nefarious purposes.
m_cursorName
=
"JDBC_CURS_"
+
m_preparedCount
++;
// Create a cursor declaration and initial fetch statement from the original query.
int
len
=
m_sqlFragments
.
length
;
String
[]
cursorBasedSql
=
new
String
[
len
];
System
.
arraycopy
(
m_sqlFragments
,
0
,
cursorBasedSql
,
0
,
len
);
cursorBasedSql
[
0
]
=
"DECLARE "
+
m_cursorName
+
" CURSOR FOR "
+
cursorBasedSql
[
0
];
cursorBasedSql
[
len
-
1
]
+=
"; FETCH FORWARD "
+
fetchSize
+
" FROM "
+
m_cursorName
;
// Make the cursor based query the one that will be used.
if
(
org
.
postgresql
.
Driver
.
logDebug
)
org
.
postgresql
.
Driver
.
debug
(
"using cursor based sql with cursor name "
+
m_cursorName
);
return
cursorBasedSql
;
}
/**
* Do transformations to a query for server-side prepare or setFetchSize() cursor
* work.
* @return the query fragments to execute
*/
private
String
[]
getQueryFragments
()
{
// nb: isSingleXXX() are relatively expensive, avoid calling them unless we must.
// We check the "mutable" bits of these conditions (which may change without
// a new query being created) here; isSingleXXX() only concern themselves with
// the query structure itself.
// We prefer cursor-based-fetch over server-side-prepare here.
// Eventually a v3 implementation should let us do both at once.
if
(
fetchSize
>
0
&&
!
connection
.
getAutoCommit
()
&&
isSingleSelect
())
return
transformToCursorFetch
();
if
(
isUseServerPrepare
()
&&
isSingleDML
())
return
transformToServerPrepare
();
// Not server-prepare or cursor-fetch, just return a plain query.
return
m_sqlFragments
;
}
/*
/*
* Some prepared statements return multiple results; the execute method
* Some prepared statements return multiple results; the execute method
* handles these complex statements as well as the simpler form of
* handles these complex statements as well as the simpler form of
* statements handled by executeQuery and executeUpdate
* statements handled by executeQuery and executeUpdate
*
* This method also handles the translation of the query into a cursor based
* query if the user has specified a fetch size and set the connection
* into a non-auto commit state.
*
*
* @return true if the next result is a ResultSet; false if it is an
* @return true if the next result is a ResultSet; false if it is an
* update count or there are no more results
* update count or there are no more results
...
@@ -319,133 +507,14 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -319,133 +507,14 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
rs
.
close
();
rs
.
close
();
}
}
//Use server prepared statements if directed
// Get the actual query fragments to run (might be a transformed version of
if
(
m_useServerPrepare
)
// the original fragments)
{
String
[]
fragments
=
getQueryFragments
();
if
(
m_statementName
==
null
)
{
m_statementName
=
"JDBC_STATEMENT_"
+
next_preparedCount
();
m_origSqlFragments
=
new
String
[
m_sqlFragments
.
length
];
m_executeSqlFragments
=
new
String
[
m_sqlFragments
.
length
];
System
.
arraycopy
(
m_sqlFragments
,
0
,
m_origSqlFragments
,
0
,
m_sqlFragments
.
length
);
m_executeSqlFragments
[
0
]
=
"EXECUTE "
+
m_statementName
;
if
(
m_sqlFragments
.
length
>
1
)
{
m_executeSqlFragments
[
0
]
=
m_executeSqlFragments
[
0
]
+
"("
;
for
(
int
i
=
1
;
i
<
m_bindTypes
.
length
;
i
++)
{
m_executeSqlFragments
[
i
]
=
", "
;
}
m_executeSqlFragments
[
m_bindTypes
.
length
]
=
")"
;
}
synchronized
(
sbuf
)
{
sbuf
.
setLength
(
0
);
sbuf
.
append
(
"PREPARE "
);
sbuf
.
append
(
m_statementName
);
if
(
m_origSqlFragments
.
length
>
1
)
{
sbuf
.
append
(
"("
);
for
(
int
i
=
0
;
i
<
m_bindTypes
.
length
-
1
;
i
++)
{
sbuf
.
append
(
m_bindTypes
[
i
]);
sbuf
.
append
(
", "
);
}
sbuf
.
append
(
m_bindTypes
[
m_bindTypes
.
length
-
1
]);
sbuf
.
append
(
")"
);
}
sbuf
.
append
(
" AS "
);
sbuf
.
append
(
m_origSqlFragments
[
0
]);
for
(
int
i
=
1
;
i
<
m_origSqlFragments
.
length
;
i
++)
{
sbuf
.
append
(
" $"
);
sbuf
.
append
(
i
);
sbuf
.
append
(
" "
);
sbuf
.
append
(
m_origSqlFragments
[
i
]);
}
sbuf
.
append
(
"; "
);
sbuf
.
append
(
m_executeSqlFragments
[
0
]);
m_sqlFragments
[
0
]
=
sbuf
.
toString
();
System
.
arraycopy
(
m_executeSqlFragments
,
1
,
m_sqlFragments
,
1
,
m_sqlFragments
.
length
-
1
);
}
}
else
{
m_sqlFragments
=
m_executeSqlFragments
;
}
}
// Use a cursor if directed and in a transaction.
else
if
(
fetchSize
>
0
&&
!
connection
.
getAutoCommit
())
{
// The first thing to do is transform the statement text into the cursor form.
String
[]
cursorBasedSql
=
new
String
[
m_sqlFragments
.
length
];
// Pinch the prepared count for our own nefarious purposes.
String
statementName
=
"JDBC_CURS_"
+
next_preparedCount
();
// Setup the cursor decleration.
// Note that we don't need a BEGIN because we've already
// made sure we're executing inside a transaction.
String
cursDecl
=
"DECLARE "
+
statementName
+
" CURSOR FOR "
;
String
endCurs
=
" FETCH FORWARD "
+
fetchSize
+
" FROM "
+
statementName
+
";"
;
// Copy the real query to the curs decleration.
try
{
// Need to confirm this with Barry Lind.
if
(
cursorBasedSql
.
length
>
1
)
throw
new
IllegalStateException
(
"cursor fetches not supported with prepared statements."
);
for
(
int
i
=
0
;
i
<
cursorBasedSql
.
length
;
i
++)
{
if
(
i
==
0
)
{
if
(
m_sqlFragments
[
i
].
trim
().
toUpperCase
().
startsWith
(
"DECLARE "
))
throw
new
IllegalStateException
(
"statement is already cursor based."
);
cursorBasedSql
[
i
]
=
cursDecl
;
}
if
(
cursorBasedSql
[
i
]
!=
null
)
cursorBasedSql
[
i
]
+=
m_sqlFragments
[
i
];
else
cursorBasedSql
[
i
]
=
m_sqlFragments
[
i
];
if
(
i
==
cursorBasedSql
.
length
-
1
)
{
// We have to be smart about adding the delimitting ";"
if
(
m_sqlFragments
[
i
].
endsWith
(
";"
))
cursorBasedSql
[
i
]
+=
endCurs
;
else
cursorBasedSql
[
i
]
+=
(
";"
+
endCurs
);
}
else
if
(
m_sqlFragments
[
i
].
indexOf
(
";"
)
>
-
1
)
{
throw
new
IllegalStateException
(
"multiple statements not "
+
"allowed with cursor based querys."
);
}
}
// Make the cursor based query the one that will be used.
if
(
org
.
postgresql
.
Driver
.
logDebug
)
org
.
postgresql
.
Driver
.
debug
(
"using cursor based sql with cursor name "
+
statementName
);
// Do all of this after exceptions have been thrown.
m_statementName
=
statementName
;
m_statementIsCursor
=
true
;
m_sqlFragments
=
cursorBasedSql
;
}
catch
(
IllegalStateException
e
)
{
// Something went wrong generating the cursor based statement.
if
(
org
.
postgresql
.
Driver
.
logDebug
)
org
.
postgresql
.
Driver
.
debug
(
e
.
getMessage
());
}
}
// 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
=
QueryExecutor
.
execute
(
m_sqlF
ragments
,
result
=
QueryExecutor
.
execute
(
f
ragments
,
m_binds
,
m_binds
,
this
);
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
)
...
@@ -721,10 +790,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -721,10 +790,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
if
(
rs
!=
null
)
if
(
rs
!=
null
)
rs
.
close
();
rs
.
close
();
// If using server prepared statements deallocate them
deallocateQuery
();
if
(
m_useServerPrepare
&&
m_statementName
!=
null
)
{
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
}
// Disasociate it from us (For Garbage Collection)
// Disasociate it from us (For Garbage Collection)
result
=
null
;
result
=
null
;
...
@@ -2093,11 +2159,8 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
...
@@ -2093,11 +2159,8 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
public
void
setUseServerPrepare
(
boolean
flag
)
throws
SQLException
{
public
void
setUseServerPrepare
(
boolean
flag
)
throws
SQLException
{
//Server side prepared statements were introduced in 7.3
//Server side prepared statements were introduced in 7.3
if
(
connection
.
haveMinimumServerVersion
(
"7.3"
))
{
if
(
connection
.
haveMinimumServerVersion
(
"7.3"
))
{
//If turning server prepared statements off deallocate statement
if
(
m_useServerPrepare
!=
flag
)
//and reset statement name
deallocateQuery
();
if
(
m_useServerPrepare
!=
flag
&&
!
flag
&&
m_statementName
!=
null
)
connection
.
execSQL
(
"DEALLOCATE "
+
m_statementName
);
m_statementName
=
null
;
m_useServerPrepare
=
flag
;
m_useServerPrepare
=
flag
;
}
else
{
}
else
{
//This is a pre 7.3 server so no op this method
//This is a pre 7.3 server so no op this method
...
...
src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
View file @
7ecb6ede
...
@@ -9,7 +9,7 @@
...
@@ -9,7 +9,7 @@
* Copyright (c) 2003, PostgreSQL Global Development Group
* Copyright (c) 2003, PostgreSQL Global Development Group
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.2
4 2003/09/17 05:14:52 barry
Exp $
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.2
5 2003/10/29 02:39:09 davec
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -389,13 +389,6 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
...
@@ -389,13 +389,6 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
}
}
public
int
getFetchSize
()
throws
SQLException
{
// Returning the current batch size seems the right thing to do.
return
rows
.
size
();
}
public
Object
getObject
(
String
columnName
,
java
.
util
.
Map
map
)
throws
SQLException
public
Object
getObject
(
String
columnName
,
java
.
util
.
Map
map
)
throws
SQLException
{
{
return
getObject
(
findColumn
(
columnName
),
map
);
return
getObject
(
findColumn
(
columnName
),
map
);
...
@@ -518,13 +511,6 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
...
@@ -518,13 +511,6 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra
}
}
public
void
setFetchSize
(
int
rows
)
throws
SQLException
{
// Sub-classes should implement this as part of their cursor support
throw
org
.
postgresql
.
Driver
.
notImplemented
();
}
public
synchronized
void
cancelRowUpdates
()
public
synchronized
void
cancelRowUpdates
()
throws
SQLException
throws
SQLException
{
{
...
...
src/interfaces/jdbc/org/postgresql/test/jdbc2/CursorFetchTest.java
View file @
7ecb6ede
...
@@ -51,7 +51,10 @@ public class CursorFetchTest extends TestCase
...
@@ -51,7 +51,10 @@ public class CursorFetchTest extends TestCase
int
[]
testSizes
=
{
0
,
1
,
49
,
50
,
51
,
99
,
100
,
101
};
int
[]
testSizes
=
{
0
,
1
,
49
,
50
,
51
,
99
,
100
,
101
};
for
(
int
i
=
0
;
i
<
testSizes
.
length
;
++
i
)
{
for
(
int
i
=
0
;
i
<
testSizes
.
length
;
++
i
)
{
stmt
.
setFetchSize
(
testSizes
[
i
]);
stmt
.
setFetchSize
(
testSizes
[
i
]);
assertEquals
(
testSizes
[
i
],
stmt
.
getFetchSize
());
ResultSet
rs
=
stmt
.
executeQuery
();
ResultSet
rs
=
stmt
.
executeQuery
();
assertEquals
(
testSizes
[
i
],
rs
.
getFetchSize
());
int
count
=
0
;
int
count
=
0
;
while
(
rs
.
next
())
{
while
(
rs
.
next
())
{
...
@@ -63,6 +66,115 @@ public class CursorFetchTest extends TestCase
...
@@ -63,6 +66,115 @@ public class CursorFetchTest extends TestCase
}
}
}
}
//
// Tests for ResultSet.setFetchSize().
//
// test one:
// set fetchsize = 0
// run query (all rows should be fetched)
// set fetchsize = 50 (should have no effect)
// process results
public
void
testResultSetFetchSizeOne
()
throws
Exception
{
createRows
(
100
);
PreparedStatement
stmt
=
con
.
prepareStatement
(
"select * from test_fetch order by value"
);
stmt
.
setFetchSize
(
0
);
ResultSet
rs
=
stmt
.
executeQuery
();
stmt
.
setFetchSize
(
50
);
// Should have no effect.
int
count
=
0
;
while
(
rs
.
next
())
{
assertEquals
(
count
,
rs
.
getInt
(
1
));
++
count
;
}
assertEquals
(
100
,
count
);
}
// test two:
// set fetchsize = 25
// run query (25 rows fetched)
// set fetchsize = 0
// process results:
// process 25 rows
// should do a FETCH ALL to get more data
// process 75 rows
public
void
testResultSetFetchSizeTwo
()
throws
Exception
{
createRows
(
100
);
PreparedStatement
stmt
=
con
.
prepareStatement
(
"select * from test_fetch order by value"
);
stmt
.
setFetchSize
(
25
);
ResultSet
rs
=
stmt
.
executeQuery
();
stmt
.
setFetchSize
(
0
);
int
count
=
0
;
while
(
rs
.
next
())
{
assertEquals
(
count
,
rs
.
getInt
(
1
));
++
count
;
}
assertEquals
(
100
,
count
);
}
// test three:
// set fetchsize = 25
// run query (25 rows fetched)
// set fetchsize = 50
// process results:
// process 25 rows. should NOT hit end-of-results here.
// do a FETCH FORWARD 50
// process 50 rows
// do a FETCH FORWARD 50
// process 25 rows. end of results.
public
void
testResultSetFetchSizeThree
()
throws
Exception
{
createRows
(
100
);
PreparedStatement
stmt
=
con
.
prepareStatement
(
"select * from test_fetch order by value"
);
stmt
.
setFetchSize
(
25
);
ResultSet
rs
=
stmt
.
executeQuery
();
stmt
.
setFetchSize
(
50
);
int
count
=
0
;
while
(
rs
.
next
())
{
assertEquals
(
count
,
rs
.
getInt
(
1
));
++
count
;
}
assertEquals
(
100
,
count
);
}
// test four:
// set fetchsize = 50
// run query (50 rows fetched)
// set fetchsize = 25
// process results:
// process 50 rows.
// do a FETCH FORWARD 25
// process 25 rows
// do a FETCH FORWARD 25
// process 25 rows. end of results.
public
void
testResultSetFetchSizeFour
()
throws
Exception
{
createRows
(
100
);
PreparedStatement
stmt
=
con
.
prepareStatement
(
"select * from test_fetch order by value"
);
stmt
.
setFetchSize
(
50
);
ResultSet
rs
=
stmt
.
executeQuery
();
stmt
.
setFetchSize
(
25
);
int
count
=
0
;
while
(
rs
.
next
())
{
assertEquals
(
count
,
rs
.
getInt
(
1
));
++
count
;
}
assertEquals
(
100
,
count
);
}
// Test odd queries that should not be transformed into cursor-based fetches.
// Test odd queries that should not be transformed into cursor-based fetches.
public
void
TODO_FAILS_testInsert
()
throws
Exception
public
void
TODO_FAILS_testInsert
()
throws
Exception
{
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment