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

« back to all changes in this revision

Viewing changes to src/interfaces/jdbc/org/postgresql/core/PGStream.java

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Vandyck
  • Date: 2005-04-21 14:25:11 UTC
  • mfrom: (1.2.1 upstream) (2.1.1 warty)
  • Revision ID: james.westby@ubuntu.com-20050421142511-wibh5vc31fkrorx7
Tags: 7.4.7-3
Built with sources...

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * PGStream.java
 
4
 *      This class is used by Connection for communicating with the
 
5
 *      backend.
 
6
 *
 
7
 * Copyright (c) 2003, PostgreSQL Global Development Group
 
8
 *
 
9
 * IDENTIFICATION
 
10
 *        $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/PGStream.java,v 1.3.2.1 2004/03/29 17:47:47 barry Exp $
 
11
 *
 
12
 *-------------------------------------------------------------------------
 
13
 */
 
14
package org.postgresql.core;
 
15
 
 
16
import java.io.BufferedInputStream;
 
17
import java.io.BufferedOutputStream;
 
18
import java.io.InputStream;
 
19
import java.io.IOException;
 
20
import java.net.Socket;
 
21
import java.sql.*;
 
22
import org.postgresql.util.PSQLException;
 
23
import org.postgresql.util.PSQLState;
 
24
 
 
25
 
 
26
public class PGStream
 
