Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd99794e

Browse files
committed
Attached is a patch for current CVS, consisting of a cvs diff -c
for the changed files and a few new files:- test/jdbc2/BatchExecuteTest.java- util/MessageTranslator.java- jdbc2/PBatchUpdateException.javaAs an aside, is this the best way to submit a patch consistingof both changed and new files? Or is there a smarter cvs commandwhich gets them all in one patch file?This patch fixes batch processing in the JDBC driver to beJDBC-2 compliant. Specifically, the changes introduced by thispatch are:1) Statement.executeBatch() no longer commits or rolls back atransaction, as this is not prescribed by the JDBC spec. Its upto the application to disable autocommit and to commit orrollback the transaction. Where JDBC talks about "executing thestatements as a unit", it means executing the statements in oneround trip to the backend for better performance, it does notmean executing the statements in a transaction.2) Statement.executeBatch() now throws a BatchUpdateException()as required by the JDBC spec. The significance of this is thatthe receiver of the exception gets the updateCounts of thecommands that succeeded before the error occurred. In order forthe messages to be translatable, java.sql.BatchUpdateExceptionis extended by org.postgresql.jdbc2.PBatchUpdateException() andthe localization code is factored out fromorg.postgresql.util.PSQLException to a separate singleton classorg.postgresql.util.MessageTranslator.3) When there is no batch or there are 0 statements in the batchwhen Statement.executeBatch() is called, do not throw anSQLException, but silently do nothing and return an update countarray of length 0. The JDBC spec says "Throws an SQLException ifthe driver does not support batch statements", which is clearlynot the case. See testExecuteEmptyBatch() inBatchExecuteTest.java for an example. The messagepostgresql.stat.batch.empty is removed from the languagespecific properties files.4) When Statement.executeBatch() is performed, reset thestatement's list of batch commands to empty. The JDBC spec isn't100% clear about this. This behaviour is only documented in theJava tutorial(http://java.sun.com/docs/books/tutorial/jdbc/jdbc2dot0/batchupdates.html).Note that the Oracle JDBC driver also resets the statement'slist in executeBatch(), and this seems the most reasonableinterpretation.5) A new test case is added to the JDBC test suite which testsvarious aspects of batch processing. See the new fileBatchExecuteTest.java.Regards,Ren? Pijlman
1 parente5d3df2 commitd99794e

File tree

6 files changed

+266
-43
lines changed

6 files changed

+266
-43
lines changed

‎src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2836,7 +2836,7 @@ public boolean insertsAreDetected(int type) throws SQLException
28362836
}
28372837

