~ubuntu-branches/ubuntu/gutsy/libpgjava/gutsy

« back to all changes in this revision

Viewing changes to src/interfaces/jdbc/example/threadsafe.java

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Gybas
  • Date: 2002-02-06 23:43:06 UTC
  • Revision ID: james.westby@ubuntu.com-20020206234306-hsg7suqr8q56qg40
Tags: upstream-7.2
ImportĀ upstreamĀ versionĀ 7.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package example;
 
2
 
 
3
import java.io.*;
 
4
import java.sql.*;
 
5
import java.text.*;
 
6
 
 
7
// rare in user code, but we use the LargeObject API in this test
 
8
import org.postgresql.largeobject.*;
 
9
 
 
10
/*
 
11
 * This example tests the thread safety of the driver.
 
12
 *
 
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.
 
16
 *
 
17
 */
 
18
 
 
19
public class threadsafe
 
20
{
 
21
        Connection db;  // The connection to the database
 
22
        Statement st;   // Our statement to run queries with
 
23
 
 
24
        public threadsafe(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException
 
25
        {
 
26
                String url = args[0];
 
27
                String usr = args[1];
 
28
                String pwd = args[2];
 
29
 
 
30
                // Load the driver
 
31
                Class.forName("org.postgresql.Driver");
 
32
 
 
33
                // Connect to database
 
34
                System.out.println("Connecting to Database URL = " + url);
 
35
                db = DriverManager.getConnection(url, usr, pwd);
 
36
 
 
37
                System.out.println("Connected...Now creating a statement");
 
38
                st = db.createStatement();
 
39
 
 
40
                // Clean up the database (in case we failed earlier) then initialise
 
41
                cleanup();
 
42
 
 
43
                // Because we use LargeObjects, we must use Transactions
 
44
                db.setAutoCommit(false);
 
45
 
 
46
                // Now run tests using JDBC methods, then LargeObjects
 
47
                doexample();
 
48
 
 
49
                // Clean up the database
 
50
                cleanup();
 
51
 
 
52
                // Finally close the database
 
53
                System.out.println("Now closing the connection");
 
54
                st.close();
 
55
                db.close();
 
56
        }
 
57
 
 
58
        /*
 
59
         * This drops the table (if it existed). No errors are reported.
 
60
         */
 
61
        public void cleanup()
 
62
        {
 
63
                try
 
64
                {
 
65
                        st.executeUpdate("drop table basic1");
 
66
                }
 
67
                catch (Exception ex)
 
68
                {
 
69
                        // We ignore any errors here
 
70
                }
 
71
 
 
72
                try
 
73
                {
 
74
                        st.executeUpdate("drop table basic2");
 
75
                }
 
76
                catch (Exception ex)
 
77
                {
 
78
                        // We ignore any errors here
 
79
                }
 
80
        }
 
81
 
 
82
        /*
 
83
         * This performs the example
 
84
         */
 
85
        public void doexample() throws SQLException
 
86
        {
 
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");
 
88
 
 
89
                thread3 thread3 = null;
 
90
 
 
91
                try
 
92
                {
 
93
 
 
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);
 
99
 
 
100
                        // now run, and wait for them
 
101
                        thread1.start();
 
102
                        thread2.start();
 
103
                        thread3.start();
 
104
 
 
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())
 
109
                                thread0.yield();
 
110
                }
 
111
                finally
 
112
                {
 
113
                        // clean up after thread3 (the finally ensures this is run even
 
114
                        // if an exception is thrown inside the try { } construct)
 
115
                        if (thread3 != null)
 
116
                                thread3.cleanup();
 
117
                }
 
118
 
 
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.");
 
120
        }
 
121
 
 
122
        // This is the first thread. It's the same as the basic test
 
123
        class thread1 extends Thread
 
124
        {
 
125
                Connection c;
 
126
                Statement st;
 
127
 
 
128
                public thread1(Connection c) throws SQLException
 
129
                {
 
130
                        this.c = c;
 
131
                        st = c.createStatement();
 
132
                }
 
133
 
 
134
                public void run()
 
135
                {
 
136
                        try
 
137
                        {
 
138
                                System.out.println("Thread 1 running...");
 
139
 
 
140
                                // First we need a table to store data in
 
141
                                st.executeUpdate("create table basic1 (a int2, b int2)");
 
142
 
 
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)");
 
147
 
 
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).
 
153
                                //
 
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++)
 
159
                                {
 
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
 
163
                                        //        c.commit();
 
164
                                        if ((i % 50) == 0)
 
165
                                                DriverManager.println("Thread 1 done " + i + " inserts");
 
166
                                }
 
167
                                ps.close();                     // Always close when we are done with it
 
168
 
 
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");
 
172
                                int cnt = 0;
 
173
                                if (rs != null)
 
174
                                {
 
175
                                        // Now we run through the result set, printing out the result.
 
176
                                        // Note, we must call .next() before attempting to read any results
 
177
                                        while (rs.next())
 
178
                                        {
 
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);
 
182
                                                cnt++;
 
183
                                        }
 
184
                                        rs.close(); // again, you must close the result when done
 
185
                                }
 
186
                                DriverManager.println("Thread 1 read " + cnt + " rows");
 
187
 
 
188
                                // The last thing to do is to drop the table. This is done in the
 
189
                                // cleanup() method.
 
190
                                System.out.println("Thread 1 finished");
 
191
                        }
 
192
                        catch (SQLException se)
 
193
                        {
 
194
                                System.err.println("Thread 1: " + se.toString());
 
195
                                se.printStackTrace();
 
196
                                System.exit(1);
 
197
                        }
 
198
                }
 
199
        }
 
200
 
 
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
 
204
        {
 
205
                Connection c;
 
206
                Statement st;
 
207
 
 
208
                public thread2(Connection c) throws SQLException
 
209
                {
 
210
                        this.c = c;
 
211
                        st = c.createStatement();
 
212
                }
 
213
 
 
214
                public void run()
 
215
                {
 
216
                        try
 
217
                        {
 
218
                                System.out.println("Thread 2 running...");
 
219
 
 
220
                                // First we need a table to store data in
 
221
                                st.executeUpdate("create table basic2 (a int2, b int2)");
 
222
 
 
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).
 
228
                                //
 
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++)
 
234
                                {
 
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
 
238
                                        //        c.commit();
 
239
                                        if ((i % 50) == 0)
 
240
                                                DriverManager.println("Thread 2 done " + i + " inserts");
 
241
                                }
 
242
                                ps.close();                     // Always close when we are done with it
 
243
 
 
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");
 
247
                                int cnt = 0;
 
248
                                if (rs != null)
 
249
                                {
 
250
                                        // First find out the column numbers.
 
251
                                        //
 
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.
 
255
                                        //
 
256
                                        int col_a = rs.findColumn("a");
 
257
                                        int col_b = rs.findColumn("b");
 
258
 
 
259
                                        // Now we run through the result set, printing out the result.
 
260
                                        // Again, we must call .next() before attempting to read any results
 
261
                                        while (rs.next())
 
262
                                        {
 
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);
 
266
                                                cnt++;
 
267
                                        }
 
268
                                        rs.close(); // again, you must close the result when done
 
269
                                }
 
270
                                DriverManager.println("Thread 2 read " + cnt + " rows");
 
271
 
 
272
                                // The last thing to do is to drop the table. This is done in the
 
273
                                // cleanup() method.
 
274
                                System.out.println("Thread 2 finished");
 
275
                        }
 
276
                        catch (SQLException se)
 
277
                        {
 
278
                                System.err.println("Thread 2: " + se.toString());
 
279
                                se.printStackTrace();
 
280
                                System.exit(1);
 
281
                        }
 
282
                }
 
283
        }
 
284
 
 
285
        // This is the third thread. It loads, then reads from a LargeObject, using
 
286
        // our LargeObject api.
 
287
        //
 
288
        // The purpose of this is to test that FastPath will work in between normal
 
289
        // JDBC queries.
 
290
        class thread3 extends Thread
 
291
        {
 
292
                Connection c;
 
293
                Statement st;
 
294
                LargeObjectManager lom;
 
295
                LargeObject lo;
 
296
                int oid;
 
297
 
 
298
                public thread3(Connection c) throws SQLException
 
299
                {
 
300
                        this.c = c;
 
301
                        //st = c.createStatement();
 
302
 
 
303
                        // create a blob
 
304
                        lom = ((org.postgresql.Connection)c).getLargeObjectAPI();
 
305
                        oid = lom.create();
 
306
                        System.out.println("Thread 3 has created a blob of oid " + oid);
 
307
                }
 
308
 
 
309
                public void run()
 
310
                {
 
311
                        try
 
312
                        {
 
313
                                System.out.println("Thread 3 running...");
 
314
 
 
315
                                DriverManager.println("Thread 3: Loading data into blob " + oid);
 
316
                                lo = lom.open(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)
 
322
                                {
 
323
                                        DriverManager.println("Thread 3 read block " + bc + " " + bs + " bytes");
 
324
                                        lo.write(buf, 0, rc);
 
325
                                        bc++;
 
326
                                        bs += rc;
 
327
                                }
 
328
                                lo.close();
 
329
                                fis.close();
 
330
 
 
331
                                DriverManager.println("Thread 3: Reading blob " + oid);
 
332
                                lo = lom.open(oid);
 
333
                                bc = 0;
 
334
                                while (buf.length > 0)
 
335
                                {
 
336
                                        buf = lo.read(buf.length);
 
337
                                        if (buf.length > 0)
 
338
                                        {
 
339
                                                String s = new String(buf);
 
340
                                                bc++;
 
341
                                                DriverManager.println("Thread 3 block " + bc);
 
342
                                                DriverManager.println("Block " + bc + " got " + s);
 
343
                                        }
 
344
                                }
 
345
                                lo.close();
 
346
 
 
347
                                System.out.println("Thread 3 finished");
 
348
                        }
 
349
                        catch (Exception se)
 
350
                        {
 
351
                                System.err.println("Thread 3: " + se.toString());
 
352
                                se.printStackTrace();
 
353
                                System.exit(1);
 
354
                        }
 
355
                }
 
356
 
 
357
                public void cleanup() throws SQLException
 
358
                {
 
359
                        if (lom != null && oid != 0)
 
360
                        {
 
361
                                System.out.println("Thread 3: Removing blob oid=" + oid);
 
362
                                lom.delete(oid);
 
363
                        }
 
364
                }
 
365
        }
 
366
 
 
367
        /*
 
368
         * Display some instructions on how to run the example
 
369
         */
 
370
        public static void instructions()
 
371
        {
 
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.");
 
374
                System.exit(1);
 
375
        }
 
376
 
 
377
        /*
 
378
         * This little lot starts the test
 
379
         */
 
380
        public static void main(String args[])
 
381
        {
 
382
                System.out.println("PostgreSQL Thread Safety test v6.4 rev 1\n");
 
383
 
 
384
                if (args.length < 3)
 
385
                        instructions();
 
386
 
 
387
                // This line outputs debug information to stderr. To enable this, simply
 
388
                // add an extra parameter to the command line
 
389
                if (args.length > 3)
 
390
                        DriverManager.setLogStream(System.err);
 
391
 
 
392
                // Now run the tests
 
393
                try
 
394
                {
 
395
                        threadsafe test = new threadsafe(args);
 
396
                }
 
397
                catch (Exception ex)
 
398
                {
 
399
                        System.err.println("Exception caught.\n" + ex);
 
400
                        ex.printStackTrace();
 
401
                }
 
402
        }
 
403
}