7
// rare in user code, but we use the LargeObject API in this test
8
import org.postgresql.largeobject.*;
11
* This example tests the thread safety of the driver.
13
* It does this by performing several queries, in different threads. Each
14
* thread has it's own Statement object, which is (in my understanding of the
15
* jdbc specification) the minimum requirement.
19
public class threadsafe
21
Connection db; // The connection to the database
22
Statement st; // Our statement to run queries with
24
public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
31
Class.forName("org.postgresql.Driver");
33
// Connect to database
34
System.out.println("Connecting to Database URL = " + url);
35
db = DriverManager.getConnection(url, usr, pwd);
37
System.out.println("Connected...Now creating a statement");
38
st = db.createStatement();
40
// Clean up the database (in case we failed earlier) then initialise
43
// Because we use LargeObjects, we must use Transactions
44
db.setAutoCommit(false);
46
// Now run tests using JDBC methods, then LargeObjects
49
// Clean up the database
52
// Finally close the database
53
System.out.println("Now closing the connection");
59
* This drops the table (if it existed). No errors are reported.
65
st.executeUpdate("drop table basic1");
69
// We ignore any errors here
74
st.executeUpdate("drop table basic2");
78
// We ignore any errors here
83
* This performs the example
85
public void doexample() throws SQLException
87
System.out.println("\nThis test runs three Threads. Two simply insert data into a table, then\nthey perform a query. While they are running, a third thread is running,\nand it load data into, then reads from a Large Object.\n\nIf alls well, this should run without any errors. If so, we are Thread Safe.\nWhy test JDBC & LargeObject's? Because both will run over the network\nconnection, and if locking on the stream isn't done correctly, the backend\nwill get pretty confused!\n");
89
thread3 thread3 = null;
94
// create the two threads
95
Thread thread0 = Thread.currentThread();
96
Thread thread1 = new thread1(db);
97
Thread thread2 = new thread2(db);
98
thread3 = new thread3(db);
100
// now run, and wait for them
105
// ok, I know this is bad, but it does the trick here as our main thread
106
// will yield as long as either of the children are still running
107
System.out.println("Waiting for threads to run");
108
while (thread1.isAlive() || thread2.isAlive() || thread3.isAlive())
113
// clean up after thread3 (the finally ensures this is run even
114
// if an exception is thrown inside the try { } construct)
119
System.out.println("No Exceptions have been thrown. This is a good omen, as it means that we are\npretty much thread safe as we can get.");
122
// This is the first thread. It's the same as the basic test
123
class thread1 extends Thread
128
public thread1(Connection c) throws SQLException
131
st = c.createStatement();
138
System.out.println("Thread 1 running...");
140
// First we need a table to store data in
141
st.executeUpdate("create table basic1 (a int2, b int2)");
143
// Now insert some data, using the Statement
144
st.executeUpdate("insert into basic1 values (1,1)");
145
st.executeUpdate("insert into basic1 values (2,1)");
146
st.executeUpdate("insert into basic1 values (3,1)");
148
// For large inserts, a PreparedStatement is more efficient, because it
149
// supports the idea of precompiling the SQL statement, and to store
150
// directly, a Java object into any column. PostgreSQL doesnt support
151
// precompiling, but does support setting a column to the value of a
152
// Java object (like Date, String, etc).
154
// Also, this is the only way of writing dates in a datestyle independent
155
// manner. (DateStyles are PostgreSQL's way of handling different methods
156
// of representing dates in the Date data type.)
157
PreparedStatement ps = db.prepareStatement("insert into basic1 values (?,?)");
158
for (int i = 2;i < 2000;i++)
160
ps.setInt(1, 4); // "column a" = 5
161
ps.setInt(2, i); // "column b" = i
162
ps.executeUpdate(); // executeUpdate because insert returns no data
165
DriverManager.println("Thread 1 done " + i + " inserts");
167
ps.close(); // Always close when we are done with it
169
// Finally perform a query on the table
170
DriverManager.println("Thread 1 performing a query");
171
ResultSet rs = st.executeQuery("select a, b from basic1");
175
// Now we run through the result set, printing out the result.
176
// Note, we must call .next() before attempting to read any results
179
int a = rs.getInt("a"); // This shows how to get the value by name
180
int b = rs.getInt(2); // This shows how to get the value by column
181
//System.out.println(" a="+a+" b="+b);
184
rs.close(); // again, you must close the result when done
186
DriverManager.println("Thread 1 read " + cnt + " rows");
188
// The last thing to do is to drop the table. This is done in the
190
System.out.println("Thread 1 finished");
192
catch (SQLException se)
194
System.err.println("Thread 1: " + se.toString());
195
se.printStackTrace();
201
// This is the second thread. It's the similar to the basic test, and thread1
202
// except it works on another table.
203
class thread2 extends Thread
208
public thread2(Connection c) throws SQLException
211
st = c.createStatement();
218
System.out.println("Thread 2 running...");
220
// First we need a table to store data in
221
st.executeUpdate("create table basic2 (a int2, b int2)");
223
// For large inserts, a PreparedStatement is more efficient, because it
224
// supports the idea of precompiling the SQL statement, and to store
225
// directly, a Java object into any column. PostgreSQL doesnt support
226
// precompiling, but does support setting a column to the value of a
227
// Java object (like Date, String, etc).
229
// Also, this is the only way of writing dates in a datestyle independent
230
// manner. (DateStyles are PostgreSQL's way of handling different methods
231
// of representing dates in the Date data type.)
232
PreparedStatement ps = db.prepareStatement("insert into basic2 values (?,?)");
233
for (int i = 2;i < 2000;i++)
235
ps.setInt(1, 4); // "column a" = 5
236
ps.setInt(2, i); // "column b" = i
237
ps.executeUpdate(); // executeUpdate because insert returns no data
240
DriverManager.println("Thread 2 done " + i + " inserts");
242
ps.close(); // Always close when we are done with it
244
// Finally perform a query on the table
245
DriverManager.println("Thread 2 performing a query");
246
ResultSet rs = st.executeQuery("select * from basic2 where b>1");
250
// First find out the column numbers.
252
// It's best to do this here, as calling the methods with the column
253
// numbers actually performs this call each time they are called. This
254
// really speeds things up on large queries.
256
int col_a = rs.findColumn("a");
257
int col_b = rs.findColumn("b");
259
// Now we run through the result set, printing out the result.
260
// Again, we must call .next() before attempting to read any results
263
int a = rs.getInt(col_a); // This shows how to get the value by name
264
int b = rs.getInt(col_b); // This shows how to get the value by column
265
//System.out.println(" a="+a+" b="+b);
268
rs.close(); // again, you must close the result when done
270
DriverManager.println("Thread 2 read " + cnt + " rows");
272
// The last thing to do is to drop the table. This is done in the
274
System.out.println("Thread 2 finished");
276
catch (SQLException se)
278
System.err.println("Thread 2: " + se.toString());
279
se.printStackTrace();
285
// This is the third thread. It loads, then reads from a LargeObject, using
286
// our LargeObject api.
288
// The purpose of this is to test that FastPath will work in between normal
290
class thread3 extends Thread
294
LargeObjectManager lom;
298
public thread3(Connection c) throws SQLException
301
//st = c.createStatement();
304
lom = ((org.postgresql.Connection)c).getLargeObjectAPI();
306
System.out.println("Thread 3 has created a blob of oid " + oid);
313
System.out.println("Thread 3 running...");
315
DriverManager.println("Thread 3: Loading data into blob " + oid);
317
FileInputStream fis = new FileInputStream("example/threadsafe.java");
318
// keep the buffer size small, to allow the other thread a chance
319
byte buf[] = new byte[128];
320
int rc, bc = 1, bs = 0;
321
while ((rc = fis.read(buf)) > 0)
323
DriverManager.println("Thread 3 read block " + bc + " " + bs + " bytes");
324
lo.write(buf, 0, rc);
331
DriverManager.println("Thread 3: Reading blob " + oid);
334
while (buf.length > 0)
336
buf = lo.read(buf.length);
339
String s = new String(buf);
341
DriverManager.println("Thread 3 block " + bc);
342
DriverManager.println("Block " + bc + " got " + s);
347
System.out.println("Thread 3 finished");
351
System.err.println("Thread 3: " + se.toString());
352
se.printStackTrace();
357
public void cleanup() throws SQLException
359
if (lom != null && oid != 0)
361
System.out.println("Thread 3: Removing blob oid=" + oid);
368
* Display some instructions on how to run the example
370
public static void instructions()
372
System.out.println("\nThis tests the thread safety of the driver.\n\nThis is done in two parts, the first with standard JDBC calls, and the\nsecond mixing FastPath and LargeObject calls with queries.\n");
373
System.out.println("Useage:\n java example.threadsafe jdbc:postgresql:database user password [debug]\n\nThe debug field can be anything. It's presence will enable DriverManager's\ndebug trace. Unless you want to see screens of items, don't put anything in\nhere.");
378
* This little lot starts the test
380
public static void main(String args[])
382
System.out.println("PostgreSQL Thread Safety test v6.4 rev 1\n");
387
// This line outputs debug information to stderr. To enable this, simply
388
// add an extra parameter to the command line
390
DriverManager.setLogStream(System.err);
395
threadsafe test = new threadsafe(args);
399
System.err.println("Exception caught.\n" + ex);
400
ex.printStackTrace();