28382838
/**
2839-
*New in 7.1 - If this is for PreparedStatement yes, ResultSet no
2839+
*Indicates whether the driver supports batch updates.
28402840
*/
28412841
publicbooleansupportsBatchUpdates()throwsSQLException
28422842
{

‎src/interfaces/jdbc/org/postgresql/jdbc2/Statement.java

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -179,20 +179,26 @@ public void clearBatch() throws SQLException
179179

180180
publicint[]executeBatch()throwsSQLException
181181
{
182-
if(batch==null ||batch.isEmpty())
183-
thrownewPSQLException("postgresql.stat.batch.empty");
184-
182+
if(batch==null)
183+
batch=newVector();
185184
intsize=batch.size();
186185
int[]result=newint[size];
187186
inti=0;
188-
this.execute("begin");// PTM: check this when autoCommit is false
189187
try {
190188
for(i=0;i<size;i++)
191189
result[i]=this.executeUpdate((String)batch.elementAt(i));
192-
this.execute("commit");// PTM: check this
193190
}catch(SQLExceptione) {
194-
this.execute("abort");// PTM: check this
195-
thrownewPSQLException("postgresql.stat.batch.error",newInteger(i),batch.elementAt(i));
191+
int[]resultSucceeded =newint[i];
192+
System.arraycopy(result,0,resultSucceeded,0,i);
193+
194+
PBatchUpdateExceptionupdex =
195+
newPBatchUpdateException("postgresql.stat.batch.error",
196+
newInteger(i),batch.elementAt(i),resultSucceeded);
197+
updex.setNextException(e);
198+
199+
throwupdex;
200+
}finally {
201+
batch.removeAllElements();
196202
}
197203
returnresult;
198204
}

‎src/interfaces/jdbc/org/postgresql/test/JDBC2Tests.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,10 @@ public static TestSuite suite() {
205205
suite.addTestSuite(TimestampTest.class);
206206

207207
// PreparedStatement
208+
suite.addTestSuite(BatchExecuteTest.class);
209+
210+
// BatchExecute
211+
208212

209213
// MetaData
210214

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
packageorg.postgresql.test.jdbc2;
2+
3+
importorg.postgresql.test.JDBC2Tests;
4+
importjunit.framework.TestCase;
5+
importjava.sql.*;
6+
7+
/**
8+
* Test case for Statement.batchExecute()
9+
*/
10+
publicclassBatchExecuteTestextendsTestCase {
11+
12+
privateConnectioncon;
13+
privateStatementstmt;
14+
15+
publicBatchExecuteTest(Stringname) {
16+
super(name);
17+
}
18+
19+
// Set up the fixture for this testcase: a connection to a database with
20+
// a table for this test.
21+
protectedvoidsetUp()throwsException {
22+
con =JDBC2Tests.openDB();
23+
stmt =con.createStatement();
24+
25+
// Drop the test table if it already exists for some reason. It is
26+
// not an error if it doesn't exist.
27+
try {
28+
stmt.executeUpdate("DROP TABLE testbatch");
29+
}catch (SQLExceptione) {
30+
// Intentionally ignore. We cannot distinguish "table does not
31+
// exist" from other errors, since PostgreSQL doesn't support
32+
// error codes yet.
33+
}
34+
35+
stmt.executeUpdate("CREATE TABLE testbatch(pk INTEGER, col1 INTEGER)");
36+
stmt.executeUpdate("INSERT INTO testbatch VALUES(1, 0)");
37+
38+
// Generally recommended with batch updates. By default we run all
39+
// tests in this test case with autoCommit disabled.
40+
con.setAutoCommit(false);
41+
}
42+
43+
// Tear down the fixture for this test case.
44+
protectedvoidtearDown()throwsException {
45+
con.setAutoCommit(true);
46+
if (stmt !=null) {
47+
stmt.executeUpdate("DROP TABLE testbatch");
48+
stmt.close();
49+
}
50+
if (con !=null) {
51+
JDBC2Tests.closeDB(con);
52+
}
53+
}
54+
55+
publicvoidtestSupportsBatchUpdates()throwsException {
56+
DatabaseMetaDatadbmd =con.getMetaData();
57+
assertTrue(dbmd.supportsBatchUpdates());
58+
}
59+
60+
privatevoidassertCol1HasValue(intexpected)throwsException {
61+
StatementgetCol1 =con.createStatement();
62+
63+
ResultSetrs =
64+
getCol1.executeQuery("SELECT col1 FROM testbatch WHERE pk = 1");
65+
assertTrue(rs.next());
66+
67+
intactual =rs.getInt("col1");
68+
69+
assertEquals(expected,actual);
70+
71+
assertEquals(false,rs.next());
72+
73+
rs.close();
74+
getCol1.close();
75+
}
76+
77+
publicvoidtestExecuteEmptyBatch()throwsException {
78+
int[]updateCount =stmt.executeBatch();
79+
assertEquals(0,updateCount.length);
80+
81+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
82+
stmt.clearBatch();
83+
updateCount =stmt.executeBatch();
84+
assertEquals(0,updateCount.length);
85+
}
86+
87+
publicvoidtestClearBatch()throwsException {
88+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
89+
assertCol1HasValue(0);
90+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
91+
assertCol1HasValue(0);
92+
stmt.clearBatch();
93+
assertCol1HasValue(0);
94+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 4 WHERE pk = 1");
95+
assertCol1HasValue(0);
96+
stmt.executeBatch();
97+
assertCol1HasValue(4);
98+
con.commit();
99+
assertCol1HasValue(4);
100+
}
101+
102+
publicvoidtestSelectThrowsException()throwsException {
103+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
104+
stmt.addBatch("SELECT col1 FROM testbatch WHERE pk = 1");
105+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
106+
107+
try {
108+
stmt.executeBatch();
109+
fail("Should raise a BatchUpdateException because of the SELECT");
110+
}catch (BatchUpdateExceptione) {
111+
int []updateCounts =e.getUpdateCounts();
112+
assertEquals(1,updateCounts.length);
113+
assertEquals(1,updateCounts[0]);
114+
}catch (SQLExceptione) {
115+
fail("Should throw a BatchUpdateException instead of " +
116+
"a generic SQLException: " +e);
117+
}
118+
}
119+
120+
publicvoidtestPreparedStatement()throwsException {
121+
PreparedStatementpstmt =con.prepareStatement(
122+
"UPDATE testbatch SET col1 = col1 + ? WHERE PK = ?" );
123+
124+
// Note that the first parameter changes for every statement in the
125+
// batch, whereas the second parameter remains constant.
126+
pstmt.setInt(1,1);
127+
pstmt.setInt(2,1);
128+
pstmt.addBatch();
129+
assertCol1HasValue(0);
130+
131+
pstmt.setInt(1,2);
132+
pstmt.addBatch();
133+
assertCol1HasValue(0);
134+
135+
pstmt.setInt(1,4);
136+
pstmt.addBatch();
137+
assertCol1HasValue(0);
138+
139+
pstmt.executeBatch();
140+
assertCol1HasValue(7);
141+
142+
con.commit();
143+
assertCol1HasValue(7);
144+
145+
con.rollback();
146+
assertCol1HasValue(7);
147+
148+
pstmt.close();
149+
}
150+
151+
/**
152+
*/
153+
publicvoidtestTransactionalBehaviour()throwsException {
154+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 1 WHERE pk = 1");
155+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 2 WHERE pk = 1");
156+
stmt.executeBatch();
157+
con.rollback();
158+
assertCol1HasValue(0);
159+
160+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 4 WHERE pk = 1");
161+
stmt.addBatch("UPDATE testbatch SET col1 = col1 + 8 WHERE pk = 1");
162+
163+
// The statement has been added to the batch, but it should not yet
164+
// have been executed.
165+
assertCol1HasValue(0);
166+
167+
int[]updateCounts =stmt.executeBatch();
168+
assertEquals(2,updateCounts.length);
169+
assertEquals(1,updateCounts[0]);
170+
assertEquals(1,updateCounts[1]);
171+
172+
assertCol1HasValue(12);
173+
con.commit();
174+
assertCol1HasValue(12);
175+
con.rollback();
176+
assertCol1HasValue(12);
177+
}
178+
}
179+
180+
/* TODO tests that can be added to this test case
181+
- SQLExceptions chained to a BatchUpdateException
182+
- test PreparedStatement as thoroughly as Statement
183+
*/
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
packageorg.postgresql.util;
2+
3+
importjava.util.*;
4+
importjava.text.*;
5+
6+
/**
7+
* A singleton class to translate JDBC driver messages in SQLException's.
8+
*/
9+
publicclassMessageTranslator {
10+
11+
// The singleton instance.
12+
privatestaticMessageTranslatorinstance =null;
13+
14+
privateResourceBundlebundle;
15+
16+
privateMessageTranslator() {
17+
try {
18+
bundle =ResourceBundle.getBundle("org.postgresql.errors");
19+
}catch(MissingResourceExceptione) {
20+
// translation files have not been installed.
21+
bundle =null;
22+
}
23+
}
24+
25+
// Synchronized, otherwise multiple threads may perform the test and
26+
// assign to the singleton instance simultaneously.
27+
privatesynchronizedfinalstaticMessageTranslatorgetInstance() {
28+
if (instance ==null) {
29+
instance =newMessageTranslator();
30+
}
31+
returninstance;
32+
}
33+
34+
publicfinalstaticStringtranslate(Stringid,Object[]args) {
35+
36+
MessageTranslatortranslator =MessageTranslator.getInstance();
37+
38+
returntranslator._translate(id,args);
39+
}
40+
41+
privatefinalString_translate(Stringid,Object[]args) {
42+
Stringmessage;
43+
44+
if (bundle !=null &&id !=null) {
45+
// Now look up a localized message. If one is not found, then use
46+
// the supplied message instead.
47+
try {
48+
message =bundle.getString(id);
49+
}catch(MissingResourceExceptione) {
50+
message =id;
51+
}
52+
}else {
53+
message =id;
54+
}
55+
56+
// Expand any arguments
57+
if (args !=null &&message !=null) {
58+
message =MessageFormat.format(message,args);
59+
}
60+
61+
returnmessage;
62+
}
63+
}

‎src/interfaces/jdbc/org/postgresql/util/PSQLException.java

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
importjava.io.*;
44
importjava.sql.*;
5-
importjava.text.*;
6-
importjava.util.*;
75

86
/**
97
* This class extends SQLException, and provides our internationalisation handling
@@ -12,9 +10,6 @@ public class PSQLException extends SQLException
1210
{
1311
privateStringmessage;
1412

15-
// Cache for future errors
16-
staticResourceBundlebundle;
17-
1813
/**
1914
* This provides the same functionality to SQLException
2015
* @param error Error string
@@ -86,37 +81,10 @@ public PSQLException(String error,Object arg1,Object arg2)
8681
translate(error,argv);
8782
}
8883

89-
/**
90-
* This does the actual translation
91-
*/
92-
privatevoidtranslate(Stringid,Object[]args)
93-
{
94-
if(bundle ==null) {
95-
try {
96-
bundle =ResourceBundle.getBundle("org.postgresql.errors");
97-
}catch(MissingResourceExceptione) {
98-
// translation files have not been installed.
99-
message =id;
100-
}
84+
privatevoidtranslate(Stringerror,Object[]args) {
85+
message =MessageTranslator.translate(error,args);
10186
}
10287

103-
if (bundle !=null) {
104-
// Now look up a localized message. If one is not found, then use
105-
// the supplied message instead.
106-
message =null;
107-
try {
108-
message =bundle.getString(id);
109-
}catch(MissingResourceExceptione) {
110-
message =id;
111-
}
112-
}
113-
114-
// Expand any arguments
115-
if(args!=null &&message !=null)
116-
message =MessageFormat.format(message,args);
117-
118-
}
119-
12088
/**
12189
* Overides Throwable
12290
*/
@@ -140,5 +108,4 @@ public String toString()
140108
{
141109
returnmessage;
142110
}
143-
144111
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp