2
2
* Copyright (C) 2008 EnterpriseDB Corporation.
3
3
* Copyright (C) 2011 Stado Global Development Group.
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.
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
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
5
* This file is part of Stado.
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.
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.
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/>.
19
20
* You can find Stado at http://www.stado.us
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;
94
97
private int backendKey = 0;
99
private String FormatPgErrorMsg(String msg) {
105
if (msg.length() > MAX_ERROR_MSG_SIZE)
107
m = msg.substring(0,MAX_ERROR_MSG_SIZE - 3) + "...";
113
// Split up the lines so we can handle them individually
114
String lines[] = m.split("\n");
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: ", "");
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: ");
127
String marker = "org.postgresql.driver.util.PSQLException :";
128
int h = f.indexOf(marker);
130
f = f.substring(h + marker.length() + 1);
136
private String FormatPgValue(Object o) {
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)
145
else if ((Boolean)o == false)
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();
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());
161
if (o instanceof byte[]) {
162
return new String(((byte[])o));
168
private String removeTrailingZeros(String str) {
172
char[] chars = str.toCharArray();int length,index ;length = str.length();
174
for (; index >=0;index--) {
175
if (chars[index] != '0') {
179
return (index == length-1) ? str :str.substring(0,index+1);
96
183
private PgProtocolMessage readRequest() throws IOException {
98
185
byte msgType = PgProtocolMessage.MESSAGE_TYPE_INITIAL;
242
329
error.putString("XX000");
244
331
error.putInt8('M');
245
if (ex.getMessage() != null
246
&& ex.getMessage().length() > MAX_ERROR_MSG_SIZE)
248
error.putString(ex.getMessage().substring(0,MAX_ERROR_MSG_SIZE - 3) + "...");
251
error.putString(ex.getMessage());
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,
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");
359
switch (response.getKind()) {
360
case ExecutionResult.COMMAND_BEGIN_TRAN:
361
m2.putString("BEGIN");
363
case ExecutionResult.COMMAND_COMMIT_TRAN:
364
m2.putString("COMMIT");
366
case ExecutionResult.COMMAND_ROLLBACK_TRAN:
367
m2.putString("ROLLBACK");
369
case ExecutionResult.COMMAND_CREATE_TABLE:
370
m2.putString("CREATE TABLE");
372
case ExecutionResult.COMMAND_DROP_TABLE:
373
m2.putString("DROP TABLE");
375
case ExecutionResult.COMMAND_CREATE_INDEX:
376
m2.putString("CREATE INDEX");
378
case ExecutionResult.COMMAND_SET:
381
case ExecutionResult.COMMAND_DECLARE_CURSOR:
382
m2.putString("DECLARE CURSOR");
384
case ExecutionResult.COMMAND_CLOSE_CURSOR:
385
m2.putString("CLOSE CURSOR");
288
391
writeToChannel(m2, channel);
290
393
case ExecutionResult.CONTENT_TYPE_SUBRESULTS:
302
405
msg.putInt16(count);
303
406
for (int i = 1; i <= count; i++) {
304
String value = rs.getString(i);
308
byte[] encoded = value.getBytes(CHARSET_NAME);
309
msg.putInt32(encoded.length);
310
msg.putBytes(encoded);
407
if (!(rs.getObject(i) instanceof byte[])) {
408
String value = FormatPgValue(rs.getObject(i));
412
byte[] encoded = value.getBytes(CHARSET_NAME);
413
msg.putInt32(encoded.length);
414
msg.putBytes(encoded);
417
byte[] b = (byte[]) rs.getObject(i);
421
msg.putInt32(b.length);
313
426
writeToChannel(msg, channel);
314
427
if (++rowCount == fetchSize && fetchSize > 0) {
1079
1192
* @throws IOException
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()));