~sgdg/stado/stado25

« back to all changes in this revision

Viewing changes to src/org/postgresql/stado/protocol/PgProtocolSession.java

  • Committer: Jim Mlodgenski
  • Date: 2011-08-30 22:39:37 UTC
  • mfrom: (1.1.3 stado)
  • Revision ID: jim@cirrusql.com-20110830223937-25q231a31x0e08b4
Merge from Spatial branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 * Copyright (C) 2008 EnterpriseDB Corporation.
3
3
 * Copyright (C) 2011 Stado Global Development Group.
4
4
 *
5
 
 * This program is free software; you can redistribute it and/or modify it
6
 
 * under the terms of the GNU General Public License version 2 as published by
7
 
 * the Free Software Foundation.
8
 
 *
9
 
 * This program is distributed in the hope that it will be useful, but WITHOUT
10
 
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
 
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12
 
 * more details.
13
 
 *
14
 
 * You should have received a copy of the GNU General Public License along
15
 
 * with this program; if not, see http://www.gnu.org/licenses or write to the
16
 
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17
 
 * 02110-1301 USA.
 
5
 * This file is part of Stado.
 
6
 *
 
7
 * Stado is free software: you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation, either version 3 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * Stado is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with Stado.  If not, see <http://www.gnu.org/licenses/>.
18
19
 *
19
20
 * You can find Stado at http://www.stado.us
20
21
 *
28
29
import java.io.InputStream;
29
30
import java.io.OutputStream;
30
31
import java.io.UnsupportedEncodingException;
 
32
import java.math.BigDecimal;
 
33
import java.math.MathContext;
31
34
import java.nio.ByteBuffer;
32
35
import java.nio.channels.SocketChannel;
33
36
import java.sql.ResultSet;
93
96
 
94
97
    private int backendKey = 0;
95
98
 
 
99
    private String FormatPgErrorMsg(String msg) {
 
100
        String m = "";
 
101
        
 
102
        if (msg == null) 
 
103
                return "Error";
 
104
        
 
105
        if (msg.length() > MAX_ERROR_MSG_SIZE)
 
106
        {
 
107
            m = msg.substring(0,MAX_ERROR_MSG_SIZE - 3) + "...";
 
108
        } else
 
109
        {
 
110
                m = msg;
 
111
        }
 
112
 
 
113
        // Split up the lines so we can handle them individually
 
114
        String lines[] = m.split("\n");
 
115
 
 
116
        // Remove the ERROR: prefix since we're going to put it back when we 
 
117
        // generate the error message later
 
118
        String f = lines[0].replaceFirst("ERROR: ", "");
 
119
 
 
120
        // Include the HINT in the message
 
121
        if (lines.length > 1) {
 
122
                if (lines[1].trim().startsWith("Hint:")) {
 
123
                        f = f + "\n" + lines[1].trim().replaceFirst("Hint:", "HINT: ");
 
124
                }
 
125
        }
 
126
        
 
127
        String marker = "org.postgresql.driver.util.PSQLException :";
 
128
        int h = f.indexOf(marker);
 
129
        if (h >=0) {
 
130
                f = f.substring(h + marker.length() + 1);
 
131
        }
 
132
        
 
133
        return f;
 
134
    }
 
135
 
 
136
    private String FormatPgValue(Object o) {
 
137
        if (o == null) 
 
138
                return null;
 
139
        
 
140
        // PostgreSQL returns a t or f over the wire for booleans not the 
 
141
        // Java Boolean values of true or false
 
142
        if (o instanceof Boolean) {
 
143
                if ((Boolean)o == true) 
 
144
                        return "t";
 
145
                else if ((Boolean)o == false)
 
146
                        return "f";
 
147
        }
 
148
        
 
149
        // PostgreSQL returns the integer value over the wire if a float
 
150
        // is really an integer ie 1.0 returns 1
 
151
        if (o instanceof Double) { 
 
152
                if (((Double)o).intValue() == ((Double)o).doubleValue())
 
153
                        return ((Integer)((Double)o).intValue()).toString();
 
154
                else {
 
155
                        // format the result because PostgreSQL will only return 15 digits of precision
 
156
                        BigDecimal bd = BigDecimal.valueOf(((Double)o));
 
157
                        return removeTrailingZeros(bd.round(new MathContext(15)).toString()); 
 
158
                }
 
159
        }
 
160
        
 
161
        if (o instanceof byte[]) {
 
162
                return new String(((byte[])o));
 
163
        }
 
164
        
 
165
        return o.toString();
 
166
    }
 
167
 
 
168
    private String removeTrailingZeros(String str) {
 
169
        if (str == null)
 
170
                return null;
 
171
        
 
172
        char[] chars = str.toCharArray();int length,index ;length = str.length();
 
173
        index = length -1;
 
174
        for (; index >=0;index--) {
 
175
                if (chars[index] != '0') {
 
176
                        break;
 
177
                }
 
178
        }
 
179
        return (index == length-1) ? str :str.substring(0,index+1);
 
180
    }
 
181
    
 
182
 
96
183
    private PgProtocolMessage readRequest() throws IOException {
97
184
        ByteBuffer bbuf;
98
185
        byte msgType = PgProtocolMessage.MESSAGE_TYPE_INITIAL;
242
329
            error.putString("XX000");
243
330
            // Message
244
331
            error.putInt8('M');
245
 
            if (ex.getMessage() != null
246
 
                    && ex.getMessage().length() > MAX_ERROR_MSG_SIZE)
247
 
            {
248
 
                error.putString(ex.getMessage().substring(0,MAX_ERROR_MSG_SIZE - 3) + "...");
249
 
            } else
250
 
            {
251
 
                error.putString(ex.getMessage());
252
 
            }
 
332
            error.putString(FormatPgErrorMsg(ex.getMessage()));
253
333
            // End of parameter list marker
254
334
            error.putInt8(0);
255
335
            writeToChannel(error, channel);
276
356
            PgProtocolMessage m2 = new PgProtocolMessage(
277
357
                    PgProtocolMessage.MESSAGE_TYPE_COMMAND_COMPLETE,
278
358
                    new byte[] {});
279
 
            if (response.getKind() == ExecutionResult.COMMAND_BEGIN_TRAN) {
280
 
                m2.putString("BEGIN");
281
 
            } else if (response.getKind() == ExecutionResult.COMMAND_COMMIT_TRAN) {
282
 
                m2.putString("COMMIT");
283
 
            } else if (response.getKind() == ExecutionResult.COMMAND_ROLLBACK_TRAN) {
284
 
                m2.putString("ROLLBACK");
285
 
            } else {
286
 
                m2.putString("OK");
287
 
            }
 
359
            switch (response.getKind()) {
 
360
                case ExecutionResult.COMMAND_BEGIN_TRAN:
 
361
                        m2.putString("BEGIN");
 
362
                        break;
 
363
                case ExecutionResult.COMMAND_COMMIT_TRAN:
 
364
                        m2.putString("COMMIT");
 
365
                        break;
 
366
                case ExecutionResult.COMMAND_ROLLBACK_TRAN:
 
367
                        m2.putString("ROLLBACK");
 
368
                        break;
 
369
                case ExecutionResult.COMMAND_CREATE_TABLE:
 
370
                        m2.putString("CREATE TABLE");
 
371
                        break;                          
 
372
                case ExecutionResult.COMMAND_DROP_TABLE:
 
373
                        m2.putString("DROP TABLE");
 
374
                        break;                          
 
375
                case ExecutionResult.COMMAND_CREATE_INDEX:
 
376
                        m2.putString("CREATE INDEX");
 
377
                        break;                          
 
378
                case ExecutionResult.COMMAND_SET:
 
379
                        m2.putString("SET");
 
380
                        break;      
 
381
                case ExecutionResult.COMMAND_DECLARE_CURSOR:
 
382
                        m2.putString("DECLARE CURSOR");
 
383
                        break;                                  
 
384
                case ExecutionResult.COMMAND_CLOSE_CURSOR:
 
385
                        m2.putString("CLOSE CURSOR");
 
386
                        break;                                  
 
387
                default:
 
388
                        m2.putString("OK");
 
389
                
 
390
        }
288
391
            writeToChannel(m2, channel);
289
392
            break;
290
393
        case ExecutionResult.CONTENT_TYPE_SUBRESULTS:
301
404
                            new byte[] {});
302
405
                    msg.putInt16(count);
303
406
                    for (int i = 1; i <= count; i++) {
304
 
                        String value = rs.getString(i);
305
 
                        if (value == null) {
306
 
                            msg.putInt32(-1);
307
 
                        } else {
308
 
                            byte[] encoded = value.getBytes(CHARSET_NAME);
309
 
                            msg.putInt32(encoded.length);
310
 
                            msg.putBytes(encoded);
311
 
                        }
 
407
                        if (!(rs.getObject(i) instanceof byte[])) {                                     
 
408
                                String value =  FormatPgValue(rs.getObject(i));
 
409
                                if (value == null) {
 
410
                                    msg.putInt32(-1);
 
411
                                } else {
 
412
                                    byte[] encoded = value.getBytes(CHARSET_NAME);
 
413
                                    msg.putInt32(encoded.length);
 
414
                                    msg.putBytes(encoded);
 
415
                                }
 
416
                        } else {
 
417
                                byte[] b = (byte[]) rs.getObject(i);
 
418
                                if (b == null) {
 
419
                                    msg.putInt32(-1);
 
420
                                } else {
 
421
                                    msg.putInt32(b.length);
 
422
                                    msg.putBytes(b);
 
423
                                }
 
424
                        }
312
425
                    }
313
426
                    writeToChannel(msg, channel);
314
427
                    if (++rowCount == fetchSize && fetchSize > 0) {
895
1008
 
896
1009
    /*
897
1010
     * Constants for well-known OIDs for the types we commonly use. Copy/paste
898
 
     * from org.postgresql.core.Oid then edit
 
1011
     * from org.postgresql.driver.core.Oid then edit
899
1012
     */
900
1013
    private static final int OID_INVALID = 0;
901
1014
 
1079
1192
         * @throws IOException
1080
1193
         */
1081
1194
        private boolean fill() throws IOException {
 
1195
                PgProtocolMessage message = null;
1082
1196
            while (!copydone) {
1083
 
                PgProtocolMessage message = readRequest();
 
1197
                message = readRequest();
1084
1198
                switch (message.getMessageType()) {
1085
1199
                case PgProtocolMessage.MESSAGE_TYPE_COPY_DATA:
1086
1200
                    bbuf = ByteBuffer.wrap(message.getBytes(message.getLength()));