27
{
 
28
        public String host;
 
29
        public int port;
 
30
        public Socket connection;
 
31
        public InputStream pg_input;
 
32
        public BufferedOutputStream pg_output;
 
33
        private byte[] byte_buf = new byte[8*1024];
 
34
 
 
35
        /*
 
36
         * Constructor:  Connect to the PostgreSQL back end and return
 
37
         * a stream connection.
 
38
         *
 
39
         * @param host the hostname to connect to
 
40
         * @param port the port number that the postmaster is sitting on
 
41
         * @exception IOException if an IOException occurs below it.
 
42
         */
 
43
        public PGStream(String p_host, int p_port) throws IOException
 
44
        {
 
45
                host = p_host;
 
46
                port = p_port;
 
47
                connection = new Socket(host, port);
 
48
 
 
49
                // Submitted by Jason Venner <jason@idiom.com> adds a 10x speed
 
50
                // improvement on FreeBSD machines (caused by a bug in their TCP Stack)
 
51
                connection.setTcpNoDelay(true);
 
52
 
 
53
                // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
 
54
                pg_input = new BufferedInputStream(connection.getInputStream(), 8192);
 
55
                pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
 
56
        }
 
57
 
 
58
        /*
 
59
         * Sends a single character to the back end
 
60
         *
 
61
         * @param val the character to be sent
 
62
         * @exception IOException if an I/O error occurs
 
63
         */
 
64
        public void SendChar(int val) throws IOException
 
65
        {
 
66
                pg_output.write((byte)val);
 
67
        }
 
68
 
 
69
        /*
 
70
         * Sends an integer to the back end
 
71
         *
 
72
         * @param val the integer to be sent
 
73
         * @param siz the length of the integer in bytes (size of structure)
 
74
         * @exception IOException if an I/O error occurs
 
75
         */
 
76
        public void SendInteger(int val, int siz) throws IOException
 
77
        {
 
78
                byte[] buf = new byte[siz];
 
79
 
 
80
                while (siz-- > 0)
 
81
                {
 
82
                        buf[siz] = (byte)(val & 0xff);
 
83
                        val >>= 8;
 
84
                }
 
85
                Send(buf);
 
86
        }
 
87
 
 
88
        /*
 
89
         * Sends an integer to the back end
 
90
         *
 
91
         * @param val the integer to be sent
 
92
         * @param siz the length of the integer in bytes (size of structure)
 
93
         * @exception IOException if an I/O error occurs
 
94
         */
 
95
        public void SendIntegerR(int val, int siz) throws IOException
 
96
        {
 
97
                byte[] buf = new byte[siz];
 
98
 
 
99
                for (int i = 0; i < siz; i++)
 
100
                {
 
101
                        buf[i] = (byte)(val & 0xff);
 
102
                        val >>= 8;
 
103
                }
 
104
                Send(buf);
 
105
        }
 
106
 
 
107
        /*
 
108
         * Send an array of bytes to the backend
 
109
         *
 
110
         * @param buf The array of bytes to be sent
 
111
         * @exception IOException if an I/O error occurs
 
112
         */
 
113
        public void Send(byte buf[]) throws IOException
 
114
        {
 
115
                pg_output.write(buf);
 
116
        }
 
117
 
 
118
        /*
 
119
         * Send an exact array of bytes to the backend - if the length
 
120
         * has not been reached, send nulls until it has.
 
121
         *
 
122
         * @param buf the array of bytes to be sent
 
123
         * @param siz the number of bytes to be sent
 
124
         * @exception IOException if an I/O error occurs
 
125
         */
 
126
        public void Send(byte buf[], int siz) throws IOException
 
127
        {
 
128
                Send(buf, 0, siz);
 
129
        }
 
130
 
 
131
        /*
 
132
         * Send an exact array of bytes to the backend - if the length
 
133
         * has not been reached, send nulls until it has.
 
134
         *
 
135
         * @param buf the array of bytes to be sent
 
136
         * @param off offset in the array to start sending from
 
137
         * @param siz the number of bytes to be sent
 
138
         * @exception IOException if an I/O error occurs
 
139
         */
 
140
        public void Send(byte buf[], int off, int siz) throws IOException
 
141
        {
 
142
                int i;
 
143
 
 
144
                pg_output.write(buf, off, ((buf.length - off) < siz ? (buf.length - off) : siz));
 
145
                if ((buf.length - off) < siz)
 
146
                {
 
147
                        for (i = buf.length - off ; i < siz ; ++i)
 
148
                        {
 
149
                                pg_output.write(0);
 
150
                        }
 
151
                }
 
152
        }
 
153
 
 
154
        /*
 
155
         * Receives a single character from the backend
 
156
         *
 
157
         * @return the character received
 
158
         * @exception SQLException if an I/O Error returns
 
159
         */
 
160
        public int ReceiveChar() throws SQLException
 
161
        {
 
162
                int c = 0;
 
163
 
 
164
                try
 
165
                {
 
166
                        c = pg_input.read();
 
167
                        if (c < 0)
 
168
                                throw new PSQLException("postgresql.stream.eof", PSQLState.COMMUNICATION_ERROR);
 
169
                }
 
170
                catch (IOException e)
 
171
                {
 
172
                        throw new PSQLException("postgresql.stream.ioerror", PSQLState.COMMUNICATION_ERROR, e);
 
173
                }
 
174
                return c;
 
175
        }
 
176
 
 
177
        /*
 
178
         * Receives an integer from the backend
 
179
         *
 
180
         * @param siz length of the integer in bytes
 
181
         * @return the integer received from the backend
 
182
         * @exception SQLException if an I/O error occurs
 
183
         */
 
184
        public int ReceiveInteger(int siz) throws SQLException
 
185
        {
 
186
                int n = 0;
 
187
 
 
188
                try
 
189
                {
 
190
                        for (int i = 0 ; i < siz ; i++)
 
191
                        {
 
192
                                int b = pg_input.read();
 
193
 
 
194
                                if (b < 0)
 
195
                                        throw new PSQLException("postgresql.stream.eof", PSQLState.COMMUNICATION_ERROR);
 
196
                                n = n | (b << (8 * i)) ;
 
197
                        }
 
198
                }
 
199
                catch (IOException e)
 
200
                {
 
201
                        throw new PSQLException("postgresql.stream.ioerror", PSQLState.COMMUNICATION_ERROR, e);
 
202
                }
 
203
                return n;
 
204
        }
 
205
 
 
206
        /*
 
207
         * Receives an integer from the backend
 
208
         *
 
209
         * @param siz length of the integer in bytes
 
210
         * @return the integer received from the backend
 
211
         * @exception SQLException if an I/O error occurs
 
212
         */
 
213
        public int ReceiveIntegerR(int siz) throws SQLException
 
214
        {
 
215
                int n = 0;
 
216
 
 
217
                try
 
218
                {
 
219
                        for (int i = 0 ; i < siz ; i++)
 
220
                        {
 
221
                                int b = pg_input.read();
 
222
 
 
223
                                if (b < 0)
 
224
                                        throw new PSQLException("postgresql.stream.eof", PSQLState.COMMUNICATION_ERROR);
 
225
                                n = b | (n << 8);
 
226
                        }
 
227
                }
 
228
                catch (IOException e)
 
229
                {
 
230
                        throw new PSQLException("postgresql.stream.ioerror", PSQLState.COMMUNICATION_ERROR, e);
 
231
                }
 
232
                return n;
 
233
        }
 
234
 
 
235
        /*
 
236
         * Receives a null-terminated string from the backend.  If we don't see a
 
237
         * null, then we assume something has gone wrong.
 
238
         *
 
239
         * @param encoding the charset encoding to use.
 
240
         * @return string from back end
 
241
         * @exception SQLException if an I/O error occurs, or end of file
 
242
         */
 
243
        public String ReceiveString(Encoding encoding)
 
244
        throws SQLException
 
245
        {
 
246
                int s = 0;
 
247
                byte[] rst = byte_buf;
 
248
                try
 
249
                {
 
250
                        int buflen = rst.length;
 
251
                        boolean done = false;
 
252
                        while (!done)
 
253
                        {
 
254
                                while (s < buflen)
 
255
                                {
 
256
                                        int c = pg_input.read();
 
257
                                        if (c < 0)
 
258
                                                throw new PSQLException("postgresql.stream.eof", PSQLState.COMMUNICATION_ERROR);
 
259
                                        else if (c == 0)
 
260
                                        {
 
261
                                                rst[s] = 0;
 
262
                                                done = true;
 
263
                                                break;
 
264
                                        }
 
265
                                        else
 
266
                                        {
 
267
                                                rst[s++] = (byte)c;
 
268
                                        }
 
269
                                        if (s >= buflen)
 
270
                                        { // Grow the buffer
 
271
                                                buflen = (int)(buflen * 2); // 100% bigger
 
272
                                                byte[] newrst = new byte[buflen];
 
273
                                                System.arraycopy(rst, 0, newrst, 0, s);
 
274
                                                rst = newrst;
 
275
                                        }
 
276
                                }
 
277
                        }
 
278
                }
 
279
                catch (IOException e)
 
280
                {
 
281
                        throw new PSQLException("postgresql.stream.ioerror", PSQLState.COMMUNICATION_ERROR, e);
 
282
                }
 
283
                return encoding.decode(rst, 0, s);
 
284
        }
 
285
 
 
286
        /*
 
287
         * Read a tuple from the back end.      A tuple is a two dimensional
 
288
         * array of bytes
 
289
         *
 
290
         * @param nf the number of fields expected
 
291
         * @return null if the current response has no more tuples, otherwise
 
292
         *      an array of strings
 
293
         * @exception SQLException if a data I/O error occurs
 
294
         */
 
295
        public byte[][] ReceiveTupleV3(int nf) throws SQLException
 
296
        {
 
297
                //TODO: use l_msgSize
 
298
                int l_msgSize = ReceiveIntegerR(4);
 
299
                int i;
 
300
                int l_nf = ReceiveIntegerR(2);
 
301
                byte[][] answer = new byte[l_nf][0];
 
302
                
 
303
                for (i = 0 ; i < l_nf ; ++i)
 
304
                {
 
305
                        int l_size = ReceiveIntegerR(4);
 
306
                        boolean isNull = l_size == -1;
 
307
                        if (isNull)
 
308
                                answer[i] = null;
 
309
                        else
 
310
                        {
 
311
                                answer[i] = Receive(l_size);
 
312
                        }
 
313
                }
 
314
                return answer;
 
315
        }
 
316
 
 
317
        /*
 
318
         * Read a tuple from the back end.      A tuple is a two dimensional
 
319
         * array of bytes
 
320
         *
 
321
         * @param nf the number of fields expected
 
322
         * @param bin true if the tuple is a binary tuple
 
323
         * @return null if the current response has no more tuples, otherwise
 
324
         *      an array of strings
 
325
         * @exception SQLException if a data I/O error occurs
 
326
         */
 
327
        public byte[][] ReceiveTupleV2(int nf, boolean bin) throws SQLException
 
328
        {
 
329
                int i, bim = (nf + 7) / 8;
 
330
                byte[] bitmask = Receive(bim);
 
331
                byte[][] answer = new byte[nf][0];
 
332
 
 
333
                int whichbit = 0x80;
 
334
                int whichbyte = 0;
 
335
 
 
336
                for (i = 0 ; i < nf ; ++i)
 
337
                {
 
338
                        boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
 
339
                        whichbit >>= 1;
 
340
                        if (whichbit == 0)
 
341
                        {
 
342
                                ++whichbyte;
 
343
                                whichbit = 0x80;
 
344
                        }
 
345
                        if (isNull)
 
346
                                answer[i] = null;
 
347
                        else
 
348
                        {
 
349
                                int len = ReceiveIntegerR(4);
 
350
                                if (!bin)
 
351
                                        len -= 4;
 
352
                                if (len < 0)
 
353
                                        len = 0;
 
354
                                answer[i] = Receive(len);
 
355
                        }
 
356
                }
 
357
                return answer;
 
358
        }
 
359
 
 
360
        /*
 
361
         * Reads in a given number of bytes from the backend
 
362
         *
 
363
         * @param siz number of bytes to read
 
364
         * @return array of bytes received
 
365
         * @exception SQLException if a data I/O error occurs
 
366
         */
 
367
        public byte[] Receive(int siz) throws SQLException
 
368
        {
 
369
                byte[] answer = new byte[siz];
 
370
                Receive(answer, 0, siz);
 
371
                return answer;
 
372
        }
 
373
 
 
374
        /*
 
375
         * Reads in a given number of bytes from the backend
 
376
         *
 
377
         * @param buf buffer to store result
 
378
         * @param off offset in buffer
 
379
         * @param siz number of bytes to read
 
380
         * @exception SQLException if a data I/O error occurs
 
381
         */
 
382
        public void Receive(byte[] b, int off, int siz) throws SQLException
 
383
        {
 
384
                int s = 0;
 
385
 
 
386
                try
 
387
                {
 
388
                        while (s < siz)
 
389
                        {
 
390
                                int w = pg_input.read(b, off + s, siz - s);
 
391
                                if (w < 0)
 
392
                                        throw new PSQLException("postgresql.stream.eof", PSQLState.COMMUNICATION_ERROR);
 
393
                                s += w;
 
394
                        }
 
395
                }
 
396
                catch (IOException e)
 
397
                {
 
398
                        throw new PSQLException("postgresql.stream.ioerror", PSQLState.COMMUNICATION_ERROR, e);
 
399
                }
 
400
        }
 
401
 
 
402
        /*
 
403
         * This flushes any pending output to the backend. It is used primarily
 
404
         * by the Fastpath code.
 
405
         * @exception SQLException if an I/O error occurs
 
406
         */
 
407
        public void flush() throws SQLException
 
408
        {
 
409
                try
 
410
                {
 
411
                        pg_output.flush();
 
412
                }
 
413
                catch (IOException e)
 
414
                {
 
415
                        throw new PSQLException("postgresql.stream.flush", PSQLState.COMMUNICATION_ERROR, e);
 
416
                }
 
417
        }
 
418
 
 
419
        /*
 
420
         * Closes the connection
 
421
         *
 
422
         * @exception IOException if a IO Error occurs
 
423
         */
 
424
        public void close() throws IOException
 
425
        {
 
426
                pg_output.close();
 
427
                pg_input.close();
 
428
                connection.close();
 
429
        }
 
430
}