Compare commits

..

58 Commits

Author SHA1 Message Date
opengauss_bot
9deecee765
!312 【6.0.0】处理utf8编码方式获取字符报错以及性能下降问题
Merge pull request !312 from zhangtingtingting/cherry-pick-1727182048
2024-09-24 13:57:46 +00:00
zhangting
f753d4bd52 处理utf8编码方式获取字符报错以及性能下降问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/e4be75548112956e249a852b2871e9b2d4ed0f8d>
2024-09-24 12:47:28 +00:00
opengauss_bot
d6e7926389
!309 【6.0.0】增加是否使用utf8Encode编码开关
Merge pull request !309 from zhangtingtingting/cherry-pick-1727013466
2024-09-22 16:11:19 +00:00
zhangting
68420e8e6b 增加utf8Decode解码功能开关
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/8d80383df6e16c642282f1515988c6117bc69b8a>
2024-09-22 13:57:48 +00:00
opengauss_bot
b8368ff2d3
!307 【6.0.0】jdbc增加cleanupSavepoints参数支持自动releaseSavePoint功能
Merge pull request !307 from zhangtingtingting/cherry-pick-1726044447
2024-09-11 11:42:07 +00:00
zhangting
788f81ac64 jdbc增加cleanupSavepoints参数支持自动releaseSavePoint功能
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/752d6c340fa442c538cf3c5cefb22ea31aa1d2e2>
2024-09-11 08:47:28 +00:00
opengauss_bot
6c4e2e2c8e
!306 【6.0.0】处理raw类型查询格式与blob不一致问题
Merge pull request !306 from zhangtingtingting/cherry-pick-1725963169
2024-09-11 01:08:17 +00:00
zhangting
3470f59aba 处理raw类型查询格式与blob不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/91896290f6a56a96b7a4e42c63ce8074d7e42c72>
2024-09-10 10:12:50 +00:00
opengauss_bot
0aaba1593e
!303 【回合6.0.0】处理b库默认返回类型为other问题
Merge pull request !303 from zhangtingtingting/cherry-pick-1725519170
2024-09-05 08:43:09 +00:00
zhangting
9de766ff5e 处理b库默认返回类型为other问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/3b35b13b8e9432801004d0888369433e937c5914>
2024-09-05 06:52:51 +00:00
opengauss_bot
d2c13a382a
!301 【回合6.0.0】处理jdbc查询binary类型与mysql不一致问题
Merge pull request !301 from zhangtingtingting/cherry-pick-1725361806
2024-09-03 11:24:09 +00:00
zhangting
8b52885512 处理jdbc查询binary类型与mysql不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/24dce297830aa46398111ba6cd78aa0c4a05a4c7>
2024-09-03 11:10:08 +00:00
opengauss_bot
58a073372f
!299 【回合6.0.0】处理b库查询blob类型与myql不一致问题
Merge pull request !299 from zhangtingtingting/cherry-pick-1725344373
2024-09-03 08:54:07 +00:00
zhangting
530fa97a21 处理b库查询blob类型与myql不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/4bb5ff66c4b4129121e339abf5dc552553e76611>
2024-09-03 06:19:33 +00:00
opengauss_bot
31ef5f1d1a
!297 【回合6.0.0】处理date类型查询结果与pg不一致问题
Merge pull request !297 from zhangtingtingting/cherry-pick-1725242328
2024-09-02 02:20:28 +00:00
zhangting
131ca764dc 处理date类型查询结果与pg不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/ff4e7d4a2364207cb4e1ef2fd59fcb58a21d59e8>
2024-09-02 01:58:50 +00:00
opengauss_bot
064cba2cbd
!295 【回合6.0.0】hiberate测b库兼容性decimal类型与mysql不一致
Merge pull request !295 from zhangtingtingting/cherry-pick-1724744669
2024-08-27 09:38:46 +00:00
zhangting
7e56979271 修复hiberate测b库兼容性decimal类型与mysql不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/8dea176ac9cdbae2967c3cd6d97ae1e4fda33a7e>
2024-08-27 07:44:32 +00:00
opengauss_bot
5170f925f2
!293 【回合6.0.0】修复blob类型调getBytes方法报错问题
Merge pull request !293 from zhangtingtingting/8.3.0
2024-08-26 01:18:09 +00:00
zhangting
f62c24b827 修复blob类型调getBytes方法报错问题 2024-08-24 10:55:10 +08:00
opengauss_bot
6a8bc6deee
!290 修复json返回类型跟mysql不一致问题
Merge pull request !290 from zhangtingtingting/7.9.1
2024-08-22 12:10:29 +00:00
opengauss_bot
c300a6200e
!289 【6.0.0】补充jdbc全链路跟踪自测用例
Merge pull request !289 from 蒋宏博/6.0.0
2024-08-22 02:56:42 +00:00
hwhbj
68eec62120 补充jdbc全链路跟踪自测用例 2024-08-21 20:16:23 +08:00
zhangting
b387c46ef0 修复json返回类型跟mysql不一致问题 2024-08-21 14:37:05 +08:00
opengauss_bot
5ad95b6c1b
!287 【回合】调getBytes方法获取bit类型值与mysql一致
Merge pull request !287 from zhangtingtingting/cherry-pick-1724140465
2024-08-20 11:14:11 +00:00
zhangting
9edf0960e3 调getBytes方法获取bit类型值与mysql一致
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/b47515a1c97de5905f09b23599286653ce62e029>
2024-08-20 07:54:26 +00:00
opengauss_bot
c9c3da0f40
!284 【回合】修复获取分区表的pk,index信息返回隐藏列问题
Merge pull request !284 from zhangtingtingting/cherry-pick-1724124403
2024-08-20 07:47:42 +00:00
opengauss_bot
be7a7a5540
!285 【回合】处理uint类型与mysql不一致问题
Merge pull request !285 from zhangtingtingting/cherry-pick-1724125130
2024-08-20 07:45:41 +00:00
opengauss_bot
d31ee74b88
!283 【回合】内核修改behavior_compat_options参数的设置导致jdbc门禁不通过
Merge pull request !283 from zhangtingtingting/cherry-pick-1724124264
2024-08-20 07:44:45 +00:00
zhangting
20c8fa07d2 处理uint类型与mysql不一致问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/50e55c2ba4e12fe728a0cf3ac13f7ef62a80ed06>
2024-08-20 03:38:50 +00:00
zhangting
5928968738 修复获取分区表的pk,index信息返回隐藏列问题
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/de99daf2a339eb7f625653af4a7aab2f5a6f07c5>
2024-08-20 03:26:43 +00:00
zhangting
3a89b8a6fb 内核修改behavior_compat_options参数的设置导致jdbc门禁不通过
(cherry picked commit from <gitee.com//opengauss/openGauss-connector-jdbc/commit/0a0233472ec7f67e2836f081bc9a2e5627432a52>
2024-08-20 03:24:27 +00:00
opengauss_bot
b3284871cb
!278 【6.0.0】删除冗余的server_support_trace,直接使用enable_record_nettime替代
Merge pull request !278 from 蒋宏博/6.0.0
2024-08-15 11:36:53 +00:00
hwhbj
7db8b18b7b 删除冗余的server_support_trace,直接使用enable_record_nettime替代 2024-08-15 16:44:58 +08:00
opengauss_bot
bcd86ea937
!277 【6.0.0】修复executeBatch场景下,statement和statement_history视图net_trans_time时间不一致的情况
Merge pull request !277 from 蒋宏博/6.0.0
2024-08-15 08:42:54 +00:00
hwhbj
f60b3e46cd 修复executeBatch场景下,statement和statement_history视图net_trans_time时间不一致的情况 2024-08-10 16:53:30 +08:00
opengauss_bot
1d725a663d
!269 jdbc占位符参数传null报错问题
Merge pull request !269 from zhangtingtingting/7.3.4
2024-08-06 11:05:40 +00:00
zhangting
e2e120dcdf jdbc占位符参数传null报错问题】 2024-08-06 15:00:10 +08:00
opengauss_bot
eafd425ce9
!268 处理year(2)类型返回值与mysql不一致问题
Merge pull request !268 from zhangtingtingting/7.3.3
2024-08-06 01:56:27 +00:00
zhangting
a833b54a9a 处理year(2)类型返回值与mysql不一致问题 2024-08-05 20:44:59 +08:00
opengauss_bot
548f6e466d
!265 处理timestampdiff函数处理带时区的数据报错
Merge pull request !265 from zhangtingtingting/7.3.1
2024-08-01 01:31:20 +00:00
zhangting
9ae8b65b08 解决timestampdiff函数处理带时区的数据报错问题 2024-07-31 19:03:34 +08:00
opengauss_bot
2edf316e07
!266 jdbc支持全链路跟踪
Merge pull request !266 from 蒋宏博/master
2024-07-30 13:00:02 +00:00
hwhbj
d858512eb3 jdbc支持全链路跟踪 2024-07-30 20:38:49 +08:00
opengauss_bot
547204b1ef
!255 处理sql注入漏洞问题
Merge pull request !255 from zhangtingtingting/7.2.7
2024-07-11 08:25:35 +00:00
opengauss_bot
b737bc0911
!253 支持显示numeric类型的负数scale
Merge pull request !253 from huangjiajun/master
2024-07-10 03:06:03 +00:00
huangjiajun
a4c5c21759 支持显示numeric类型的负数scale 2024-07-09 16:08:40 +08:00
opengauss_bot
bbabcfc345
!254 解决boolean数组类型报错问题
Merge pull request !254 from zhangtingtingting/7.3.0
2024-07-08 02:31:44 +00:00
zhangting
b62f7d2e7e 处理sql注入漏洞问题 2024-07-04 19:53:41 +08:00
zhangting
8cc4af4001 解决boolean数组类型报错问题 2024-07-03 16:42:08 +08:00
opengauss_bot
7f638fadaf
!252 对a、b库区分bit的返回类型
Merge pull request !252 from zhangtingtingting/7.2.7
2024-06-24 09:19:55 +00:00
zhangting
5e3d410269 对a、b库区分bit的返回类型 2024-06-24 10:00:07 +08:00
opengauss_bot
a02dbd0682
!249 【b兼容性】补充日期、时间相关类型测试用例
Merge pull request !249 from zhangtingtingting/7.2.6
2024-06-05 01:27:14 +00:00
zhangting
1f30d6147f 补充日期、时间相关类型测试用例 2024-05-31 15:40:35 +08:00
opengauss_bot
2a890c1178
!248 补充uint[]数组类型测试用例
Merge pull request !248 from zhangtingtingting/7.2.6
2024-05-31 01:27:04 +00:00
zhangting
6bae34a9db 补充uint[]数组类型测试用例 2024-05-30 17:48:15 +08:00
opengauss_bot
d329ab205a
!247 处理getObject()/getColumnType()获取tinyint(1)类型和值兼容B库与mysql不一致
Merge pull request !247 from zhangtingtingting/7.2.1
2024-05-28 07:37:41 +00:00
zhangting
b4b7b167f6 处理getObject()/getColumnType()获取tinyint(1)类型和值兼容B库与mysql不一致 2024-05-25 16:49:58 +08:00
54 changed files with 3426 additions and 611 deletions

View File

@ -612,6 +612,17 @@ public enum PGProperty {
B_CMPT_MODE("BCmptMode", "true", "Specify 'dolphin.b_compatibility_mode'"
+ " connection initialization parameter."),
/**
* Configure bit type format of b database, value include dec,bin,hex.
*/
BIT_OUTPUT("bitOutput", null, "Specify 'dolphin.bit_output' connection initialization parameter."),
/**
* Determine whether SAVEPOINTS used in AUTOSAVE will be released per query or not
*/
CLEANUP_SAVEPOINTS("cleanupSavepoints", "false", "Determine whether SAVEPOINTS "
+ "used in AUTOSAVE will be released per query or not", false, new String[]{"true", "false"})
;
private String _name;

View File

@ -10,6 +10,7 @@ import org.postgresql.jdbc.ClientLogic;
import org.postgresql.jdbc.FieldMetadata;
import org.postgresql.jdbc.PgStatement;
import org.postgresql.jdbc.TimestampUtils;
import org.postgresql.jdbc.PgDatabase;
import org.postgresql.log.Log;
import org.postgresql.util.LruCache;
import org.postgresql.xml.PGXmlFactoryFactory;
@ -246,4 +247,6 @@ public interface BaseConnection extends PGConnection, Connection {
public boolean IsBatchInsert();
public boolean isAdaptiveSetSQLType();
PgDatabase getPgDatabase();
}

View File

@ -13,6 +13,7 @@ import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import org.postgresql.log.Logger;
import org.postgresql.log.Log;
@ -27,7 +28,7 @@ public class Encoding {
private static Log LOGGER = Logger.getLogger(Encoding.class.getName());
private static final Encoding DEFAULT_ENCODING = new Encoding();
private static final Encoding UTF8_ENCODING = new Encoding("UTF-8");
private static final Encoding UTF8_ENCODING = new Encoding(StandardCharsets.UTF_8, true);
/*
* Preferred JVM encodings for backend encodings.
@ -79,27 +80,42 @@ public class Encoding {
encodings.put("LATIN10", new String[0]);
}
private final String encoding;
private final Charset encoding;
private final boolean fastASCIINumbers;
/**
* Uses the default charset of the JVM.
*/
private Encoding() {
this(Charset.defaultCharset().name());
this(Charset.defaultCharset());
}
/**
* Use the charset passed as parameter.
* Use the charset passed as parameter and tests at creation time whether
* the specified encoding is compatible with ASCII numbers.
*
* @param encoding charset name to use
*/
protected Encoding(String encoding) {
private Encoding(Charset encoding) {
this(encoding, testAsciiNumbers(encoding));
}
/**
* Subclasses may use this constructor if they know in advance of their
* ASCII number compatibility.
*
* @param encoding charset name to use
* @param isFastASCIINumbers whether this encoding is compatible with ASCII numbers.
*/
private Encoding(Charset encoding, boolean isFastASCIINumbers) {
if (encoding == null) {
throw new NullPointerException("Null encoding charset not supported");
}
this.encoding = encoding;
fastASCIINumbers = testAsciiNumbers();
this.fastASCIINumbers = isFastASCIINumbers;
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Creating new Encoding " + encoding + " with fastASCIINumbers " + isFastASCIINumbers);
}
}
/**
@ -120,11 +136,13 @@ public class Encoding {
* default JVM encoding if the specified encoding is unavailable.
*/
public static Encoding getJVMEncoding(String jvmEncoding) {
if (Charset.isSupported(jvmEncoding)) {
return new Encoding(jvmEncoding);
} else {
return DEFAULT_ENCODING;
if ("UTF-8".equals(jvmEncoding)) {
return UTF8_ENCODING;
}
if (Charset.isSupported(jvmEncoding)) {
return new Encoding(Charset.forName(jvmEncoding));
}
return DEFAULT_ENCODING;
}
/**
@ -135,7 +153,7 @@ public class Encoding {
* default JVM encoding if the specified encoding is unavailable.
*/
public static Encoding getDatabaseEncoding(String databaseEncoding) {
if ("UTF8".equals(databaseEncoding)) {
if ("UTF8".equals(databaseEncoding) || "UNICODE".equals(databaseEncoding)) {
return UTF8_ENCODING;
}
// If the backend encoding is known and there is a suitable
@ -144,9 +162,11 @@ public class Encoding {
String[] candidates = encodings.get(databaseEncoding);
if (candidates != null) {
for (String candidate : candidates) {
LOGGER.trace("Search encoding candidate " + candidate);
if (LOGGER.isTraceEnabled()) {
LOGGER.trace("Search encoding candidate " + candidate);
}
if (Charset.isSupported(candidate)) {
return new Encoding(candidate);
return new Encoding(Charset.forName(candidate));
}
}
}
@ -154,11 +174,13 @@ public class Encoding {
// Try the encoding name directly -- maybe the charset has been
// provided by the user.
if (Charset.isSupported(databaseEncoding)) {
return new Encoding(databaseEncoding);
return new Encoding(Charset.forName(databaseEncoding));
}
// Fall back to default JVM encoding.
LOGGER.trace(databaseEncoding + " encoding not found, returning default encoding");
if (LOGGER.isTraceEnabled()) {
LOGGER.trace(databaseEncoding + " encoding not found, returning default encoding");
}
return DEFAULT_ENCODING;
}
@ -168,7 +190,7 @@ public class Encoding {
* @return the JVM encoding name used by this instance.
*/
public String name() {
return Charset.isSupported(encoding) ? Charset.forName(encoding).name() : encoding;
return encoding.name();
}
/**
@ -242,30 +264,25 @@ public class Encoding {
return DEFAULT_ENCODING;
}
@Override
public String toString() {
return encoding;
return encoding.name();
}
/**
* Checks weather this encoding is compatible with ASCII for the number characters '-' and
* '0'..'9'. Where compatible means that they are encoded with exactly same values.
*
* @param encoding current encoding
* @return If faster ASCII number parsing can be used with this encoding.
*/
private boolean testAsciiNumbers() {
// TODO: test all postgres supported encoding to see if there are
private static boolean testAsciiNumbers(Charset encoding) {
// any which do _not_ have ascii numbers in same location
// at least all the encoding listed in the encodings hashmap have
// working ascii numbers
try {
String test = "-0123456789";
byte[] bytes = encode(test);
String res = new String(bytes, "US-ASCII");
return test.equals(res);
} catch (java.io.UnsupportedEncodingException e) {
return false;
} catch (IOException e) {
return false;
}
String test = "-0123456789";
byte[] bytes = test.getBytes(encoding);
String res = new String(bytes, StandardCharsets.US_ASCII);
return test.equals(res);
}
}

View File

@ -228,6 +228,19 @@ public class PGStream implements Closeable, Flushable {
pg_output.write(_int4buf);
}
/**
* Sends a Long to the back end.
*
* @param val the long to be sent
* @throws IOException if an I/O error occurs
*/
public void sendLong(long val) throws IOException {
int high = (int)(val >> 32);
int low = (int)(val & 0xffffffff);
sendInteger4(high);
sendInteger4(low);
}
/**
* Sends a 2-byte integer (short) to the back end.
*
@ -327,6 +340,18 @@ public class PGStream implements Closeable, Flushable {
| _int4buf[3] & 0xFF;
}
/**
* Receives a Long from the backend.
*
* @return the 64bit integer received from the backend
* @throws IOException if an I/O error occurs
*/
public long receiveLong() throws IOException {
long high = receiveInteger4();
long low = receiveInteger4();
return (high << 32) | low;
}
/**
* Receives a two byte integer from the backend.
*

View File

@ -90,8 +90,12 @@ public abstract class QueryExecutorBase implements QueryExecutor {
});
}
protected abstract void sendSupportTrace() throws IOException;
protected abstract void sendCloseMessage() throws IOException;
protected abstract void sendTrace() throws IOException;
@Override
public void setNetworkTimeout(int milliseconds) throws IOException {
pgStream.setNetworkTimeout(milliseconds);
@ -146,6 +150,7 @@ public abstract class QueryExecutorBase implements QueryExecutor {
try {
LOGGER.trace(" FE=> Terminate");
sendTrace();
sendCloseMessage();
pgStream.flush();
pgStream.close();

View File

@ -42,13 +42,6 @@ public interface TypeInfo {
*/
void setPGTypes() throws SQLException;
/**
* cache db type, A/B/C/PG
* cache b_compatibility_mode, on or off
* @return
*/
void setDBType() throws SQLException;
/**
* Look up the oid for a given postgresql type name. This is the inverse of
* {@link #getPGType(int)}.

View File

@ -1,168 +0,0 @@
/*
* Copyright (c) 2003, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.core;
import org.postgresql.util.GT;
import java.io.IOException;
class UTF8Encoding extends Encoding {
private static final int MIN_2_BYTES = 0x80;
private static final int MIN_3_BYTES = 0x800;
private static final int MIN_4_BYTES = 0x10000;
private static final int MAX_CODE_POINT = 0x10ffff;
private char[] decoderArray = new char[1024];
UTF8Encoding(String jvmEncoding) {
super(jvmEncoding);
}
// helper for decode
private static void checkByte(int ch, int pos, int len) throws IOException {
if ((ch & 0xc0) != 0x80) {
throw new IOException(
GT.tr("Illegal UTF-8 sequence: byte {0} of {1} byte sequence is not 10xxxxxx: {2}",
pos, len, ch));
}
}
private static void checkMinimal(int ch, int minValue) throws IOException {
if (ch >= minValue) {
return;
}
int actualLen;
switch (minValue) {
case MIN_2_BYTES:
actualLen = 2;
break;
case MIN_3_BYTES:
actualLen = 3;
break;
case MIN_4_BYTES:
actualLen = 4;
break;
default:
throw new IllegalArgumentException(
"unexpected minValue passed to checkMinimal: " + minValue);
}
int expectedLen;
if (ch < MIN_2_BYTES) {
expectedLen = 1;
} else if (ch < MIN_3_BYTES) {
expectedLen = 2;
} else if (ch < MIN_4_BYTES) {
expectedLen = 3;
} else {
throw new IllegalArgumentException("unexpected ch passed to checkMinimal: " + ch);
}
throw new IOException(
GT.tr("Illegal UTF-8 sequence: {0} bytes used to encode a {1} byte value: {2}",
actualLen, expectedLen, ch));
}
/**
* Custom byte[] -> String conversion routine for UTF-8 only. This is about twice as fast as using
* the String(byte[],int,int,String) ctor, at least under JDK 1.4.2. The extra checks for illegal
* representations add about 10-15% overhead, but they seem worth it given the number of SQL_ASCII
* databases out there.
*
* @param data the array containing UTF8-encoded data
* @param offset the offset of the first byte in {@code data} to decode from
* @param length the number of bytes to decode
* @return a decoded string
* @throws IOException if something goes wrong
*/
@Override
public synchronized String decode(byte[] data, int offset, int length) throws IOException {
char[] cdata = decoderArray;
if (cdata.length < length) {
cdata = decoderArray = new char[length];
}
int in = offset;
int out = 0;
int end = length + offset;
try {
while (in < end) {
int ch = data[in++] & 0xff;
// Convert UTF-8 to 21-bit codepoint.
if (ch < 0x80) {
// 0xxxxxxx -- length 1.
} else if (ch < 0xc0) {
// 10xxxxxx -- illegal!
throw new IOException(GT.tr("Illegal UTF-8 sequence: initial byte is {0}: {1}",
"10xxxxxx", ch));
} else if (ch < 0xe0) {
// 110xxxxx 10xxxxxx
ch = ((ch & 0x1f) << 6);
checkByte(data[in], 2, 2);
ch = ch | (data[in++] & 0x3f);
checkMinimal(ch, MIN_2_BYTES);
} else if (ch < 0xf0) {
// 1110xxxx 10xxxxxx 10xxxxxx
ch = ((ch & 0x0f) << 12);
checkByte(data[in], 2, 3);
ch = ch | ((data[in++] & 0x3f) << 6);
checkByte(data[in], 3, 3);
ch = ch | (data[in++] & 0x3f);
checkMinimal(ch, MIN_3_BYTES);
} else if (ch < 0xf8) {
// 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
ch = ((ch & 0x07) << 18);
checkByte(data[in], 2, 4);
ch = ch | ((data[in++] & 0x3f) << 12);
checkByte(data[in], 3, 4);
ch = ch | ((data[in++] & 0x3f) << 6);
checkByte(data[in], 4, 4);
ch = ch | (data[in++] & 0x3f);
checkMinimal(ch, MIN_4_BYTES);
} else {
throw new IOException(GT.tr("Illegal UTF-8 sequence: initial byte is {0}: {1}",
"11111xxx", ch));
}
if (ch > MAX_CODE_POINT) {
throw new IOException(
GT.tr("Illegal UTF-8 sequence: final value is out of range: {0}", ch));
}
// Convert 21-bit codepoint to Java chars:
// 0..ffff are represented directly as a single char
// 10000..10ffff are represented as a "surrogate pair" of two chars
// See: http://java.sun.com/developer/technicalArticles/Intl/Supplementary/
if (ch > 0xffff) {
// Use a surrogate pair to represent it.
ch -= 0x10000; // ch is now 0..fffff (20 bits)
cdata[out++] = (char) (0xd800 + (ch >> 10)); // top 10 bits
cdata[out++] = (char) (0xdc00 + (ch & 0x3ff)); // bottom 10 bits
} else if (ch >= 0xd800 && ch < 0xe000) {
// Not allowed to encode the surrogate range directly.
throw new IOException(
GT.tr("Illegal UTF-8 sequence: final value is a surrogate value: {0}", ch));
} else {
// Normal case.
cdata[out++] = (char) ch;
}
}
} catch (ArrayIndexOutOfBoundsException a) {
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
}
// Check if we ran past the end without seeing an exception.
if (in > end) {
throw new IOException("Illegal UTF-8 sequence: multibyte sequence was truncated");
}
return new String(cdata, 0, out);
}
}

View File

@ -126,6 +126,16 @@ public class QueryExecutorImpl extends QueryExecutorBase {
private String clientEncoding;
private long sendTime;
private long recvTime;
private long netTime;
private boolean enableTrace = false;
private boolean waitNexttime = false;
/**
* {@code CommandComplete(B)} messages are quite common, so we reuse instance to parse those
*/
@ -157,11 +167,18 @@ public class QueryExecutorImpl extends QueryExecutorBase {
private static final String OFF = "off";
private static final String GUC_SERVER_SUPPORT_TRACE = "enable_record_nettime";
private static final int PROTOCOL3_MSGLEN_OFFSET = 4;
private static final int TIME_NS_ONE_US = 1000;
public QueryExecutorImpl(PGStream pgStream, String user, String database,
int cancelSignalTimeout, Properties info) throws SQLException, IOException {
super(pgStream, user, database, cancelSignalTimeout, info);
this.allowEncodingChanges = PGProperty.ALLOW_ENCODING_CHANGES.getBoolean(info);
this.cleanupSavePoints = PGProperty.CLEANUP_SAVEPOINTS.getBoolean(info);
this.replicationProtocol = new V3ReplicationProtocol(this, pgStream);
this.socketAddress = pgStream.getConnectInfo();
this.secSocketAddress = pgStream.getSecConnectInfo();
@ -222,6 +239,14 @@ public class QueryExecutorImpl extends QueryExecutorBase {
return this.clientEncoding;
}
public boolean getWaitNexttime() {
return waitNexttime;
}
public void setWaitNexttime(boolean waitNexttime) {
this.waitNexttime = waitNexttime;
}
/**
* When database compatibility mode is A database and the parameter overload function
* is turned on, add out parameter description message.
@ -294,6 +319,14 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
}
private void recordSendTime() {
sendTime = System.nanoTime();
}
private void recordRecvTime() {
recvTime = System.nanoTime();
}
/**
* @param holder object assumed to hold the lock
* @return whether given object actually holds the lock
@ -363,6 +396,10 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
}
private boolean isSimpleQuery(int flags) {
return (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0;
}
public synchronized void execute(Query query, ParameterList parameters, ResultHandler handler,
int maxRows, int fetchSize, int flags) throws SQLException {
waitOnLock();
@ -388,6 +425,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
boolean autosave = false;
try {
try {
recordAndSendTrace(flags);
handler = sendQueryPreamble(handler, flags);
autosave = sendAutomaticSavepoint(query, flags);
sendQuery(query, (V3ParameterList) parameters, maxRows, fetchSize, flags,
@ -432,11 +470,26 @@ public class QueryExecutorImpl extends QueryExecutorBase {
try {
handler.handleCompletion();
if (cleanupSavePoints) {
releaseSavePoint(autosave, flags);
}
} catch (SQLException e) {
rollbackIfRequired(autosave, e);
}
}
private void releaseSavePoint(boolean autosave, int flags) throws SQLException {
if (autosave && getAutoSave() == AutoSave.ALWAYS
&& getTransactionState() == TransactionState.OPEN) {
try {
sendOneQuery(releaseAutoSave, SimpleQuery.NO_PARAMETERS, 1, 0,
QUERY_NO_RESULTS | QUERY_NO_METADATA | QUERY_EXECUTE_AS_SIMPLE);
} catch (IOException ex) {
throw new PSQLException(GT.tr("Error releasing savepoint"), PSQLState.IO_ERROR);
}
}
}
private boolean sendAutomaticSavepoint(Query query, int flags) throws IOException {
if (((flags & QueryExecutor.QUERY_SUPPRESS_BEGIN) == 0
|| getTransactionState() == TransactionState.OPEN)
@ -546,6 +599,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
boolean autosave = false;
ResultHandler handler = batchHandler;
try {
recordAndSendTrace(flags);
handler = sendQueryPreamble(batchHandler, flags);
autosave = sendAutomaticSavepoint(queries[0], flags);
estimatedReceiveBufferBytes = 0;
@ -584,6 +638,9 @@ public class QueryExecutorImpl extends QueryExecutorBase {
try {
handler.handleCompletion();
if (cleanupSavePoints) {
releaseSavePoint(autosave, flags);
}
} catch (SQLException e) {
rollbackIfRequired(autosave, e);
}
@ -619,6 +676,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
boolean autosave = false;
ResultHandler handler = batchHandler;
try {
// P->DS->S U->E->S
recordAndSendTrace(flags);
handler = sendQueryPreamble(batchHandler, flags);
autosave = sendAutomaticSavepoint(queries[0], flags);
estimatedReceiveBufferBytes = 0;
@ -648,6 +707,9 @@ public class QueryExecutorImpl extends QueryExecutorBase {
try {
handler.handleCompletion();
if (cleanupSavePoints) {
releaseSavePoint(autosave, flags);
}
} catch (SQLException e) {
rollbackIfRequired(autosave, e);
}
@ -748,6 +810,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
};
try {
recordAndSendTrace(QueryExecutor.QUERY_NO_METADATA);
sendOneQuery(beginTransactionQuery, SimpleQuery.NO_PARAMETERS, 0, 0,
QueryExecutor.QUERY_NO_METADATA);
sendSync();
@ -1564,6 +1627,32 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
}
//
// record sendTime and send K message.
//
private void recordAndSendTrace(int flags) throws IOException {
if (!isSimpleQuery(flags)) {
recordSendTime();
}
sendTrace();
}
//
// send netTime to database
//
protected void sendTrace() throws IOException {
if (!enableTrace) {
return;
}
pgStream.sendChar('K'); // Sync
pgStream.sendInteger4(8 + PROTOCOL3_MSGLEN_OFFSET); // Length
if (getWaitNexttime()) {
pgStream.sendLong(0L);
return;
}
pgStream.sendLong(netTime);
}
//
// Message sending
//
@ -2142,11 +2231,12 @@ public class QueryExecutorImpl extends QueryExecutorBase {
//
private void sendOneQuery(SimpleQuery query, SimpleParameterList params, int maxRows,
int fetchSize, int flags) throws IOException {
boolean asSimple = (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) != 0;
boolean asSimple = isSimpleQuery(flags);
if (asSimple) {
assert (flags & QueryExecutor.QUERY_DESCRIBE_ONLY) == 0
: "Simple mode does not support describe requests. sql = " + query.getNativeSql()
+ ", flags = " + flags;
recordSendTime();
sendSimpleQuery(query, params);
return;
}
@ -2445,10 +2535,25 @@ public class QueryExecutorImpl extends QueryExecutorBase {
// from there.
boolean doneAfterRowDescNoData = false;
try {
boolean isRecvP = false;
while (!endQuery) {
c = pgStream.receiveChar();
recievedPacketType=c;
switch (c) {
case 'K': //receive dbTime
recordRecvTime();
int msgLen = pgStream.receiveInteger4();
// dbTime 8 bytes
assert (msgLen == 8 + PROTOCOL3_MSGLEN_OFFSET);
long dbTime = pgStream.receiveLong();
if (getWaitNexttime()) {
netTime += ((recvTime - sendTime) / TIME_NS_ONE_US) - dbTime;
} else {
netTime = ((recvTime - sendTime) / TIME_NS_ONE_US) - dbTime;
}
isRecvP = true;
break;
case 'A': // Asynchronous Notify
receiveAsyncNotify();
break;
@ -2593,8 +2698,8 @@ public class QueryExecutorImpl extends QueryExecutorBase {
// For simple 'Q' queries, executeQueue is cleared via ReadyForQuery message
}
if (currentQuery == autoSaveQuery) {
// ignore "SAVEPOINT" status from autosave query
if (currentQuery == autoSaveQuery || currentQuery == releaseAutoSave) {
// ignore "SAVEPOINT" or RELEASE SAVEPOINT status from autosave query
break;
}
@ -2836,7 +2941,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
throw new IOException("Unexpected packet type: " + c);
}
}
enableTrace = isRecvP;
} catch(IOException e) {
LOGGER.error("IO Exception.recieved packetType:" + recievedPacketType + "last PacketType:" + lastPacketType
+ "connection info:" + secSocketAddress + "buffer :\n" + pgStream.getInputBufferByHex());
@ -2877,6 +2982,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
processDeadParsedQueries();
processDeadPortals();
recordAndSendTrace(0);
sendExecute(portal.getQuery(), portal, fetchSize);
sendSync();
@ -2916,6 +3022,9 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
int typeLength = pgStream.receiveInteger2();
int typeModifier = pgStream.receiveInteger4();
if (typeOid == Oid.INT1 && typeModifier == 1) {
typeOid = Oid.BIT;
}
int formatType = pgStream.receiveInteger2();
fields[i] = new Field(columnLabel,
typeOid, typeLength, typeModifier, tableOid, positionInTable);
@ -3056,6 +3165,12 @@ public class QueryExecutorImpl extends QueryExecutorBase {
}
}
protected void sendSupportTrace() throws IOException {
pgStream.sendChar('V');
pgStream.sendInteger4(4);
pgStream.flush();
}
@Override
protected void sendCloseMessage() throws IOException {
pgStream.sendChar('X');
@ -3122,6 +3237,11 @@ public class QueryExecutorImpl extends QueryExecutorBase {
String name = pgStream.receiveString();
String value = pgStream.receiveString();
if (name.equals(GUC_SERVER_SUPPORT_TRACE)) {
// receive GUC_SERVER_SUPPORT_TRACE from server means server support trace
sendSupportTrace();
}
if (name.equals(CLIENT_ENCODING)) {
if (allowEncodingChanges) {
if (!value.equalsIgnoreCase("UTF8") && !value.equalsIgnoreCase("GBK")) {
@ -3291,6 +3411,7 @@ public class QueryExecutorImpl extends QueryExecutorBase {
private long nextUniqueID = 1;
private final boolean allowEncodingChanges;
private final boolean cleanupSavePoints;
private String output = "";
@ -3320,6 +3441,11 @@ public class QueryExecutorImpl extends QueryExecutorBase {
new NativeQuery("SAVEPOINT PGJDBC_AUTOSAVE", new int[0], false, SqlCommand.BLANK),
null, false);
private final SimpleQuery releaseAutoSave =
new SimpleQuery(
new NativeQuery("RELEASE SAVEPOINT PGJDBC_AUTOSAVE", new int[0], false, SqlCommand.BLANK),
null, false);
private final SimpleQuery restoreToAutoSave =
new SimpleQuery(
new NativeQuery("ROLLBACK TO SAVEPOINT PGJDBC_AUTOSAVE", new int[0], false, SqlCommand.BLANK),

View File

@ -229,93 +229,142 @@ class SimpleParameterList implements V3ParameterList {
bind(index, NULL_OBJECT, oid, binaryTransfer);
}
/**
* <p>Escapes a given text value as a literal, wraps it in single quotes, casts it to the
* to the given data type, and finally wraps the whole thing in parentheses.</p>
*
* <p>For example, "123" and "int4" becomes "('123'::int)"</p>
*
* <p>The additional parentheses is added to ensure that the surrounding text of where the
* parameter value is entered does modify the interpretation of the value.</p>
*
* <p>For example if our input SQL is: <code>SELECT ?b</code></p>
*
* <p>Using a parameter value of '{}' and type of json we'd get:</p>
*
* <pre>
* test=# SELECT ('{}'::json)b;
* b
* ----
* {}
* </pre>
*
* <p>But without the parentheses the result changes:</p>
*
* <pre>
* test=# SELECT '{}'::jsonb;
* jsonb
* -------
* {}
* </pre>
**/
private static String quoteAndCast(String text, String type, boolean standardConformingStrings) {
StringBuilder sb = new StringBuilder((text.length() + 10) / 10 * 11); // Add 10% for escaping.
sb.append("('");
try {
Utils.escapeLiteral(sb, text, standardConformingStrings);
} catch (SQLException e) {
// This should only happen if we have an embedded null
// and there's not much we can do if we do hit one.
//
// To force a server side failure, we deliberately include
// a zero byte character in the literal to force the server
// to reject the command.
sb.append('\u0000');
}
sb.append("'");
if (type != null) {
sb.append("::");
sb.append(type);
}
sb.append(")");
return sb.toString();
}
@Override
public String toString(int index, boolean standardConformingStrings) {
--index;
Object paramValue = paramValues[index];
if (paramValues[index] == null) {
return "?";
} else if (paramValues[index] == NULL_OBJECT) {
return "NULL";
return "(NULL)";
} else if ((flags[index] & BINARY) == BINARY) {
// handle some of the numeric types
switch (paramTypes[index]) {
case Oid.INT2:
short s = ByteConverter.int2((byte[]) paramValues[index], 0);
return Short.toString(s);
return quoteAndCast(Short.toString(s), "int2", standardConformingStrings);
case Oid.INT4:
int i = ByteConverter.int4((byte[]) paramValues[index], 0);
return Integer.toString(i);
return quoteAndCast(Integer.toString(i), "int4", standardConformingStrings);
case Oid.INT8:
long l = ByteConverter.int8((byte[]) paramValues[index], 0);
return Long.toString(l);
return quoteAndCast(Long.toString(l), "int8", standardConformingStrings);
case Oid.FLOAT4:
float f = ByteConverter.float4((byte[]) paramValues[index], 0);
return Float.toString(f);
if (Float.isNaN(f)) {
return "('NaN'::real)";
}
return quoteAndCast(Float.toString(f), "float", standardConformingStrings);
case Oid.FLOAT8:
double d = ByteConverter.float8((byte[]) paramValues[index], 0);
return Double.toString(d);
if (Double.isNaN(d)) {
return "('NaN'::double precision)";
}
return quoteAndCast(Double.toString(d), "double precision", standardConformingStrings);
case Oid.NUMERIC:
Number n = ByteConverter.numeric((byte[]) paramValue);
if (n instanceof Double) {
assert ((Double) n).isNaN();
return "('NaN'::numeric)";
}
return n.toString();
case Oid.UUID:
String uuid =
new UUIDArrayAssistant().buildElement((byte[]) paramValues[index], 0, 16).toString();
return "'" + uuid + "'::uuid";
new UUIDArrayAssistant().buildElement((byte[]) paramValues[index], 0, 16).toString();
return quoteAndCast(uuid, "uuid", standardConformingStrings);
case Oid.POINT:
PGpoint pgPoint = new PGpoint();
pgPoint.setByteValue((byte[]) paramValues[index], 0);
return "'" + pgPoint.toString() + "'::point";
return quoteAndCast(pgPoint.toString(), "point", standardConformingStrings);
case Oid.BOX:
PGbox pgBox = new PGbox();
pgBox.setByteValue((byte[]) paramValues[index], 0);
return "'" + pgBox.toString() + "'::box";
return quoteAndCast(pgBox.toString(), "box", standardConformingStrings);
}
return "?";
} else if (paramValues[index] instanceof Struct) {
Struct struct = (Struct) paramValues[index];
return struct.toString();
} else {
String param = paramValues[index].toString();
// add room for quotes + potential escaping.
StringBuilder p = new StringBuilder(3 + (param.length() + 10) / 10 * 11);
// No E'..' here since escapeLiteral escapes all things and it does not use \123 kind of
// escape codes
p.append('\'');
try {
p = Utils.escapeLiteral(p, param, standardConformingStrings);
} catch (SQLException sqle) {
// This should only happen if we have an embedded null
// and there's not much we can do if we do hit one.
//
// The goal of toString isn't to be sent to the server,
// so we aren't 100% accurate (see StreamWrapper), put
// the unescaped version of the data.
//
p.append(param);
}
p.append('\'');
String param = paramValue.toString();
int paramType = paramTypes[index];
if (paramType == Oid.TIMESTAMP) {
p.append("::timestamp");
return quoteAndCast(param, "timestamp", standardConformingStrings);
} else if (paramType == Oid.TIMESTAMPTZ) {
p.append("::timestamp with time zone");
return quoteAndCast(param, "timestamp with time zone", standardConformingStrings);
} else if (paramType == Oid.TIME) {
p.append("::time");
return quoteAndCast(param, "time", standardConformingStrings);
} else if (paramType == Oid.TIMETZ) {
p.append("::time with time zone");
return quoteAndCast(param, "time with time zone", standardConformingStrings);
} else if (paramType == Oid.DATE) {
p.append("::date");
return quoteAndCast(param, "date", standardConformingStrings);
} else if (paramType == Oid.INTERVAL) {
p.append("::interval");
return quoteAndCast(param, "interval", standardConformingStrings);
} else if (paramType == Oid.NUMERIC) {
return quoteAndCast(param, "numeric", standardConformingStrings);
}
return p.toString();
return quoteAndCast(param, null, standardConformingStrings);
}
}

View File

@ -1431,6 +1431,22 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
PGProperty.AUTOSAVE.set(properties, autoSave.value());
}
/**
* see PGProperty#CLEANUP_SAVEPOINTS
* @return boolean indicating property set
*/
public boolean getCleanupSavepoints() {
return PGProperty.CLEANUP_SAVEPOINTS.getBoolean(properties);
}
/**
* see PGProperty#CLEANUP_SAVEPOINTS
* @param cleanupSavepoints will cleanup savepoints after a successful transaction
*/
public void setCleanupSavepoints(boolean cleanupSavepoints) {
PGProperty.CLEANUP_SAVEPOINTS.set(properties, cleanupSavepoints);
}
/**
* @see PGProperty#REWRITE_BATCHED_INSERTS
* @return boolean indicating property is enabled or not.
@ -1447,6 +1463,14 @@ public abstract class BaseDataSource implements CommonDataSource, Referenceable
PGProperty.REWRITE_BATCHED_INSERTS.set(properties, reWrite);
}
public boolean isCleanupSavePoints() {
return getCleanupSavepoints();
}
public void setCleanupSavePoints(final boolean cleanupSavepoints) {
setCleanupSavepoints(cleanupSavepoints);
}
public java.util.logging.Logger getParentLogger() {
if(org.postgresql.log.Logger.isUsingJDKLogger()){
return java.util.logging.Logger.getLogger("org.postgresql");

View File

@ -560,7 +560,7 @@ public class PgArray implements java.sql.Array {
final int type =
connection.getTypeInfo().getSQLType(connection.getTypeInfo().getPGArrayElement(oid));
if (type == Types.BIT) {
if (type == Types.BIT || type == Types.BOOLEAN) {
boolean[] pa = null; // primitive array
Object[] oa = null; // objects array
@ -656,7 +656,7 @@ public class PgArray implements java.sql.Array {
pa[length++] = o == null ? 0L : PgResultSet.toLong((String) o);
}
}
} else if (type == Types.NUMERIC) {
} else if (type == Types.NUMERIC || type == Types.DECIMAL) {
Object[] oa = null;
ret = oa =
(dims > 1 ? (Object[]) java.lang.reflect.Array.newInstance(BigDecimal.class, dimsLength)

View File

@ -181,7 +181,7 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme
}
int columnType = rs.getMetaData().getColumnType(i + 1);
if (columnType == Types.NUMERIC) {
if (columnType == Types.NUMERIC || columnType == Types.DECIMAL) {
callResult[j] = rs.getBigDecimal(i + 1);
} else {
callResult[j] = rs.getObject(i + 1);
@ -251,8 +251,8 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme
case Types.LONGVARCHAR:
sqlType = Types.VARCHAR;
break;
case Types.DECIMAL:
sqlType = Types.NUMERIC;
case Types.NUMERIC:
sqlType = Types.DECIMAL;
break;
case Types.FLOAT:
// float is the same as double
@ -598,7 +598,7 @@ class PgCallableStatement extends PgPreparedStatement implements CallableStateme
public java.math.BigDecimal getBigDecimal(int parameterIndex) throws SQLException {
checkClosed();
checkIndex(parameterIndex, Types.NUMERIC, "BigDecimal");
checkIndex(parameterIndex, Types.DECIMAL, "BigDecimal");
try {
return ((BigDecimal) callResult[parameterIndex - 1]);
}catch(Exception e) {

View File

@ -198,7 +198,9 @@ public class PgConnection implements BaseConnection {
private String socketAddress;
private String secSocketAddress;
private boolean adaptiveSetSQLType = false;
private boolean isDolphinCmpt = false;
private boolean isDolphinCmpt = false;
private PgDatabase pgDatabase;
final CachedQuery borrowQuery(String sql) throws SQLException {
return queryExecutor.borrowQuery(sql);
}
@ -228,6 +230,10 @@ public class PgConnection implements BaseConnection {
LOGGER.debug(" setFlushCacheOnDeallocate = " + flushCacheOnDeallocate);
}
public PgDatabase getPgDatabase() {
return pgDatabase;
}
//
// Ctor.
//
@ -312,6 +318,19 @@ public class PgConnection implements BaseConnection {
bindStringAsVarchar = true;
}
/* set dolphin.b_compatibility_mode to the value of PGProperty.B_CMPT_MODE */
this.setDolphinCmpt(PGProperty.B_CMPT_MODE.getBoolean(info));
int unknownLength = PGProperty.UNKNOWN_LENGTH.getInt(info);
// Initialize object handling
_typeCache = createTypeInfo(this, unknownLength);
_typeCache.setPGTypes();
initObjectTypes(info);
pgDatabase = new PgDatabase(this);
pgDatabase.setDolphin(info);
// Initialize timestamp stuff
timestampUtils = new TimestampUtils(!queryExecutor.getIntegerDateTimes(), new Provider<TimeZone>() {
@Override
@ -320,6 +339,7 @@ public class PgConnection implements BaseConnection {
}
});
timestampUtils.setTimestampNanoFormat(PGProperty.TIMESTAMP_NANO_FORMAT.getInteger(info));
timestampUtils.setDolphin(pgDatabase.isDolphin());
// Initialize common queries.
// isParameterized==true so full parse is performed and the engine knows the query
@ -327,14 +347,6 @@ public class PgConnection implements BaseConnection {
commitQuery = createQuery("COMMIT", false, true).query;
rollbackQuery = createQuery("ROLLBACK", false, true).query;
int unknownLength = PGProperty.UNKNOWN_LENGTH.getInt(info);
// Initialize object handling
_typeCache = createTypeInfo(this, unknownLength);
_typeCache.setPGTypes();
_typeCache.setDBType();
initObjectTypes(info);
if (PGProperty.LOG_UNCLOSED_CONNECTIONS.getBoolean(info)) {
openStackTrace = new Throwable("Connection was created at this point:");
}
@ -345,7 +357,11 @@ public class PgConnection implements BaseConnection {
_typeCache.addCoreType("xml", Oid.XML, Types.SQLXML, "java.sql.SQLXML", Oid.XML_ARRAY);
}
_typeCache.addCoreType("clob", Oid.CLOB, Types.CLOB, "java.sql.CLOB", Oid.UNSPECIFIED);
_typeCache.addCoreType("blob", Oid.BLOB, Types.BLOB, "java.sql.BLOB", Oid.UNSPECIFIED);
int blobType = Types.BLOB;
if (pgDatabase.isDolphin()) {
blobType = Types.LONGVARBINARY;
}
_typeCache.addCoreType("blob", Oid.BLOB, blobType, "java.sql.BLOB", Oid.UNSPECIFIED);
this._clientInfo = new Properties();
if (haveMinimumServerVersion(ServerVersion.v9_0)) {
@ -465,11 +481,8 @@ public class PgConnection implements BaseConnection {
batchInsert = false;
}
/* set dolphin.b_compatibility_mode to the value of PGProperty.B_CMPT_MODE */
this.setDolphinCmpt(PGProperty.B_CMPT_MODE.getBoolean(info));
adaptiveSetSQLType = PGProperty.ADAPTIVE_SET_SQL_TYPE.getBoolean(info);
initClientLogic(info);
}

View File

@ -0,0 +1,96 @@
package org.postgresql.jdbc;
import org.postgresql.PGProperty;
import org.postgresql.core.BaseStatement;
import org.postgresql.core.QueryExecutor;
import org.postgresql.util.CompatibilityEnum;
import org.postgresql.util.GT;
import org.postgresql.util.PSQLException;
import org.postgresql.util.PSQLState;
import org.postgresql.util.BitOutputEnum;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Locale;
import java.util.Properties;
public class PgDatabase {
private PgConnection connection;
private boolean isDolphin;
private boolean isDec;
public PgDatabase(PgConnection connection) {
this.connection = connection;
}
public boolean isDolphin() {
return isDolphin;
}
public boolean isDec() {
return isDec;
}
/**
* cache dolphin
*
* @param info connection param
* @throws SQLException execute sql exception
*/
public void setDolphin(Properties info) throws SQLException {
String extensionDolphin = getDolphin("select count(1) from pg_extension where extname = 'dolphin';");
int dolphinNum = Integer.parseInt(extensionDolphin);
String compatibility = getDolphin("show dolphin.b_compatibility_mode;");
CompatibilityEnum compatibilityEnum = CompatibilityEnum.valueOf(compatibility.toUpperCase(Locale.ROOT));
if (dolphinNum > 0 && CompatibilityEnum.ON.equals(compatibilityEnum)) {
isDolphin = true;
String bitOutput = PGProperty.BIT_OUTPUT.get(info);
if (bitOutput == null) {
bitOutput = getDolphin("show dolphin.bit_output;");
} else {
updateBitOutput(bitOutput);
}
if (BitOutputEnum.DEC.equals(BitOutputEnum.valueOf(bitOutput.toUpperCase(Locale.ROOT)))) {
isDec = true;
}
} else {
isDolphin = false;
}
}
/**
* get dolphin
*
* @param sql execute sql
* @return dolphin of b database
* @throws SQLException execute sql exception
*/
public String getDolphin(String sql) throws SQLException {
try (PreparedStatement dbStatement = connection.prepareStatement(sql)) {
if (!((BaseStatement) dbStatement).executeWithFlags(QueryExecutor.QUERY_SUPPRESS_BEGIN)) {
throw new PSQLException(GT.tr("No results were returned by the query."), PSQLState.NO_DATA);
}
try (ResultSet rs = dbStatement.getResultSet()) {
if (rs.next()) {
return rs.getString(1);
}
return "";
}
}
}
private void updateBitOutput(String bitOutput) throws SQLException {
/* set parameter cannot use prepareStatement to set the value */
try (Statement stmt = connection.createStatement()) {
String sql = "set dolphin.bit_output to " + bitOutput;
stmt.execute(sql);
} catch (SQLException e) {
throw e;
}
}
}

View File

@ -30,6 +30,8 @@ import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import static org.postgresql.jdbc.TypeInfoCache.FLOATSCALE;
public class PgDatabaseMetaData implements DatabaseMetaData {
public PgDatabaseMetaData(PgConnection conn) {
@ -1601,7 +1603,7 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
int decimalDigits = connection.getTypeInfo().getScale(typeOid, typeMod);
int columnSize = connection.getTypeInfo().getPrecision(typeOid, typeMod);
if (columnSize == 0) {
if (columnSize == 0 || decimalDigits == FLOATSCALE) {
columnSize = connection.getTypeInfo().getDisplaySize(typeOid, typeMod);
}
@ -2419,6 +2421,7 @@ public class PgDatabaseMetaData implements DatabaseMetaData {
sql += ") i";
}
sql += " where (i.keys).x >= 0";
sql += " ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION ";
return connection.createStatement().executeQuery(sql);

View File

@ -223,7 +223,7 @@ class PgPreparedStatement extends PgStatement implements PreparedStatement {
checkClosed();
int oid;
if (sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR) {
if (sqlType == Types.VARCHAR || sqlType == Types.LONGVARCHAR || connection.getPgDatabase().isDolphin()) {
oid = connection.getStringVarcharFlag() ? Oid.VARCHAR : Oid.UNSPECIFIED;
} else if (sqlTypeToOid.containsKey(sqlType)) {
oid = sqlTypeToOid.get(sqlType);

View File

@ -256,113 +256,122 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
return getURL(findColumn(columnName));
}
protected Object internalGetObject(int columnIndex, Field field) throws SQLException {
switch (getSQLType(columnIndex)) {
case Types.BOOLEAN:
return getBoolean(columnIndex);
case Types.BIT:
return getBit(columnIndex);
case Types.SQLXML:
return getSQLXML(columnIndex);
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
return getInt(columnIndex);
case Types.BIGINT:
return getLong(columnIndex);
case TypeInfoCache.bIntegerType:
return getBigInteger(columnIndex);
case Types.NUMERIC:
case Types.DECIMAL:
return getBigDecimal(columnIndex,
(field.getMod() == -1) ? -1 : ((field.getMod() - 4) & 0xffff));
case Types.REAL:
return getFloat(columnIndex);
case Types.FLOAT:
case Types.DOUBLE:
return getDouble(columnIndex);
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex, null);
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
case Types.CLOB:
return getClob(columnIndex);
case Types.BLOB:
return getBlob(columnIndex);
case Types.STRUCT:
return getStruct(columnIndex);
protected Object internalGetObject(int columnIndex, Field field) throws SQLException {
switch (getSQLType(columnIndex)) {
case Types.BOOLEAN:
return getBoolean(columnIndex);
case Types.BIT:
return getBit(columnIndex);
case Types.SQLXML:
return getSQLXML(columnIndex);
case Types.TINYINT:
case Types.SMALLINT:
case Types.INTEGER:
if (field.getPGType().equals("uint4")) {
return getLong(columnIndex);
}
return getInt(columnIndex);
case Types.BIGINT:
if (field.getPGType().equals("uint8")) {
return getBigInteger(columnIndex);
}
return getLong(columnIndex);
case Types.NUMERIC:
case Types.DECIMAL:
int scale;
if (field.getMod() == -1) {
return getBigDecimal(columnIndex, -1);
} else {
scale = (short) ((field.getMod() - 4) & 0xffff);
return getBigDecimal(columnIndex, (Math.max(scale, -1)));
}
case Types.REAL:
return getFloat(columnIndex);
case Types.FLOAT:
case Types.DOUBLE:
return getDouble(columnIndex);
case Types.CHAR:
case Types.VARCHAR:
case Types.LONGVARCHAR:
return getString(columnIndex);
case Types.DATE:
return getDate(columnIndex);
case Types.TIME:
return getTime(columnIndex);
case Types.TIMESTAMP:
return getTimestamp(columnIndex, null);
case Types.BINARY:
case Types.VARBINARY:
case Types.LONGVARBINARY:
return getBytes(columnIndex);
case Types.ARRAY:
return getArray(columnIndex);
case Types.CLOB:
return getClob(columnIndex);
case Types.BLOB:
return getBlob(columnIndex);
case Types.STRUCT:
return getStruct(columnIndex);
default:
String type = getPGType(columnIndex);
default:
String type = getPGType(columnIndex);
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown")) {
return getString(columnIndex);
// if the backend doesn't know the type then coerce to String
if (type.equals("unknown")) {
return getString(columnIndex);
}
if (type.equals("uuid")) {
if (isBinary(columnIndex)) {
return getUUID(this_row[columnIndex - 1]);
}
return getUUID(getString(columnIndex));
}
// Specialized support for ref cursors is neater.
if (type.equals("refcursor")) {
// Fetch all results.
String cursorName = getString(columnIndex);
StringBuilder sb = new StringBuilder("FETCH ALL IN ");
Utils.escapeIdentifier(sb, cursorName);
// nb: no BEGIN triggered here. This is fine. If someone
// committed, and the cursor was not holdable (closing the
// cursor), we avoid starting a new xact and promptly causing
// it to fail. If the cursor *was* holdable, we don't want a
// new xact anyway since holdable cursor state isn't affected
// by xact boundaries. If our caller didn't commit at all, or
// autocommit was on, then we wouldn't issue a BEGIN anyway.
//
// We take the scrollability from the statement, but until
// we have updatable cursors it must be readonly.
ResultSet rs =
connection.execSQLQuery(sb.toString(), resultsettype, ResultSet.CONCUR_READ_ONLY);
//
// In long running transactions these backend cursors take up memory space
// we could close in rs.close(), but if the transaction is closed before the result set,
// then
// the cursor no longer exists
sb.setLength(0);
sb.append("CLOSE ");
Utils.escapeIdentifier(sb, cursorName);
connection.execSQLUpdate(sb.toString());
((PgResultSet) rs).setRefCursor(cursorName);
return rs;
}
if ("hstore".equals(type)) {
if (isBinary(columnIndex)) {
return HStoreConverter.fromBytes(this_row[columnIndex - 1], connection.getEncoding());
}
return HStoreConverter.fromString(getString(columnIndex));
}
// Caller determines what to do (JDBC3 overrides in this case)
return null;
}
if (type.equals("uuid")) {
if (isBinary(columnIndex)) {
return getUUID(this_row[columnIndex - 1]);
}
return getUUID(getString(columnIndex));
}
// Specialized support for ref cursors is neater.
if (type.equals("refcursor")) {
// Fetch all results.
String cursorName = getString(columnIndex);
StringBuilder sb = new StringBuilder("FETCH ALL IN ");
Utils.escapeIdentifier(sb, cursorName);
// nb: no BEGIN triggered here. This is fine. If someone
// committed, and the cursor was not holdable (closing the
// cursor), we avoid starting a new xact and promptly causing
// it to fail. If the cursor *was* holdable, we don't want a
// new xact anyway since holdable cursor state isn't affected
// by xact boundaries. If our caller didn't commit at all, or
// autocommit was on, then we wouldn't issue a BEGIN anyway.
//
// We take the scrollability from the statement, but until
// we have updatable cursors it must be readonly.
ResultSet rs =
connection.execSQLQuery(sb.toString(), resultsettype, ResultSet.CONCUR_READ_ONLY);
//
// In long running transactions these backend cursors take up memory space
// we could close in rs.close(), but if the transaction is closed before the result set,
// then
// the cursor no longer exists
sb.setLength(0);
sb.append("CLOSE ");
Utils.escapeIdentifier(sb, cursorName);
connection.execSQLUpdate(sb.toString());
((PgResultSet) rs).setRefCursor(cursorName);
return rs;
}
if ("hstore".equals(type)) {
if (isBinary(columnIndex)) {
return HStoreConverter.fromBytes(this_row[columnIndex - 1], connection.getEncoding());
}
return HStoreConverter.fromString(getString(columnIndex));
}
// Caller determines what to do (JDBC3 overrides in this case)
return null;
}
}
/**
* Get the PGStruct object based on parameter index
@ -649,7 +658,7 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
}
}
return connection.getTimestampUtils().toDate(cal, getString(i));
return connection.getTimestampUtils().toDate(cal, new String(this_row[i - 1]));
}
@ -2088,12 +2097,17 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
if (connection.unwrap(PgConnection.class).isDolphinCmpt()) {
return new String(toBytes(result));
}
} else if (blobSet.contains(typeName)) {
} else if (blobSet.contains(typeName) || ("raw".equals(typeName)
&& connection.getPgDatabase().isDolphin())) {
return new String(toBytes(result));
} else if ("time".equals(typeName)) {
char[] cs = result.toCharArray();
int start = TimestampUtils.firstDigit(cs, 0);
result = result.substring(start);
return result.substring(start);
} else if ("date".equals(typeName) && connection.getPgDatabase().isDolphin()) {
java.util.Calendar cal = getDefaultCalendar();
Date dt = connection.getTimestampUtils().toDate(cal, result);
return String.valueOf(dt);
}
return result;
} catch (IOException ioe) {
@ -2210,7 +2224,13 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
if (connection.getBitToString()) {
return val;
}
return BooleanTypeUtil.castToBoolean(val);
Field field = this.fields[columnIndex - 1];
if (field.getMod() == 1 || !connection.getPgDatabase().isDolphin()) {
return BooleanTypeUtil.castToBoolean(val);
}
return this.getBytes(columnIndex);
}
private static final BigInteger BYTEMAX = new BigInteger(Byte.toString(Byte.MAX_VALUE));
@ -2636,13 +2656,46 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
int oid = fields[columnIndex - 1].getOID();
if (oid == Oid.BYTEA) {
return trimBytes(columnIndex, PGbytea.toBytes(this_row[columnIndex - 1]));
} else if (oid == Oid.BLOB) {
return toBytes(getString(columnIndex));
} else if (oid == Oid.BLOB || blobSet.contains(getPGType(columnIndex))) {
String result = new String(this_row[columnIndex - 1]);
return toBytes(result);
} else if (oid == Oid.BIT && connection.getPgDatabase().isDec()) {
return toDecBytes(fields[columnIndex - 1].getMod(), getString(columnIndex));
} else {
return trimBytes(columnIndex, this_row[columnIndex - 1]);
}
}
private byte[] toDecBytes(int mod, String str) {
if (mod <= 0) {
return new byte[0];
}
int lengthToSplit = 8;
long value = Long.parseLong(str);
String binary = Long.toBinaryString(value);
int formatMod = mod;
if (mod % lengthToSplit != 0) {
formatMod = (mod / lengthToSplit + 1) * lengthToSplit;
}
if (binary.length() < formatMod) {
StringBuilder formatBinary = new StringBuilder();
for (int i = 0; i < formatMod - binary.length(); i++) {
formatBinary.append("0");
}
binary = formatBinary.append(binary).toString();
}
int byteLength = formatMod / lengthToSplit;
byte[] bytes = new byte[byteLength];
for (int i = 0; i < byteLength; i++) {
String splitStr = binary.substring(i * lengthToSplit, (i + 1) * lengthToSplit);
bytes[i] = (byte) Integer.parseInt(splitStr, 2);
}
return bytes;
}
public java.sql.Date getDate(int columnIndex) throws SQLException {
connection.getLogger().trace("[" + connection.getSecSocketAddress() + "]" + " getDate columnIndex: " + columnIndex);
return getDate(columnIndex, null);
@ -2826,7 +2879,8 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
return null;
}
if(blobSet.contains(getPGType(columnIndex))){
String pgType = getPGType(columnIndex);
if (blobSet.contains(pgType)) {
return toBytes(getBlobSetString(columnIndex));
}
@ -2835,13 +2889,13 @@ public class PgResultSet implements ResultSet, org.postgresql.PGRefCursorResultS
return result;
}
if (binarySet.contains(getPGType(columnIndex))) {
if (binarySet.contains(pgType)) {
return this_row[columnIndex - 1];
}
if (isBinary(columnIndex)) {
return connection.getObject(getPGType(columnIndex), null, this_row[columnIndex - 1]);
return connection.getObject(pgType, null, this_row[columnIndex - 1]);
}
return connection.getObject(getPGType(columnIndex), getString(columnIndex), null);
return connection.getObject(pgType, getString(columnIndex), null);
}
public Object getObject(String columnName) throws SQLException {

View File

@ -7,6 +7,7 @@ package org.postgresql.jdbc;
import org.postgresql.Driver;
import org.postgresql.core.*;
import org.postgresql.core.v3.QueryExecutorImpl;
import org.postgresql.quickautobalance.ConnectionManager;
import org.postgresql.quickautobalance.LoadBalanceHeartBeating;
import org.postgresql.util.GT;
@ -991,6 +992,7 @@ public class PgStatement implements Statement, BaseStatement {
BatchResultHandler handler;
handler = createBatchHandler(queries, parameterLists);
QueryExecutorImpl executer = (QueryExecutorImpl) connection.getQueryExecutor();
if ((preDescribe || forceBinaryTransfers)
&& (flags & QueryExecutor.QUERY_EXECUTE_AS_SIMPLE) == 0) {
// Do a client-server round trip, parsing and describing the query so we
@ -1000,6 +1002,9 @@ public class PgStatement implements Statement, BaseStatement {
StatementResultHandler handler2 = new StatementResultHandler();
try {
connection.getQueryExecutor().execute(queries[0], parameterLists[0], handler2, 0, 0, flags2);
if (connection.getQueryExecutor() instanceof QueryExecutorImpl) {
executer.setWaitNexttime(true);
}
} catch (SQLException e) {
// Unable to parse the first statement -> throw BatchUpdateException
handler.handleError(e);
@ -1046,6 +1051,7 @@ public class PgStatement implements Statement, BaseStatement {
}
}
}
executer.setWaitNexttime(false);
return handler;
}

View File

@ -61,6 +61,12 @@ public class TimestampUtils {
private TimeZone defaultTimeZoneCache;
private int timestampNanoFormat = 0;
private boolean isDolphin = false;
public void setDolphin(boolean isDolphin) {
this.isDolphin = isDolphin;
}
static {
// The expected maximum value is 60 (seconds), so 64 is used "just in case"
NUMBERS = new char[64][];
@ -402,7 +408,7 @@ public class TimestampUtils {
ParsedTimestamp ts = parseBackendTimestamp(s);
Calendar useCal = ts.tz != null ? ts.tz : setupCalendar(cal);
useCal.set(Calendar.ERA, ts.era);
useCal.set(Calendar.YEAR, ts.year);
useCal.set(Calendar.YEAR, getYear(ts.year, slen));
useCal.set(Calendar.MONTH, ts.month - 1);
useCal.set(Calendar.DAY_OF_MONTH, ts.day);
useCal.set(Calendar.HOUR_OF_DAY, ts.hour);
@ -415,6 +421,17 @@ public class TimestampUtils {
return result;
}
private int getYear(int tsYear, int slen) {
int year = tsYear;
if (slen == 2 || slen == 1) {
if (year <= 69) {
year += 100;
}
year += 1900;
}
return year;
}
/**
* Parse a string and return a LocalTime representing its value.
*
@ -640,6 +657,9 @@ public class TimestampUtils {
}
public synchronized String toString(Calendar cal, Timestamp x) {
if (isDolphin) {
return toString(cal, x, false);
}
return toString(cal, x, true);
}

View File

@ -68,54 +68,55 @@ public class TypeInfoCache implements TypeInfo {
private static ConcurrentHashMap<Integer, String> pgTypes = new ConcurrentHashMap<>();
public static final int bIntegerType = 1324;
// SELECT LENGTH(pow(10::numeric,131071)); 131071 = 2^17-1
public static final int NUMERIC_MAX_DISPLAYSIZE = 131089;
public static String sqlCompatibility = "A";
// when behavior_compat_options='float_as_numeric' is on,
// openGauss accepts float(p) as numeric Type and the scale is -32768(PG_INT16_MIN)
public static final int FLOATSCALE = -32768;
public static String dolphinMode = "off";
// basic pg types info:
// 0 - type name
// 1 - type oid
// 2 - sql type
// 3 - java class
// 4 - array type oid
private static final Object[][] types = {
{"int1", Oid.INT1, Types.TINYINT, "java.lang.Integer", Oid.INT1_ARRAY},
{"int2", Oid.INT2, Types.SMALLINT, "java.lang.Integer", Oid.INT2_ARRAY},
{"int4", Oid.INT4, Types.INTEGER, "java.lang.Integer", Oid.INT4_ARRAY},
{"oid", Oid.OID, Types.BIGINT, "java.lang.Long", Oid.OID_ARRAY},
{"int8", Oid.INT8, Types.BIGINT, "java.lang.Long", Oid.INT8_ARRAY},
{"uint1", Oid.UINT1, Types.SMALLINT, "java.lang.Integer", Oid.UINT1_ARRAY},
{"uint2", Oid.UINT2, Types.INTEGER, "java.lang.Integer", Oid.UINT2_ARRAY},
{"uint4", Oid.UINT4, Types.BIGINT, "java.lang.Long", Oid.UINT4_ARRAY},
{"uint8", Oid.UINT8, bIntegerType, "java.math.BigInteger", Oid.UINT8_ARRAY},
{"money", Oid.MONEY, Types.DOUBLE, "java.lang.Double", Oid.MONEY_ARRAY},
{"numeric", Oid.NUMERIC, Types.NUMERIC, "java.math.BigDecimal", Oid.NUMERIC_ARRAY},
{"float4", Oid.FLOAT4, Types.REAL, "java.lang.Float", Oid.FLOAT4_ARRAY},
{"float8", Oid.FLOAT8, Types.DOUBLE, "java.lang.Double", Oid.FLOAT8_ARRAY},
{"char", Oid.CHAR, Types.CHAR, "java.lang.String", Oid.CHAR_ARRAY},
{"bpchar", Oid.BPCHAR, Types.CHAR, "java.lang.String", Oid.BPCHAR_ARRAY},
{"varchar", Oid.VARCHAR, Types.VARCHAR, "java.lang.String", Oid.VARCHAR_ARRAY},
{"text", Oid.TEXT, Types.VARCHAR, "java.lang.String", Oid.TEXT_ARRAY},
{"name", Oid.NAME, Types.VARCHAR, "java.lang.String", Oid.NAME_ARRAY},
{"bytea", Oid.BYTEA, Types.BINARY, "[B", Oid.BYTEA_ARRAY},
{"bool", Oid.BOOL, Types.BOOLEAN, "java.lang.Boolean", Oid.BOOL_ARRAY},
{"bit", Oid.BIT, Types.BIT, "java.lang.Boolean", Oid.BIT_ARRAY},
{"date", Oid.DATE, Types.DATE, "java.sql.Date", Oid.DATE_ARRAY},
{"time", Oid.TIME, Types.TIME, "java.sql.Time", Oid.TIME_ARRAY},
{"timetz", Oid.TIMETZ, Types.TIME, "java.sql.Time", Oid.TIMETZ_ARRAY},
{"timestamp", Oid.TIMESTAMP, Types.TIMESTAMP, "java.sql.Timestamp", Oid.TIMESTAMP_ARRAY},
{"smalldatetime", Oid.SMALLDATETIME, Types.TIMESTAMP, "java.lang.Timestamp", Oid.SMALLDATETIME_ARRAY},
{"timestamptz", Oid.TIMESTAMPTZ, Types.TIMESTAMP, "java.sql.Timestamp",
Oid.TIMESTAMPTZ_ARRAY},
{"json", Oid.JSON, Types.OTHER, "org.postgresql.util.PGobject", Oid.JSON_ARRAY},
{"point", Oid.POINT, Types.OTHER, "org.postgresql.geometric.PGpoint", Oid.POINT_ARRAY},
{"blob", Oid.BLOB, Types.BLOB, "org.postgresql.util.PGobject", -1},
{"clob", Oid.CLOB, Types.CLOB, "org.postgresql.util.PGobject", -1},
{"nvarchar2", Oid.NVARCHAR2, Types.VARCHAR, "java.lang.String", Oid.NVARCHAR2_ARRAY},
{"refcursor", Oid.REF_CURSOR, Types.REF_CURSOR, "java.sql.ResultSet", Oid.REF_CURSOR_ARRAY}
};
// basic pg types info:
// 0 - type name
// 1 - type oid
// 2 - sql type
// 3 - java class
// 4 - array type oid
private static final Object[][] types = {
{"int1", Oid.INT1, Types.TINYINT, "java.lang.Integer", Oid.INT1_ARRAY},
{"int2", Oid.INT2, Types.SMALLINT, "java.lang.Integer", Oid.INT2_ARRAY},
{"int4", Oid.INT4, Types.INTEGER, "java.lang.Integer", Oid.INT4_ARRAY},
{"oid", Oid.OID, Types.BIGINT, "java.lang.Long", Oid.OID_ARRAY},
{"int8", Oid.INT8, Types.BIGINT, "java.lang.Long", Oid.INT8_ARRAY},
{"uint1", Oid.UINT1, Types.TINYINT, "java.lang.Integer", Oid.UINT1_ARRAY},
{"uint2", Oid.UINT2, Types.SMALLINT, "java.lang.Integer", Oid.UINT2_ARRAY},
{"uint4", Oid.UINT4, Types.INTEGER, "java.lang.Integer", Oid.UINT4_ARRAY},
{"uint8", Oid.UINT8, Types.BIGINT, "java.lang.Long", Oid.UINT8_ARRAY},
{"money", Oid.MONEY, Types.DOUBLE, "java.lang.Double", Oid.MONEY_ARRAY},
{"numeric", Oid.NUMERIC, Types.DECIMAL, "java.math.BigDecimal", Oid.NUMERIC_ARRAY},
{"float4", Oid.FLOAT4, Types.REAL, "java.lang.Float", Oid.FLOAT4_ARRAY},
{"float8", Oid.FLOAT8, Types.DOUBLE, "java.lang.Double", Oid.FLOAT8_ARRAY},
{"char", Oid.CHAR, Types.CHAR, "java.lang.String", Oid.CHAR_ARRAY},
{"bpchar", Oid.BPCHAR, Types.CHAR, "java.lang.String", Oid.BPCHAR_ARRAY},
{"varchar", Oid.VARCHAR, Types.VARCHAR, "java.lang.String", Oid.VARCHAR_ARRAY},
{"text", Oid.TEXT, Types.VARCHAR, "java.lang.String", Oid.TEXT_ARRAY},
{"name", Oid.NAME, Types.VARCHAR, "java.lang.String", Oid.NAME_ARRAY},
{"bytea", Oid.BYTEA, Types.BINARY, "[B", Oid.BYTEA_ARRAY},
{"bool", Oid.BOOL, Types.BOOLEAN, "java.lang.Boolean", Oid.BOOL_ARRAY},
{"bit", Oid.BIT, Types.BIT, "java.lang.Boolean", Oid.BIT_ARRAY},
{"date", Oid.DATE, Types.DATE, "java.sql.Date", Oid.DATE_ARRAY},
{"time", Oid.TIME, Types.TIME, "java.sql.Time", Oid.TIME_ARRAY},
{"timetz", Oid.TIMETZ, Types.TIME, "java.sql.Time", Oid.TIMETZ_ARRAY},
{"timestamp", Oid.TIMESTAMP, Types.TIMESTAMP, "java.sql.Timestamp", Oid.TIMESTAMP_ARRAY},
{"smalldatetime", Oid.SMALLDATETIME, Types.TIMESTAMP, "java.lang.Timestamp", Oid.SMALLDATETIME_ARRAY},
{"timestamptz", Oid.TIMESTAMPTZ, Types.TIMESTAMP, "java.sql.Timestamp",
Oid.TIMESTAMPTZ_ARRAY},
{"json", Oid.JSON, Types.VARCHAR, "java.lang.String", Oid.JSON_ARRAY},
{"point", Oid.POINT, Types.OTHER, "org.postgresql.geometric.PGpoint", Oid.POINT_ARRAY},
{"blob", Oid.BLOB, Types.BLOB, "org.postgresql.util.PGobject", -1},
{"clob", Oid.CLOB, Types.CLOB, "org.postgresql.util.PGobject", -1},
{"nvarchar2", Oid.NVARCHAR2, Types.VARCHAR, "java.lang.String", Oid.NVARCHAR2_ARRAY},
{"refcursor", Oid.REF_CURSOR, Types.REF_CURSOR, "java.sql.ResultSet", Oid.REF_CURSOR_ARRAY}
};
/**
* PG maps several alias to real type names. When we do queries against pg_catalog, we must use
@ -215,6 +216,18 @@ public class TypeInfoCache implements TypeInfo {
return i;
}
Integer type = null;
if ("binary".equals(pgTypeName)) {
type = Types.BINARY;
} else if ("varbinary".equals(pgTypeName)) {
type = Types.VARBINARY;
}
if (type != null) {
_pgNameToSQLType.put(pgTypeName, type);
return type;
}
if (_getTypeInfoStatement == null) {
// There's no great way of telling what's an array type.
// People can name their own types starting with _.
@ -240,7 +253,6 @@ public class TypeInfoCache implements TypeInfo {
ResultSet rs = _getTypeInfoStatement.getResultSet();
Integer type = null;
if (rs.next()) {
boolean isArray = rs.getBoolean(1);
String typtype = rs.getString(2);
@ -254,7 +266,11 @@ public class TypeInfoCache implements TypeInfo {
}
if (type == null) {
type = Types.OTHER;
if (_conn.getPgDatabase().isDolphin()) {
type = Types.CHAR;
} else {
type = Types.OTHER;
}
}
rs.close();
@ -434,41 +450,6 @@ public class TypeInfoCache implements TypeInfo {
return pgTypes;
}
public void setDBType() throws SQLException {
String compatibilitySql = "show sql_compatibility;";
String compatibility = getDBParam(compatibilitySql);
if (compatibility != null) {
sqlCompatibility = compatibility;
if ("B".equals(compatibility)) {
String dolphinSql = "show dolphin.b_compatibility_mode;";
String dolphin = getDBParam(dolphinSql);
if (dolphin != null) {
dolphinMode = dolphin;
}
}
}
}
private String getDBParam(String sql) throws SQLException {
PreparedStatement dbStatement = _conn.prepareStatement(sql);
if (!((BaseStatement) dbStatement).executeWithFlags(QueryExecutor.QUERY_SUPPRESS_BEGIN)) {
throw new PSQLException(GT.tr("No results were returned by the query."), PSQLState.NO_DATA);
}
ResultSet rs = dbStatement.getResultSet();
if (rs != null && rs.next()) {
return rs.getString(1);
}
return null;
}
public static String getDolphinMode(){
return dolphinMode;
}
public static String getSqlCompatibility(){
return sqlCompatibility;
}
public synchronized int getPGType(String pgTypeName) throws SQLException {
Integer oid = _pgNameToOid.get(pgTypeName);
if (oid != null) {
@ -821,7 +802,7 @@ public class TypeInfoCache implements TypeInfo {
if (typmod == -1) {
return 0;
}
return (typmod - 4) & 0xFFFF;
return (short)((typmod - 4) & 0xFFFF);
case Oid.TIME:
case Oid.TIMETZ:
case Oid.TIMESTAMP:
@ -957,10 +938,15 @@ public class TypeInfoCache implements TypeInfo {
return typmod - 4;
case Oid.NUMERIC:
if (typmod == -1) {
return 131089; // SELECT LENGTH(pow(10::numeric,131071)); 131071 = 2^17-1
return NUMERIC_MAX_DISPLAYSIZE;
}
int precision = (typmod - 4 >> 16) & 0xffff;
int scale = (typmod - 4) & 0xffff;
int scale = (short)((typmod - 4) & 0xffff);
if (scale == FLOATSCALE) {
return NUMERIC_MAX_DISPLAYSIZE;
} else if (scale < 0) {
return 1 + precision - scale;
}
// sign + digits + decimal point (only if we have nonzero scale)
return 1 + precision + (scale != 0 ? 1 : 0);
case Oid.BIT:

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2024 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FITFOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.util;
/**
* This class is used b database and bit type.
*
* @author zhangting
* @date 2024/08/10 09:01
*/
public enum BitOutputEnum {
BIN, DEC, HEX
}

View File

@ -5,6 +5,9 @@
package org.postgresql.util;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* Helper methods to parse java base types from byte arrays.
*
@ -16,6 +19,291 @@ public class ByteConverter {
// prevent instantiation of static helper class
}
private static final int NUMERIC_DSCALE_MASK = 0x00003FFF;
private static final short NUMERIC_POS = 0x0000;
private static final short NUMERIC_NEG = 0x4000;
private static final short NUMERIC_NAN = (short) 0xC000;
private static final int SHORT_BYTES = 2;
private static final int[] INT_TEN_POWERS = new int[6];
private static final BigInteger[] BI_TEN_POWERS = new BigInteger[32];
private static final BigInteger BI_TEN_THOUSAND = BigInteger.valueOf(10000);
/**
* Convert a variable length array of bytes to an integer
* @param bytes array of bytes that can be decoded as an integer
* @return integer
*/
public static Number numeric(byte [] bytes) {
return numeric(bytes, 0, bytes.length);
}
/**
* Convert a variable length array of bytes to a {@link Number}. The result will
* always be a {@link BigDecimal} or {@link Double#NaN}.
*
* @param bytes array of bytes to be decoded from binary numeric representation.
* @param pos index of the start position of the bytes array for number
* @param numBytes number of bytes to use, length is already encoded
* in the binary format but this is used for double checking
* @return BigDecimal representation of numeric or {@link Double#NaN}.
*/
public static Number numeric(byte [] bytes, int pos, int numBytes) {
if (numBytes < 8) {
throw new IllegalArgumentException("number of bytes should be at-least 8");
}
//number of 2-byte shorts representing 4 decimal digits - should be treated as unsigned
int len = ByteConverter.int2(bytes, pos) & 0xFFFF;
//0 based number of 4 decimal digits (i.e. 2-byte shorts) before the decimal
//a value <= 0 indicates an absolute value < 1.
short weight = ByteConverter.int2(bytes, pos + 2);
//indicates positive, negative or NaN
short sign = ByteConverter.int2(bytes, pos + 4);
//number of digits after the decimal. This must be >= 0.
//a value of 0 indicates a whole number (integer).
short scale = ByteConverter.int2(bytes, pos + 6);
//An integer should be built from the len number of 2 byte shorts, treating each
//as 4 digits.
//The weight, if > 0, indicates how many of those 4 digit chunks should be to the
//"left" of the decimal. If the weight is 0, then all 4 digit chunks start immediately
//to the "right" of the decimal. If the weight is < 0, the absolute distance from 0
//indicates 4 leading "0" digits to the immediate "right" of the decimal, prior to the
//digits from "len".
//A weight which is positive, can be a number larger than what len defines. This means
//there are trailing 0s after the "len" integer and before the decimal.
//The scale indicates how many significant digits there are to the right of the decimal.
//A value of 0 indicates a whole number (integer).
//The combination of weight, len, and scale can result in either trimming digits provided
//by len (only to the right of the decimal) or adding significant 0 values to the right
//of len (on either side of the decimal).
if (numBytes != (len * SHORT_BYTES + 8)) {
throw new IllegalArgumentException("invalid length of bytes \"numeric\" value");
}
if (!(sign == NUMERIC_POS
|| sign == NUMERIC_NEG
|| sign == NUMERIC_NAN)) {
throw new IllegalArgumentException("invalid sign in \"numeric\" value");
}
if (sign == NUMERIC_NAN) {
return Double.NaN;
}
if ((scale & NUMERIC_DSCALE_MASK) != scale) {
throw new IllegalArgumentException("invalid scale in \"numeric\" value");
}
if (len == 0) {
return new BigDecimal(BigInteger.ZERO, scale);
}
int idx = pos + 8;
short d = ByteConverter.int2(bytes, idx);
//if the absolute value is (0, 1), then leading '0' values
//do not matter for the unscaledInt, but trailing 0s do
if (weight < 0) {
assert scale > 0;
int effectiveScale = scale;
//adjust weight to determine how many leading 0s after the decimal
//before the provided values/digits actually begin
++weight;
if (weight < 0) {
effectiveScale += 4 * weight;
}
int i = 1;
//typically there should not be leading 0 short values, as it is more
//efficient to represent that in the weight value
for (; i < len && d == 0; i++) {
//each leading 0 value removes 4 from the effective scale
effectiveScale -= 4;
idx += 2;
d = ByteConverter.int2(bytes, idx);
}
assert effectiveScale > 0;
if (effectiveScale >= 4) {
effectiveScale -= 4;
} else {
//an effective scale of less than four means that the value d
//has trailing 0s which are not significant
//so we divide by the appropriate power of 10 to reduce those
d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
effectiveScale = 0;
}
//defer moving to BigInteger as long as possible
//operations on the long are much faster
BigInteger unscaledBI = null;
long unscaledInt = d;
for (; i < len; i++) {
if (i == 4 && effectiveScale > 2) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
idx += 2;
d = ByteConverter.int2(bytes, idx);
//if effective scale is at least 4, then all 4 digits should be used
//and the existing number needs to be shifted 4
if (effectiveScale >= 4) {
if (unscaledBI == null) {
unscaledInt *= 10000;
} else {
unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
}
effectiveScale -= 4;
} else {
//if effective scale is less than 4, then only shift left based on remaining scale
if (unscaledBI == null) {
unscaledInt *= INT_TEN_POWERS[effectiveScale];
} else {
unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
}
//and d needs to be shifted to the right to only get correct number of
//significant digits
d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
effectiveScale = 0;
}
if (unscaledBI == null) {
unscaledInt += d;
} else {
if (d != 0) {
unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
}
}
}
//now we need BigInteger to create BigDecimal
if (unscaledBI == null) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
//if there is remaining effective scale, apply it here
if (effectiveScale > 0) {
unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
}
if (sign == NUMERIC_NEG) {
unscaledBI = unscaledBI.negate();
}
return new BigDecimal(unscaledBI, scale);
}
//if there is no scale, then shorts are the unscaled int
if (scale == 0) {
//defer moving to BigInteger as long as possible
//operations on the long are much faster
BigInteger unscaledBI = null;
long unscaledInt = d;
//loop over all of the len shorts to process as the unscaled int
for (int i = 1; i < len; i++) {
if (i == 4) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
idx += 2;
d = ByteConverter.int2(bytes, idx);
if (unscaledBI == null) {
unscaledInt *= 10000;
unscaledInt += d;
} else {
unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
if (d != 0) {
unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
}
}
}
//now we need BigInteger to create BigDecimal
if (unscaledBI == null) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
if (sign == NUMERIC_NEG) {
unscaledBI = unscaledBI.negate();
}
//the difference between len and weight (adjusted from 0 based) becomes the scale for BigDecimal
final int bigDecScale = (len - (weight + 1)) * 4;
//string representation always results in a BigDecimal with scale of 0
//the binary representation, where weight and len can infer trailing 0s, can result in a negative scale
//to produce a consistent BigDecimal, we return the equivalent object with scale set to 0
return bigDecScale == 0 ? new BigDecimal(unscaledBI) : new BigDecimal(unscaledBI, bigDecScale).setScale(0);
}
//defer moving to BigInteger as long as possible
//operations on the long are much faster
BigInteger unscaledBI = null;
long unscaledInt = d;
//weight and scale as defined by postgresql are a bit different than how BigDecimal treats scale
//maintain the effective values to massage as we process through values
int effectiveWeight = weight;
int effectiveScale = scale;
for (int i = 1; i < len; i++) {
if (i == 4) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
idx += 2;
d = ByteConverter.int2(bytes, idx);
//first process effective weight down to 0
if (effectiveWeight > 0) {
--effectiveWeight;
if (unscaledBI == null) {
unscaledInt *= 10000;
} else {
unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
}
} else if (effectiveScale >= 4) {
//if effective scale is at least 4, then all 4 digits should be used
//and the existing number needs to be shifted 4
effectiveScale -= 4;
if (unscaledBI == null) {
unscaledInt *= 10000;
} else {
unscaledBI = unscaledBI.multiply(BI_TEN_THOUSAND);
}
} else {
//if effective scale is less than 4, then only shift left based on remaining scale
if (unscaledBI == null) {
unscaledInt *= INT_TEN_POWERS[effectiveScale];
} else {
unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
}
//and d needs to be shifted to the right to only get correct number of
//significant digits
d = (short) (d / INT_TEN_POWERS[4 - effectiveScale]);
effectiveScale = 0;
}
if (unscaledBI == null) {
unscaledInt += d;
} else {
if (d != 0) {
unscaledBI = unscaledBI.add(BigInteger.valueOf(d));
}
}
}
//now we need BigInteger to create BigDecimal
if (unscaledBI == null) {
unscaledBI = BigInteger.valueOf(unscaledInt);
}
//if there is remaining weight, apply it here
if (effectiveWeight > 0) {
unscaledBI = unscaledBI.multiply(tenPower(effectiveWeight * 4));
}
//if there is remaining effective scale, apply it here
if (effectiveScale > 0) {
unscaledBI = unscaledBI.multiply(tenPower(effectiveScale));
}
if (sign == NUMERIC_NEG) {
unscaledBI = unscaledBI.negate();
}
return new BigDecimal(unscaledBI, scale);
}
private static BigInteger tenPower(int exponent) {
return BI_TEN_POWERS.length > exponent ? BI_TEN_POWERS[exponent] : BigInteger.TEN.pow(exponent);
}
/**
* Parses a long value from the byte array.
*

View File

@ -0,0 +1,5 @@
package org.postgresql.util;
public enum CompatibilityEnum {
ON, OFF
}

View File

@ -0,0 +1,131 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.core;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static org.junit.Assert.assertEquals;
/**
* test utf8 encoding
*
* @author zhangting
* @since 2024-09-24
*/
@RunWith(Parameterized.class)
public class UTF8EncodingTest {
private static final int STEP = 8 * 1024;
/**
* character encoding
*/
@Parameterized.Parameter(0)
public Encoding encoding;
/**
* test data
*/
@Parameterized.Parameter(1)
public String str;
/**
* test data
*/
@Parameterized.Parameter(2)
public String shortStr;
/**
* Construct data
*
* @return data
*/
@Parameterized.Parameters(name = "string={2}, encoding={0}")
public static Iterable<Object[]> data() {
final StringBuilder reallyLongString = new StringBuilder(1024 * 1024);
for (int i = 0; i < 185000; ++i) {
reallyLongString.append(i);
}
final List<String> strs = new ArrayList<>(150);
strs.add("short simple");
strs.add("longer but still not really all that long");
strs.add(reallyLongString.toString());
// add multi-byte to end of a long string
strs.add(reallyLongString.append('\u03C0').toString());
strs.add(reallyLongString.delete((32 * 1024) + 5, reallyLongString.capacity() - 1).toString());
// add high order char to end of mid length string
strs.add(reallyLongString.append('\u00DC').toString());
strs.add(reallyLongString.delete((16 * 1024) + 5, reallyLongString.capacity() - 1).toString());
// add high order char to end of mid length string
strs.add(reallyLongString.append('\u00DD').toString());
strs.add("e\u00E4t \u03A3 \u03C0 \u798F, it is good");
for (int i = 1; i < 0xd800; i += STEP) {
int count = (i + STEP) > 0xd800 ? 0xd800 - i : STEP;
char[] testChars = new char[count];
for (int j = 0; j < count; ++j) {
testChars[j] = (char) (i + j);
}
strs.add(new String(testChars));
}
for (int i = 0xe000; i < 0x10000; i += STEP) {
int count = (i + STEP) > 0x10000 ? 0x10000 - i : STEP;
char[] testChars = new char[count];
for (int j = 0; j < count; ++j) {
testChars[j] = (char) (i + j);
}
strs.add(new String(testChars));
}
for (int i = 0x10000; i < 0x110000; i += STEP) {
int count = (i + STEP) > 0x110000 ? 0x110000 - i : STEP;
char[] testChars = new char[count * 2];
for (int j = 0; j < count; ++j) {
testChars[j * 2] = (char) (0xd800 + ((i + j - 0x10000) >> 10));
testChars[j * 2 + 1] = (char) (0xdc00 + ((i + j - 0x10000) & 0x3ff));
}
strs.add(new String(testChars));
}
final List<Object[]> data = new ArrayList<>(strs.size() * 2);
for (String str : strs) {
if (str != null && str.length() > 1000) {
str = str.substring(0, 100) + "...(" + str.length() + " chars)";
}
data.add(new Object[] {Encoding.getDatabaseEncoding("UNICODE"), str, str});
}
return data;
}
@Test
public void test() throws IOException {
final byte[] encoded = encoding.encode(str);
assertEquals(str, encoding.decode(encoded));
}
}

View File

@ -60,6 +60,6 @@ public class V3ParameterListTests {
s1SPL.appendAll(s2SPL);
assertEquals(
"Expected string representation of values does not match outcome.",
"<[1 ,2 ,3 ,4 ,5 ,6 ,7 ,8]>", s1SPL.toString());
"<[('1'::int4) ,('2'::int4) ,('3'::int4) ,('4'::int4) ,('5'::int4) ,('6'::int4) ,('7'::int4) ,('8'::int4)]>", s1SPL.toString());
}
}

View File

@ -0,0 +1,353 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.jdbc;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4PG;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import static org.junit.Assert.assertTrue;
/**
* test full trace.
*
* @author hwhbj
* @since 2024-08-20
*/
public class FullTraceTest extends BaseTest4PG {
private static final Integer WAIT_FLUSH_TIME = 1000;
private static final String QUERY_STMT_HISTORY = "select db_time, net_trans_time from statement_history "
+ "where query like '%s'";
private static final String RECORD_FULL_SQL = "set track_stmt_stat_level = 'L0,L0'";
private static final String ENABLE_TRACE_SQL = "set enable_record_nettime = on";
private static Connection createConnection() throws Exception {
return TestUtil.openDB();
}
private static Connection createConnection(Properties props) throws Exception {
return TestUtil.openDB(props);
}
private static Connection createConnection(String dbName) throws Exception {
return TestUtil.openDB(dbName);
}
private List<Integer> recordCount(String sql) throws Exception {
String querySql = String.format(QUERY_STMT_HISTORY, sql);
try (Connection conn = createConnection("postgres");
PreparedStatement pstmt = conn.prepareStatement(querySql);
ResultSet rs = pstmt.executeQuery()) {
int count1 = 0;
int count2 = 0;
int count3 = 0;
while (rs.next()) {
int dbTime = rs.getInt(1);
int netTransTime = rs.getInt(2);
if (dbTime == 0 && netTransTime == 0) {
count1++;
} else if (dbTime > 0 && netTransTime == 0) {
count2++;
} else if (dbTime > 0 && netTransTime > 0) {
count3++;
}
}
return Arrays.asList(count1, count2, count3);
}
}
private void setRecordFullSql(Connection conn) throws Exception {
try (PreparedStatement pstmt = conn.prepareStatement(ENABLE_TRACE_SQL + ";" + RECORD_FULL_SQL)) {
pstmt.execute();
}
}
private void sendPreTimeAndFlush(Connection conn) throws Exception {
/* send previous net_time */
try (PreparedStatement pstmt = conn.prepareStatement("select 1;")) {
pstmt.executeQuery();
Thread.sleep(WAIT_FLUSH_TIME);
}
}
@Test
public void testExecuteMultiSqlPBE() throws Exception {
String sql1 = "drop table if exists t1";
String sql2 = "create table t1(id int)";
List<Integer> beforeInfoSql1 = recordCount(sql1);
List<Integer> beforeInfoSql2 = recordCount(sql2);
/* PBEPBES */
try (Connection conn = createConnection();
PreparedStatement pstmt = conn.prepareStatement(sql1 + ";" + sql2)) {
setRecordFullSql(conn);
pstmt.execute();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql1 = recordCount(sql1);
List<Integer> afterInfoSql2 = recordCount(sql2);
assertTrue(beforeInfoSql1.get(0) + 1 == afterInfoSql1.get(0));
assertTrue(beforeInfoSql1.get(1) + 1 == afterInfoSql1.get(1));
assertTrue(beforeInfoSql1.get(2) == afterInfoSql1.get(2));
assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 1 == afterInfoSql2.get(2));
}
}
@Test
public void testExecuteBatchPBENoCache() throws Exception {
Properties props = new Properties();
props.setProperty("prepareThreshold", "0");
String sql1 = "drop table if exists t1; create table t1(id int);";
String sql2 = "insert into t1 values(?)";
String sql2Record = "insert into t1 values(%)";
List<Integer> beforeInfoSql2 = recordCount(sql2Record);
/* PUES / PUES */
try (Connection conn = createConnection(props);
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2)) {
stmt.execute(sql1);
setRecordFullSql(conn);
for (int i = 0; i < 5000; ++i) {
pstmt.setInt(1, i);
pstmt.addBatch();
}
pstmt.executeBatch();
for (int i = 0; i < 5000; ++i) {
pstmt.setInt(1, i);
pstmt.addBatch();
}
pstmt.executeBatch();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql2 = recordCount(sql2Record);
assertTrue(beforeInfoSql2.get(0) + 2 == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
}
}
@Test
public void testExecuteBatchPBEUseCache() throws Exception {
Properties props = new Properties();
props.setProperty("prepareThreshold", "1");
String sql1 = "drop table if exists t1; create table t1(id int);";
String sql2 = "insert into t1 values(?)";
String sql2Record = "insert into t1 values(%)";
List<Integer> beforeInfoSql2 = recordCount(sql2Record);
/* P/DS/S / UES / UES */
try (Connection conn = createConnection(props);
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2)) {
stmt.execute(sql1);
setRecordFullSql(conn);
for (int i = 0; i < 5000; ++i) {
pstmt.setInt(1, i);
pstmt.addBatch();
}
pstmt.executeBatch();
for (int i = 0; i < 5000; ++i) {
pstmt.setInt(1, i);
pstmt.addBatch();
}
pstmt.executeBatch();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql2 = recordCount(sql2Record);
assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
}
}
@Test
public void testExecutePBENoCache() throws Exception {
Properties props = new Properties();
props.setProperty("prepareThreshold", "0");
String sql1 = "drop table if exists t1; create table t1(id int, age int);";
String sql2 = "select ? from t1;";
String sql2Record = "select%from t1";
List<Integer> beforeInfoSql2 = recordCount(sql2Record);
/* PBES / PBES */
try (Connection conn = createConnection(props);
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2)) {
stmt.execute(sql1);
setRecordFullSql(conn);
pstmt.setString(1, "id");
pstmt.execute();
pstmt.setString(1, "age");
pstmt.execute();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql2 = recordCount(sql2Record);
assertTrue(beforeInfoSql2.get(0) + 2 == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
}
}
@Test
public void testExecutePBEUseCache() throws Exception {
Properties props = new Properties();
props.setProperty("prepareThreshold", "1");
String sql1 = "drop table if exists t1; create table t1(id int, age int);";
String sql2 = "select ? from t1;";
String sql2Record = "select%from t1";
List<Integer> beforeInfoSql2 = recordCount(sql2Record);
/* PBES/BES */
try (Connection conn = createConnection(props);
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2)) {
stmt.execute(sql1);
setRecordFullSql(conn);
pstmt.setString(1, "id");
pstmt.execute();
pstmt.setString(1, "age");
pstmt.execute();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql2 = recordCount(sql2Record);
assertTrue(beforeInfoSql2.get(0) + 1 == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
}
}
@Test
public void testExecuteFetchSize() throws Exception {
String sql1 = "drop table if exists t1; create table t1(id int)";
String sql2 = "insert into t1 values(?)";
String sql3 = "select * from t1";
List<Integer> beforeInfoSql3 = recordCount(sql3);
ResultSet rst = null;
try (Connection conn = createConnection();
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2);
PreparedStatement pstmt1 = conn.prepareStatement(sql3)) {
/* prepare data */
stmt.execute(sql1);
for (int i = 0; i < 5000; ++i) {
pstmt.setInt(1, i);
pstmt.addBatch();
}
pstmt.executeBatch();
conn.setAutoCommit(false);
setRecordFullSql(conn);
pstmt1.setFetchSize(1000);
/* PBDES/ES/ES/ES/ES/ES */
rst = pstmt1.executeQuery();
while (rst.next()) {
rst.getInt(1);
}
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql3 = recordCount(sql3);
assertTrue(beforeInfoSql3.get(0) + 1 == afterInfoSql3.get(0));
assertTrue(beforeInfoSql3.get(1) == afterInfoSql3.get(1));
assertTrue(beforeInfoSql3.get(2) + 6 == afterInfoSql3.get(2));
} finally {
if (rst != null) {
rst.close();
}
}
}
@Test
public void testExecuteMultiSqlQ() throws Exception {
Properties props = new Properties();
props.setProperty("preferQueryMode", "simple");
String sql1 = "drop table if exists t1";
String sql2 = "create table t1(id int)";
List<Integer> beforeInfoSql1 = recordCount(sql1);
List<Integer> beforeInfoSql2 = recordCount(sql2);
try (Connection conn = createConnection(props);
PreparedStatement pstmt = conn.prepareStatement(sql1 + ";" + sql2)) {
setRecordFullSql(conn);
/* Q -> Q */
pstmt.execute();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql1 = recordCount(sql1);
List<Integer> afterInfoSql2 = recordCount(sql2);
assertTrue(beforeInfoSql1.get(0) == afterInfoSql1.get(0));
assertTrue(beforeInfoSql1.get(1) + 1 == afterInfoSql1.get(1));
assertTrue(beforeInfoSql1.get(2) == afterInfoSql1.get(2));
assertTrue(beforeInfoSql2.get(0) == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 1 == afterInfoSql2.get(2));
}
}
@Test
public void testExecuteQ() throws Exception {
Properties props = new Properties();
props.setProperty("preferQueryMode", "simple");
String sql1 = "drop table if exists t1; create table t1(id int, age int)";
String sql2 = "select ? from t1";
String sql2Record = "select%from t1";
List<Integer> beforeInfoSql2 = recordCount(sql2Record);
try (Connection conn = createConnection(props);
Statement stmt = conn.createStatement();
PreparedStatement pstmt = conn.prepareStatement(sql2)) {
stmt.execute(sql1);
setRecordFullSql(conn);
/* Q / Q */
pstmt.setString(1, "id");
pstmt.execute();
pstmt.setString(1, "age");
pstmt.execute();
sendPreTimeAndFlush(conn);
List<Integer> afterInfoSql2 = recordCount(sql2Record);
assertTrue(beforeInfoSql2.get(0) == afterInfoSql2.get(0));
assertTrue(beforeInfoSql2.get(1) == afterInfoSql2.get(1));
assertTrue(beforeInfoSql2.get(2) + 2 == afterInfoSql2.get(2));
}
}
}

View File

@ -0,0 +1,119 @@
package org.postgresql.jdbc;
import org.junit.Test;
import org.postgresql.test.jdbc2.BaseTest4;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class ParameterInjectionTest extends BaseTest4 {
private interface ParameterBinder {
void bind(PreparedStatement stmt) throws SQLException;
}
public void testParamInjection(ParameterBinder bindPositiveOne, ParameterBinder bindNegativeOne) throws SQLException {
PreparedStatement stmt = con.prepareStatement("SELECT -?");
bindPositiveOne.bind(stmt);
try (ResultSet rs = stmt.executeQuery()) {
assertTrue(rs.next());
assertEquals(-1, rs.getInt(1));
}
bindNegativeOne.bind(stmt);
try (ResultSet rs = stmt.executeQuery()) {
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
}
PreparedStatement stmt2 = con.prepareStatement("SELECT -?, ?");
bindPositiveOne.bind(stmt2);
stmt2.setString(2, "\nWHERE 0 > 1");
try (ResultSet rs = stmt2.executeQuery()) {
assertTrue(rs.next());
assertEquals(-1, rs.getInt(1));
}
bindNegativeOne.bind(stmt2);
stmt2.setString(2, "\nWHERE 0 > 1");
try (ResultSet rs = stmt2.executeQuery()) {
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
}
}
@Test
public void handleInt2() throws SQLException {
testParamInjection(
stmt -> {
stmt.setShort(1, (short) 1);
},
stmt -> {
stmt.setShort(1, (short) -1);
}
);
}
@Test
public void handleInt4() throws SQLException {
testParamInjection(
stmt -> {
stmt.setInt(1, 1);
},
stmt -> {
stmt.setInt(1, -1);
}
);
}
@Test
public void handleBigInt() throws SQLException {
testParamInjection(
stmt -> {
stmt.setLong(1, (long) 1);
},
stmt -> {
stmt.setLong(1, (long) -1);
}
);
}
@Test
public void handleNumeric() throws SQLException {
testParamInjection(
stmt -> {
stmt.setBigDecimal(1, new BigDecimal("1"));
},
stmt -> {
stmt.setBigDecimal(1, new BigDecimal("-1"));
}
);
}
@Test
public void handleFloat() throws SQLException {
testParamInjection(
stmt -> {
stmt.setFloat(1, 1);
},
stmt -> {
stmt.setFloat(1, -1);
}
);
}
@Test
public void handleDouble() throws SQLException {
testParamInjection(
stmt -> {
stmt.setDouble(1, 1);
},
stmt -> {
stmt.setDouble(1, -1);
}
);
}
}

View File

@ -41,6 +41,7 @@ public class TestUtil {
*/
public static final String SERVER_HOST_PORT_PROP = "_test_hostport";
public static final String DATABASE_PROP = "_test_database";
private static String applicationName = "Driver Tests";
/*
* Returns the Test database JDBC URL
@ -50,10 +51,10 @@ public class TestUtil {
}
public static String getURL(String server, int port) {
return getURL(server + ":" + port, getDatabase());
return getURL(server + ":" + port, getDatabase(), applicationName);
}
public static String getURL(String hostport, String database) {
public static String getURL(String hostport, String database, String applicationName) {
String logLevel = "";
if (getLogLevel() != null && !getLogLevel().equals("")) {
logLevel = "&loggerLevel=" + getLogLevel();
@ -99,10 +100,11 @@ public class TestUtil {
allowEncodingChanges = "&allowEncodingChanges=" + getAllowEncodingChanges();
}
String application = "?ApplicationName=" + applicationName;
return "jdbc:postgresql://"
+ hostport + "/"
+ database
+ "?ApplicationName=Driver Tests"
+ application
+ logLevel
+ logFile
+ protocolVersion
@ -363,6 +365,10 @@ public class TestUtil {
return openDB(props,getDatabase());
}
public static Connection openDB(String dbName) throws Exception {
return openDB(new Properties(), dbName);
}
public static Connection openDBPG(Properties props) throws Exception {
return openDB(props,getDatabasePG());
}
@ -412,7 +418,10 @@ public class TestUtil {
String hostport = props.getProperty(SERVER_HOST_PORT_PROP, getServer() + ":" + getPort());
String database = props.getProperty(DATABASE_PROP, dbName);
return DriverManager.getConnection(getURL(hostport, database), props);
if (props.containsKey("ApplicationName")) {
return DriverManager.getConnection(getURL(hostport, database, props.get("ApplicationName").toString()), props);
}
return DriverManager.getConnection(getURL(hostport, database, applicationName), props);
}
/*

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* test binary
*
* @author zhangting
* @since 2024-08-20
*/
public class BinaryTest extends BaseTest4B {
@Test
public void testBinary1() throws SQLException {
TestUtil.createTable(con, "test_binary_b", "id int, c1 binary(5)");
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_binary_b VALUES (?,?)")) {
pstmt.setInt(1, 1);
try (InputStream data = new ByteArrayInputStream("abcde".getBytes(StandardCharsets.UTF_8))) {
pstmt.setBinaryStream(2, data);
pstmt.execute();
} catch (IOException e) {
e.printStackTrace();
}
}
String sql = "INSERT INTO test_binary_b VALUES (2,'abcde'::binary)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.execute();
}
try (Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM test_binary_b")) {
while (rs.next()) {
assertEquals("\\x6162636465", new String(rs.getBytes(2),
StandardCharsets.UTF_8));
}
}
TestUtil.dropTable(con, "test_binary_b");
}
@Test
public void testBinary2() throws SQLException {
try (Statement stat = con.createStatement()) {
try (ResultSet rs = stat.executeQuery("SELECT '10101'::binary(5)")) {
while (rs.next()) {
assertEquals("\\x3130313031", new String(rs.getBytes(1),
StandardCharsets.UTF_8));
}
}
try (ResultSet rs = stat.executeQuery("SELECT cast('abc' as binary)")) {
while (rs.next()) {
assertEquals("\\x616263", rs.getString(1));
}
}
stat.execute("set bytea_output=escape;");
try (ResultSet rs = stat.executeQuery("SELECT '10101'::binary(5)")) {
while (rs.next()) {
assertEquals("10101", new String(rs.getBytes(1),
StandardCharsets.UTF_8));
}
}
try (ResultSet rs = stat.executeQuery("SELECT cast('abc' as binary)")) {
while (rs.next()) {
assertEquals("abc", rs.getString(1));
}
}
}
}
/*
* test binary type
*/
@Test
public void testBinaryType() throws Exception {
TestUtil.createTable(con, "test_binary", "c1 binary,c2 binary(5),"
+ "c3 varbinary,c4 varbinary(5)");
try (Statement stat = con.createStatement()) {
stat.execute("set bytea_output=escape;");
stat.executeUpdate("INSERT INTO test_binary VALUES ('a','abcde','a','abcde')");
}
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_binary")) {
assertTrue(rs.next());
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(4, rsmd.getColumnCount());
assertEquals(Types.BINARY, rsmd.getColumnType(1));
assertEquals(Types.BINARY, rsmd.getColumnType(2));
assertEquals(Types.VARBINARY, rsmd.getColumnType(3));
assertEquals(Types.VARBINARY, rsmd.getColumnType(4));
assertEquals("a", rs.getString(1));
assertEquals("abcde", rs.getString(2));
assertEquals("a", rs.getString(3));
assertEquals("abcde", rs.getString(4));
}
TestUtil.dropTable(con, "test_binary");
}
}

View File

@ -0,0 +1,88 @@
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
public class BitTest extends BaseTest4B {
@Override
protected void openDB(Properties props) throws Exception {
props.put("bitOutput", "dec");
props.put("ApplicationName", "PostgreSQL JDBC Driver");
super.openDB(props);
}
/*
* Tests bit type
*/
@Test
public void testBit() throws Exception {
TestUtil.createTable(con, "test_bit", "c1 bit(1),c2 bit(10),c3 bit(6)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_bit VALUES (1, 12.569, 8.753)");
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT c1,c2,c3 FROM test_bit");
assertTrue(rs.next());
Object o1 = rs.getObject(1);
assertNotNull(o1);
assertEquals(true, o1);
String o2 = rs.getObject(2).getClass().toString();
assertNotNull(o2);
assertEquals("class [B", o2);
String o3 = rs.getObject(3).getClass().toString();
assertNotNull(o3);
assertEquals("class [B", o3);
TestUtil.dropTable(con, "test_bit");
}
/*
* Tests bit by getBytes()
*/
@Test
public void testBitToBytes() throws Exception {
TestUtil.createTable(con, "test_bitToBytes", "c1 bit(10),c2 bit(18)");
String sql = "INSERT INTO test_bitToBytes VALUES (123.45, 18437.567)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.executeUpdate();
}
try (Statement ps = con.createStatement();
ResultSet rs = ps.executeQuery("SELECT c1,c2 FROM test_bitToBytes")) {
assertTrue(rs.next());
String r1 = rs.getString(1);
assertNotNull(r1);
assertEquals("123", r1);
byte[] bytes1 = rs.getBytes(1);
assertNotNull(bytes1);
assertEquals(0, bytes1[0]);
assertEquals(123, bytes1[1]);
String r2 = rs.getString(2);
assertNotNull(r2);
assertEquals("18438", r2);
byte[] bytes2 = rs.getBytes(2);
assertNotNull(bytes2);
assertEquals(0, bytes2[0]);
assertEquals(72, bytes2[1]);
assertEquals(6, bytes2[2]);
} finally {
TestUtil.dropTable(con, "test_bitToBytes");
}
}
}

View File

@ -5,7 +5,6 @@
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.core.ServerVersion;
import org.postgresql.core.types.PGBlob;
import org.postgresql.jdbc.PgConnection;
import org.postgresql.test.TestUtil;
@ -18,8 +17,11 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
public class BlobTest extends BaseTest4B {
@ -107,4 +109,56 @@ public class BlobTest extends BaseTest4B {
}
}
}
@Test
public void testStringToBlob() throws SQLException {
String sql = "INSERT INTO test_blob_b VALUES (2,'1234'::tinyblob,"
+ "'1234'::blob,'1234'::mediumblob,'1234'::longblob)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.execute();
}
try (Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM test_blob_b")) {
while (rs.next()) {
assertEquals("1234", new String(rs.getBlob(2).getBytes(1, 4),
StandardCharsets.UTF_8));
assertEquals("1234", new String(rs.getBlob(3).getBytes(1, 4),
StandardCharsets.UTF_8));
assertEquals("1234", new String(rs.getBlob(4).getBytes(1, 4),
StandardCharsets.UTF_8));
assertEquals("1234", new String(rs.getBlob(5).getBytes(1, 4),
StandardCharsets.UTF_8));
}
}
}
/**
* test blob by getBytes
*
* @throws SQLException sql exception
*/
@Test
public void testBlobToBytes() throws SQLException {
String sql = "INSERT INTO test_blob_b VALUES (1,'abcd'::tinyblob,"
+ "'abcd'::blob,'abcd'::mediumblob,'abcd'::longblob)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.execute();
}
try (Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM test_blob_b")) {
assertTrue(rs.next());
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(Types.LONGVARBINARY, rsmd.getColumnType(3));
assertEquals("abcd", new String(rs.getBytes(2),
StandardCharsets.UTF_8));
assertEquals("abcd", new String(rs.getBytes(3),
StandardCharsets.UTF_8));
assertEquals("abcd", new String(rs.getBytes(4),
StandardCharsets.UTF_8));
assertEquals("abcd", new String(rs.getBytes(5),
StandardCharsets.UTF_8));
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* test date
*
* @author zhangting
* @since 2024-08-30
*/
public class DateTest extends BaseTest4B {
/*
* test Date type
*/
@Test
public void testDate() throws Exception {
TestUtil.createTable(con, "test_date", "id date");
String sql = "INSERT INTO test_date VALUES (?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setString(1, "0000-01-01");
pstmt.executeUpdate();
pstmt.setString(1, "epoch");
pstmt.executeUpdate();
}
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_date")) {
assertTrue(rs.next());
assertEquals("0001-01-01", rs.getObject(1).toString());
assertTrue(rs.next());
assertEquals("1970-01-01", rs.getObject(1).toString());
}
TestUtil.dropTable(con, "test_date");
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* test default type
*
* @author zhangting
* @since 2024-09-04
*/
public class DefaultTypeTest extends BaseTest4B {
/*
* test Date type
*/
@Test
public void testDefaultType() throws Exception {
TestUtil.createTable(con, "test_default_type",
"c1 set('abc','ttp','mytest'),c2 enum('2012','2013','2014')");
String sql = "INSERT INTO test_default_type VALUES ('abc','2014')";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.executeUpdate();
}
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_default_type")) {
assertTrue(rs.next());
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(2, rsmd.getColumnCount());
assertEquals(Types.CHAR, rsmd.getColumnType(1));
assertEquals(Types.CHAR, rsmd.getColumnType(2));
assertEquals("abc", rs.getString(1));
assertEquals("2014", rs.getString(2));
}
TestUtil.dropTable(con, "test_default_type");
}
}

View File

@ -0,0 +1,145 @@
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class IntTest extends BaseTest4B {
/*
* Tests tinyint1 to boolean
*/
@Test
public void testTinyint1() throws Exception {
TestUtil.createTable(con, "test_tinyint", "id tinyint(1)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_tinyint VALUES (?)");
pstmt.setObject(1, 18, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, 106, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, -1, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, 0, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, -10, Types.INTEGER);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_tinyint");
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(true, r1);
assertTrue(rs.next());
Object r2 = rs.getObject(1);
assertNotNull(r2);
assertEquals(true, r2);
assertTrue(rs.next());
Object r3 = rs.getObject(1);
assertNotNull(r3);
assertEquals(true, r3);
assertTrue(rs.next());
Object r4 = rs.getObject(1);
assertNotNull(r4);
assertEquals(false, r4);
assertTrue(rs.next());
Object r5 = rs.getObject(1);
assertNotNull(r5);
assertEquals(false, r5);
TestUtil.dropTable(con, "test_tinyint");
}
/*
* Tests tinyint2
*/
@Test
public void testTinyint2() throws Exception {
TestUtil.createTable(con, "test_tinyint2", "id tinyint(2),id2 smallint(1)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_tinyint2 VALUES (?,?)");
pstmt.setObject(1, 25, Types.INTEGER);
pstmt.setObject(2, 36, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, -24, Types.INTEGER);
pstmt.setObject(2, -54, Types.INTEGER);
pstmt.executeUpdate();
pstmt.setObject(1, 0, Types.INTEGER);
pstmt.setObject(2, 0, Types.INTEGER);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id,id2 FROM test_tinyint2");
assertTrue(rs.next());
Object r11 = rs.getObject(1);
assertNotNull(r11);
assertEquals(25, r11);
Object r12 = rs.getObject(2);
assertNotNull(r12);
assertEquals(36, r12);
assertTrue(rs.next());
Object r21 = rs.getObject(1);
assertNotNull(r21);
assertEquals(-24, r21);
Object r22 = rs.getObject(2);
assertNotNull(r22);
assertEquals(-54, r22);
assertTrue(rs.next());
Object r31 = rs.getObject(1);
assertNotNull(r31);
assertEquals(0, r31);
Object r32 = rs.getObject(2);
assertNotNull(r32);
assertEquals(0, r32);
TestUtil.dropTable(con, "test_tinyint2");
}
/*
* Tests int type
*/
@Test
public void testIntType() throws Exception {
TestUtil.createTable(con, "test_int", "c1 int1,c2 int2,c3 int4,"
+ "c4 int8,uc1 uint1,uc2 uint2,uc3 uint4,uc4 uint8");
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_int")) {
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(8, rsmd.getColumnCount());
assertEquals(Types.TINYINT, rsmd.getColumnType(1));
assertEquals(Types.SMALLINT, rsmd.getColumnType(2));
assertEquals(Types.INTEGER, rsmd.getColumnType(3));
assertEquals(Types.BIGINT, rsmd.getColumnType(4));
assertEquals(Types.TINYINT, rsmd.getColumnType(5));
assertEquals(Types.SMALLINT, rsmd.getColumnType(6));
assertEquals(Types.INTEGER, rsmd.getColumnType(7));
assertEquals(Types.BIGINT, rsmd.getColumnType(8));
} finally {
TestUtil.dropTable(con, "test_int");
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
/**
* test null
*
* @author zhangting
* @since 2024-08-05
*/
public class NullTest extends BaseTest4B {
@Test
public void testStringNull() throws Exception {
TestUtil.createTable(con, "test_null", "id varchar, id2 varchar");
try (Statement statement = con.createStatement()) {
statement.execute("INSERT INTO test_null VALUES ('acc','uu'),('ptv','bb'),('mtt','gf')");
}
String sql = "select id,id2 from test_null where id in (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setObject(1, "ptv");
pstmt.setNull(2, -3);
try (ResultSet rs = pstmt.executeQuery()) {
assertTrue(rs.next());
String s1 = rs.getString(1);
assertNotNull(s1);
assertEquals("ptv", s1);
String s2 = rs.getString(2);
assertNotNull(s2);
assertEquals("bb", s2);
}
}
TestUtil.dropTable(con, "test_null");
}
@Test
public void testIntNull() throws Exception {
TestUtil.createTable(con, "test_null", "id int, id2 int");
try (Statement statement = con.createStatement()) {
statement.execute("INSERT INTO test_null VALUES (51,34),(92,44),(67,88)");
}
String sql = "select id,id2 from test_null where id in (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setInt(1, 92);
pstmt.setNull(2, 1111);
try (ResultSet rs = pstmt.executeQuery()) {
assertTrue(rs.next());
int r1 = rs.getInt(1);
assertNotNull(r1);
assertEquals(92, r1);
int r2 = rs.getInt(2);
assertNotNull(r2);
assertEquals(44, r2);
}
}
TestUtil.dropTable(con, "test_null");
}
@Test
public void testDateNull() throws Exception {
TestUtil.createTable(con, "test_null", "id date, id2 varchar");
try (Statement statement = con.createStatement()) {
statement.execute("INSERT INTO test_null VALUES ('2024-05-02','n1')");
statement.execute("INSERT INTO test_null VALUES ('2024-03-15','n2')");
statement.execute("INSERT INTO test_null VALUES ('2024-06-07','n3')");
}
String sql = "select id,id2 from test_null where id in (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setObject(1, "2024-03-15");
pstmt.setNull(2, -2);
try (ResultSet rs = pstmt.executeQuery()) {
assertTrue(rs.next());
Date r1 = rs.getDate(1);
assertNotNull(r1);
Date d1 = new SimpleDateFormat("yyyy-MM-dd").parse("2024-03-15");
assertEquals(d1, r1);
String r2 = rs.getString(2);
assertNotNull(r2);
assertEquals("n2", r2);
}
}
TestUtil.dropTable(con, "test_null");
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
/**
* test numeric
*
* @author zhangting
* @since 2024-08-20
*/
public class NumericTest extends BaseTest4B {
/*
* test numeric type
*/
@Test
public void testNumeric() throws Exception {
TestUtil.createTable(con, "test_numeric", "c1 numeric,c2 numeric(8,4),c3 float,"
+ "c4 float(8,4),c5 double,c6 double(8,4),c7 real,c8 real(8,4),c9 decimal(8,4)");
String sql = "INSERT INTO test_numeric VALUES (?,?,?,?,?,?,?,?,?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
for (int i = 1; i <= 9; i++) {
pstmt.setDouble(i, 92.456739023);
}
pstmt.executeUpdate();
}
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_numeric")) {
assertTrue(rs.next());
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(9, rsmd.getColumnCount());
assertEquals(Types.DECIMAL, rsmd.getColumnType(1));
assertEquals(Types.DECIMAL, rsmd.getColumnType(2));
assertEquals(Types.REAL, rsmd.getColumnType(3));
assertEquals(Types.DECIMAL, rsmd.getColumnType(4));
assertEquals(Types.DOUBLE, rsmd.getColumnType(5));
assertEquals(Types.DECIMAL, rsmd.getColumnType(6));
assertEquals(Types.REAL, rsmd.getColumnType(7));
assertEquals(Types.DECIMAL, rsmd.getColumnType(8));
assertEquals(Types.DECIMAL, rsmd.getColumnType(9));
assertEquals(new BigDecimal(92), rs.getObject(1));
assertEquals(new String("92.4567"), rs.getString(2));
assertEquals(new String("92.4567"), rs.getString(4));
assertEquals(new String("92.4567"), rs.getString(6));
assertEquals(new String("92.4567"), rs.getString(8));
assertEquals(new String("92.4567"), rs.getString(9));
}
TestUtil.dropTable(con, "test_numeric");
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
/**
* test raw
*
* @author zhangting
* @since 2024-09-10
*/
public class RawTest extends BaseTest4B {
/*
* test raw type
*/
@Test
public void testRaw() throws Exception {
TestUtil.createTable(con, "test_raw", "c1 blob,c2 raw,c3 bytea");
try (Statement statement = con.createStatement()) {
statement.execute("set bytea_output=escape;");
statement.execute("INSERT INTO test_raw VALUES (empty_blob(),hextoraw('deadbeef'),e'\\\\xdeadbeef')");
statement.execute("INSERT INTO test_raw VALUES ('null','null','null')");
}
String sql = "select c1,c2,c3 from test_raw";
try (PreparedStatement pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
assertTrue(rs.next());
assertEquals("", rs.getString(1));
assertEquals("deadbeef", rs.getString(2));
assertEquals("\\336\\255\\276\\357", rs.getString(3));
assertTrue(rs.next());
assertEquals("null", rs.getString(1));
assertEquals("null", rs.getString(2));
assertEquals("null", rs.getString(3));
}
TestUtil.dropTable(con, "test_raw");
}
}

View File

@ -7,6 +7,9 @@ import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@ -42,4 +45,51 @@ public class TimeTest extends BaseTest4B {
TestUtil.dropTable(con, "test_time");
}
@Test
public void testYearToDate() throws SQLException, ParseException {
TestUtil.createTable(con, "test_year", "c date,c2 year default '2024'");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_year(c) VALUES (?);");
pstmt.setObject(1, "2023-05-20", Types.DATE);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT c2 FROM test_year");
assertTrue(rs.next());
Object c21 = rs.getObject(1);
assertNotNull(c21);
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2024-01-01");
assertEquals(date, c21);
Date c22 = rs.getDate(1);
assertNotNull(c22);
assertEquals(date, c22);
TestUtil.dropTable(con, "test_year");
}
@Test
public void testAsTime() throws SQLException {
TestUtil.createTable(con, "test_as_time", "id int");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_as_time VALUES (?);");
pstmt.setObject(1, -11);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT cast(id as time) from test_as_time");
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals("00:00:11", r1.toString());
String r2 = rs.getString(1);
assertNotNull(r2);
assertEquals("00:00:11", r2);
Time r3 = rs.getTime(1);
assertNotNull(r3);
assertEquals("00:00:11", r3.toString());
TestUtil.dropTable(con, "test_as_time");
}
}

View File

@ -0,0 +1,155 @@
package org.postgresql.test.dolphintest;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertEquals;
public class TimestampTest extends BaseTest4B {
@Test
public void testTimeZone() throws Exception {
TestUtil.createTable(con, "test_timestamp", "id int");
String createSql = "INSERT INTO test_timestamp VALUES (1)";
try (PreparedStatement pstmt = con.prepareStatement(createSql)) {
pstmt.execute();
}
String updateSql = "UPDATE test_timestamp SET id = timestampdiff(second,?,?)";
try (PreparedStatement pstmt2 = con.prepareStatement(updateSql)) {
java.util.Date start = new java.util.Date();
pstmt2.setTimestamp(1, new Timestamp(start.getTime()));
pstmt2.setTimestamp(2, new Timestamp(start.getTime() + 6000));
pstmt2.execute();
}
String selectSql = "SELECT id FROM test_timestamp";
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery(selectSql)) {
assertTrue(rs.next());
int r1 = rs.getInt(1);
assertNotNull(r1);
assertEquals(6, r1);
}
TestUtil.dropTable(con, "test_timestamp");
}
@Test
public void testTimeZone2() throws Exception {
TestUtil.createTable(con, "test_timeZone", "id timestamp");
String sql = "INSERT INTO test_timeZone VALUES (?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
java.util.Date start = new java.util.Date();
pstmt.setTimestamp(1, new Timestamp(start.getTime()));
pstmt.execute();
}
TestUtil.dropTable(con, "test_timeZone");
}
@Test
public void testTimeRange() throws Exception {
TestUtil.createTable(con, "test_TimeRange", "id int, c2 timestamp");
String sql = "INSERT INTO test_TimeRange VALUES (?, ?)";
java.util.Date start = new java.util.Date();
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setInt(1, 1);
pstmt.setTimestamp(2, new Timestamp(start.getTime() - 100000));
pstmt.execute();
pstmt.setInt(1, 2);
pstmt.setTimestamp(2, new Timestamp(start.getTime()));
pstmt.execute();
pstmt.setInt(1, 3);
pstmt.setTimestamp(2, new Timestamp(start.getTime() + 500000));
pstmt.execute();
pstmt.setInt(1, 4);
pstmt.setTimestamp(2, new Timestamp(start.getTime() + 1000000000));
pstmt.execute();
}
String selectSql = "select id, c2 from test_TimeRange where c2 between ? and ?;";
try (PreparedStatement pstmt2 = con.prepareStatement(selectSql)) {
pstmt2.setTimestamp(1, new Timestamp(start.getTime()-5000));
pstmt2.setTimestamp(2, new Timestamp(start.getTime() + 800000));
try (ResultSet rs = pstmt2.executeQuery()) {
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
}
}
String selectSql2 = "select id, c2 from test_TimeRange where c2 >= ? and c2 <= ?;";
try (PreparedStatement pstmt2 = con.prepareStatement(selectSql2)) {
pstmt2.setTimestamp(1, new Timestamp(start.getTime()-5000));
pstmt2.setTimestamp(2, new Timestamp(start.getTime() + 800000));
try (ResultSet rs = pstmt2.executeQuery()) {
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
}
}
TestUtil.dropTable(con, "test_TimeRange");
}
@Test
public void testYear2() throws Exception {
TestUtil.createTable(con, "test_year2", "id year(2)");
try (Statement stat = con.createStatement()) {
stat.execute("INSERT INTO test_year2 VALUES (8),(69),(70),(82)");
}
String sql5 = "select id from test_year2";
try (PreparedStatement pstmt2 = con.prepareStatement(sql5);
ResultSet rs = pstmt2.executeQuery()) {
assertTrue(rs.next());
Date d1 = rs.getDate(1);
assertNotNull(d1);
Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2008-01-01");
assertEquals(date, d1);
String s1 = rs.getString(1);
assertEquals("2008-01-01", s1);
assertTrue(rs.next());
Date d2 = rs.getDate(1);
assertNotNull(d2);
Date date2 = new SimpleDateFormat("yyyy-MM-dd").parse("2069-01-01");
assertEquals(date2, d2);
String s2 = rs.getString(1);
assertEquals("2069-01-01", s2);
assertTrue(rs.next());
Date d3 = rs.getDate(1);
assertNotNull(d3);
Date date3 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01");
assertEquals(date3, d3);
String s3 = rs.getString(1);
assertEquals("1970-01-01", s3);
assertTrue(rs.next());
Date d4 = rs.getDate(1);
assertNotNull(d4);
Date date4 = new SimpleDateFormat("yyyy-MM-dd").parse("1982-01-01");
assertEquals(date4, d4);
String s4 = rs.getString(1);
assertEquals("1982-01-01", s4);
}
TestUtil.dropTable(con, "test_year2");
}
}

View File

@ -2,15 +2,21 @@ package org.postgresql.test.dolphintest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4B;
import java.math.BigInteger;
import java.sql.*;
import java.sql.PreparedStatement;
import java.sql.Types;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Array;
import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class UnsignedTest extends BaseTest4B {
/**
@ -21,19 +27,20 @@ public class UnsignedTest extends BaseTest4B {
public void testUint1() throws SQLException {
TestUtil.createTable(con, "test_unit1", "id uint1");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit1 VALUES (?)");
pstmt.setObject(1, 234, Types.SMALLINT);
pstmt.executeUpdate();
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit1 VALUES (?)")) {
pstmt.setObject(1, 234, Types.SMALLINT);
pstmt.executeUpdate();
}
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit1");
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(234, r1);
TestUtil.dropTable(con, "test_unit1");
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit1");) {
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(234, r1);
} finally {
TestUtil.dropTable(con, "test_unit1");
}
}
/**
@ -44,19 +51,20 @@ public class UnsignedTest extends BaseTest4B {
public void testUint2() throws SQLException {
TestUtil.createTable(con, "test_unit2", "id uint2");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit2 VALUES (?)");
pstmt.setObject(1, 65518, Types.INTEGER);
pstmt.executeUpdate();
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit2 VALUES (?)")) {
pstmt.setObject(1, 65518, Types.INTEGER);
pstmt.executeUpdate();
}
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit2");
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(65518, r1);
TestUtil.dropTable(con, "test_unit2");
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit2")) {
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(65518, r1);
} finally {
TestUtil.dropTable(con, "test_unit2");
}
}
/**
@ -67,20 +75,20 @@ public class UnsignedTest extends BaseTest4B {
public void testUint4() throws SQLException {
TestUtil.createTable(con, "test_unit4", "id uint4");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit4 VALUES (?)");
long l = 4294967282L;
pstmt.setObject(1, l, Types.BIGINT);
pstmt.executeUpdate();
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit4 VALUES (?)")) {
pstmt.setObject(1, 4294967282L, Types.BIGINT);
pstmt.executeUpdate();
}
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit4");
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(l, r1);
TestUtil.dropTable(con, "test_unit4");
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit4")) {
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(4294967282L, r1);
} finally {
TestUtil.dropTable(con, "test_unit4");
}
}
/**
@ -90,29 +98,113 @@ public class UnsignedTest extends BaseTest4B {
@Test
public void testUint8() throws SQLException {
TestUtil.createTable(con, "test_unit8", "id uint8");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit8 VALUES (?)");
BigInteger b = new BigInteger("9223372036859999999");
pstmt.setObject(1, b, Types.NUMERIC);
pstmt.executeUpdate();
BigInteger b2 = new BigInteger("15223372036859999999");
pstmt.setObject(1, b2, Types.NUMERIC);
pstmt.executeUpdate();
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_unit8 VALUES (?)")) {
pstmt.setObject(1, b, Types.NUMERIC);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit8");
pstmt.setObject(1, b2, Types.NUMERIC);
pstmt.executeUpdate();
}
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(b, r1);
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT id FROM test_unit8")) {
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(b, r1);
assertTrue(rs.next());
Object r2 = rs.getObject(1);
assertNotNull(r2);
assertEquals(b2, r2);
assertTrue(rs.next());
Object r2 = rs.getObject(1);
assertNotNull(r2);
assertEquals(b2, r2);
} finally {
TestUtil.dropTable(con, "test_unit8");
}
}
TestUtil.dropTable(con, "test_unit8");
@Test
public void testCreateArrayOfUint1() throws SQLException {
try (PreparedStatement pstmt = con.prepareStatement("SELECT ?::uint1[]")) {
Object[] in = new Object[3];
in[0] = 0;
in[1] = 88;
in[2] = 115;
pstmt.setArray(1, con.createArrayOf("uint1", in));
try (ResultSet rs = pstmt.executeQuery()) {
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Object[] out = (Object[]) arr.getArray();
Assert.assertEquals(3, out.length);
Assert.assertEquals(0, Integer.parseInt(out[0].toString()));
Assert.assertEquals(88, Integer.parseInt(out[1].toString()));
Assert.assertEquals(115, Integer.parseInt(out[2].toString()));
}
}
}
@Test
public void testCreateArrayOfUint2() throws SQLException {
try (PreparedStatement pstmt = con.prepareStatement("SELECT ?::uint2[]")) {
Short[] in = new Short[3];
in[0] = 0;
in[1] = 12654;
in[2] = 30035;
pstmt.setArray(1, con.createArrayOf("uint2", in));
try (ResultSet rs = pstmt.executeQuery()) {
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Short[] out = (Short[]) arr.getArray();
Assert.assertEquals(3, out.length);
Assert.assertEquals(0, out[0].shortValue());
Assert.assertEquals(12654, out[1].shortValue());
Assert.assertEquals(30035, out[2].shortValue());
}
}
}
@Test
public void testCreateArrayOfUint4() throws SQLException {
try (PreparedStatement pstmt = con.prepareStatement("SELECT ?::uint4[]")) {
Integer[] in = new Integer[2];
in[0] = 0;
in[1] = 1994967295;
pstmt.setArray(1, con.createArrayOf("uint4", in));
try (ResultSet rs = pstmt.executeQuery()) {
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Integer[] out = (Integer[]) arr.getArray();
Assert.assertEquals(2, out.length);
Assert.assertEquals(0, out[0].intValue());
Assert.assertEquals(1994967295, out[1].intValue());
}
}
}
@Test
public void testCreateArrayOfUint8() throws SQLException {
try (PreparedStatement pstmt = con.prepareStatement("SELECT ?::uint8[]")) {
Long[] in = new Long[2];
in[0] = 0L;
in[1] = 32458765334567556L;
pstmt.setArray(1, con.createArrayOf("uint8", in));
try (ResultSet rs = pstmt.executeQuery()) {
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Object[] out = (Object[]) arr.getArray();
Long[] outLong = new Long[out.length];
for (int i = 0; i < out.length; i++) {
outLong[i] = Long.valueOf(out[i].toString());
}
Assert.assertEquals(2, out.length);
Assert.assertEquals(0L, outLong[0].longValue());
Assert.assertEquals(32458765334567556L, outLong[1].longValue());
}
}
}
}

View File

@ -109,7 +109,7 @@ public class ArrayTest extends BaseTest4 {
assertEquals(3, intarr[2].intValue());
arr = rs.getArray(2);
assertEquals(Types.NUMERIC, arr.getBaseType());
assertEquals(Types.DECIMAL, arr.getBaseType());
BigDecimal[] decarr = (BigDecimal[]) arr.getArray();
assertEquals(2, decarr.length);
assertEquals(new BigDecimal("3.1"), decarr[0]);
@ -151,7 +151,7 @@ public class ArrayTest extends BaseTest4 {
Assert.assertEquals(3, intarr[2].intValue());
arr = rs.getArray(2);
Assert.assertEquals(Types.NUMERIC, arr.getBaseType());
Assert.assertEquals(Types.DECIMAL, arr.getBaseType());
BigDecimal[] decarr = (BigDecimal[]) arr.getArray();
Assert.assertEquals(2, decarr.length);
Assert.assertEquals(new BigDecimal("3.1"), decarr[0]);
@ -223,7 +223,7 @@ public class ArrayTest extends BaseTest4 {
Assert.assertEquals(3, intarr[2].intValue());
arr = rs.getArray(2);
Assert.assertEquals(Types.NUMERIC, arr.getBaseType());
Assert.assertEquals(Types.DECIMAL, arr.getBaseType());
BigDecimal[] decarr = (BigDecimal[]) arr.getArray();
Assert.assertEquals(2, decarr.length);
Assert.assertEquals(new BigDecimal("3.1"), decarr[0]);
@ -271,7 +271,7 @@ public class ArrayTest extends BaseTest4 {
arrrs.close();
arr = rs.getArray(2);
Assert.assertEquals(Types.NUMERIC, arr.getBaseType());
Assert.assertEquals(Types.DECIMAL, arr.getBaseType());
arrrs = arr.getResultSet();
Assert.assertTrue(arrrs.next());
Assert.assertEquals(new BigDecimal("3.1"), arrrs.getBigDecimal(2));

View File

@ -171,7 +171,7 @@ public class CallableStmtTest extends BaseTest4 {
assumeCallableStatementsSupported();
CallableStatement call = con.prepareCall(func + pkgName + "getNumeric (?) }");
call.setBigDecimal(2, new java.math.BigDecimal(4));
call.registerOutParameter(1, Types.NUMERIC);
call.registerOutParameter(1, Types.DECIMAL);
call.execute();
assertEquals(new java.math.BigDecimal(42), call.getBigDecimal(1));
}
@ -180,7 +180,7 @@ public class CallableStmtTest extends BaseTest4 {
public void testGetNumericWithoutArg() throws Throwable {
assumeCallableStatementsSupported();
CallableStatement call = con.prepareCall(func + pkgName + "getNumericWithoutArg () }");
call.registerOutParameter(1, Types.NUMERIC);
call.registerOutParameter(1, Types.DECIMAL);
call.execute();
assertEquals(new java.math.BigDecimal(42), call.getBigDecimal(1));
}

View File

@ -1332,4 +1332,38 @@ public class DatabaseMetaDataTest {
}
}
@Test
public void testPrimaryKey() throws SQLException {
try (Statement stmt = con.createStatement()) {
stmt.execute("drop table if exists test_metadata");
stmt.execute("CREATE TABLE test_metadata (\n"
+ " col_pk numeric NOT NULL primary key,\n"
+ " partition_col character varying(30) NOT NULL\n"
+ ")\n"
+ "WITH (orientation=row, compression=no)\n"
+ "PARTITION BY LIST (partition_col)\n"
+ "(\n"
+ " PARTITION partition_col_id_0100 VALUES ('0100') ,\n"
+ " PARTITION partition_col_id_0110 VALUES ('0110') ,\n"
+ " PARTITION partition_col_id_other VALUES (DEFAULT)\n"
+ ");");
}
DatabaseMetaData metaData = con.getMetaData();
try (ResultSet rs = metaData.getPrimaryKeys("", "public", "test_metadata")) {
assertTrue(rs.next());
assertEquals("col_pk", rs.getString(4));
assertEquals(1, rs.getInt(5));
assertFalse(rs.next());
}
try (ResultSet rs1 = metaData.getIndexInfo("", "public",
"test_metadata", true, true)) {
assertTrue(rs1.next());
assertEquals("test_metadata_pkey", rs1.getString(6));
assertEquals("col_pk", rs1.getString(9));
assertFalse(rs1.next());
}
TestUtil.dropTable(con, "test_metadata");
}
}

View File

@ -15,6 +15,7 @@ import org.junit.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.nio.charset.Charset;
import java.util.Locale;
/**
@ -35,6 +36,7 @@ public class EncodingTest {
@Test
public void testTransformations() throws Exception {
Encoding encoding = Encoding.getDatabaseEncoding("UTF8");
assertTrue(encoding.hasAsciiNumbers());
assertEquals("ab", encoding.decode(new byte[]{97, 98}));
assertEquals(2, encoding.encode("ab").length);
@ -55,4 +57,31 @@ public class EncodingTest {
assertEquals(98, reader.read());
assertEquals(-1, reader.read());
}
@Test
public void testEncodingWithNull() {
try {
Encoding encoding = Encoding.getDatabaseEncoding(null);
} catch (IllegalArgumentException e) {
assertEquals(e.getMessage(), "Null charset name");
}
}
@Test
public void testGetJVMEncoding() {
Encoding encoding = Encoding.getJVMEncoding("UTF8");
assertEquals(encoding.name(), "UTF-8");
Encoding encodingGBK = Encoding.getJVMEncoding("GBK");
assertEquals(encodingGBK.name(), "GBK");
Encoding encodingWrong = Encoding.getJVMEncoding("encodingWrong");
assertEquals(encodingWrong.name(), Charset.defaultCharset().name());
}
@Test
public void testDefaultEncoding() {
Charset.defaultCharset();
assertEquals(Encoding.defaultEncoding().name(), Charset.defaultCharset().name());
}
}

View File

@ -129,7 +129,8 @@ import org.junit.runners.Suite;
CopyTest.class,
CopyLargeFileTest.class,
UpsertTest.class,
OuterJoinSyntaxTest.class
OuterJoinSyntaxTest.class,
NumericNegScaleTest.class
})
public class Jdbc2TestSuite {
}

View File

@ -0,0 +1,122 @@
package org.postgresql.test.jdbc2;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.postgresql.jdbc.TypeInfoCache.FLOATSCALE;
import static org.postgresql.jdbc.TypeInfoCache.NUMERIC_MAX_DISPLAYSIZE;
public class NumericNegScaleTest extends BaseTest4 {
@Test
public void testFloat() throws Exception {
TestUtil.execute("set behavior_compat_options='float_as_numeric'", con);
TestUtil.createTable(con, "test_float", "col1 float(1), col2 float(23), col3 float(126)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_float VALUES (?,?,?)");
BigDecimal n1 = new BigDecimal("1.8355454812");
pstmt.setObject(1, n1, Types.NUMERIC);
pstmt.setObject(2, n1, Types.NUMERIC);
pstmt.setObject(3, n1, Types.NUMERIC);
pstmt.executeUpdate();
n1 = BigDecimal.valueOf(1234567890);
pstmt.setObject(1, n1, Types.NUMERIC);
pstmt.setObject(2, n1, Types.NUMERIC);
pstmt.setObject(3, n1, Types.NUMERIC);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_float");
int[] precision_arr = {0, 1, 23, 126};
for (int i=1; i<4; i++)
{
assertEquals(rs.getMetaData().getPrecision(i), precision_arr[i]);
assertEquals(rs.getMetaData().getScale(i), FLOATSCALE);
assertEquals(rs.getMetaData().getColumnDisplaySize(i), NUMERIC_MAX_DISPLAYSIZE);
}
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(BigDecimal.valueOf(2), r1);
Object r2 = rs.getObject(2);
assertNotNull(r2);
assertEquals(BigDecimal.valueOf(1.835545), r2);
Object r3 = rs.getObject(3);
assertNotNull(r3);
assertEquals(BigDecimal.valueOf(1.8355454812), r3);
assertTrue(rs.next());
r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(BigDecimal.valueOf(1000000000), r1);
r2 = rs.getObject(2);
assertNotNull(r2);
assertEquals(BigDecimal.valueOf(1234568000), r2);
r3 = rs.getObject(3);
assertNotNull(r3);
assertEquals(BigDecimal.valueOf(1234567890), r3);
rs.close();
TestUtil.execute("set behavior_compat_options=''", con);
TestUtil.dropTable(con, "test_float");
}
@Test
public void testNegScale() throws Exception {
TestUtil.createTable(con, "test_neg_scale", "col1 numeric(4,-3), col2 numeric(3,-4)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_neg_scale VALUES (?,?)");
BigDecimal n1 = new BigDecimal("1.8355454812");
pstmt.setObject(1, n1, Types.NUMERIC);
pstmt.setObject(2, n1, Types.NUMERIC);
pstmt.executeUpdate();
n1 = BigDecimal.valueOf(1234567);
pstmt.setObject(1, n1, Types.NUMERIC);
pstmt.setObject(2, n1, Types.NUMERIC);
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_neg_scale");
int[][] typmod_arr = {{0}, {4, -3}, {3, -4}};
for (int i=1; i<3; i++)
{
assertEquals(rs.getMetaData().getPrecision(i), typmod_arr[i][0]);
assertEquals(rs.getMetaData().getScale(i), typmod_arr[i][1]);
assertEquals(rs.getMetaData().getColumnDisplaySize(i), 8);
}
assertTrue(rs.next());
Object r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(BigDecimal.valueOf(0), r1);
Object r2 = rs.getObject(2);
assertNotNull(r2);
assertEquals(BigDecimal.valueOf(0), r2);
assertTrue(rs.next());
r1 = rs.getObject(1);
assertNotNull(r1);
assertEquals(BigDecimal.valueOf(1235000), r1);
r2 = rs.getObject(2);
assertNotNull(r2);
assertEquals(BigDecimal.valueOf(1230000), r2);
rs.close();
TestUtil.dropTable(con, "test_neg_scale");
}
}

View File

@ -75,7 +75,7 @@ public class OptionTest extends BaseTest4 {
assertEquals(value, s);
// behavior_compat_options_name duplicate option
s = setOptionsAndGet(behaviorCompatOptionsName, "hide_tailing_zero,hide_tailing_zero");
assertEquals("hide_tailing_zero,hide_tailing_zero", s);
assertEquals("hide_tailing_zero", s);
// options applied failed
optionsBehaviorCompatOptionsFailed(behaviorCompatOptionsName, "''");
optionsBehaviorCompatOptionsFailed(behaviorCompatOptionsName, "hide_tailing_zero,,");

View File

@ -153,6 +153,7 @@ public class PGPropertyTest {
excluded.add("enableStatementLoadBalance");
excluded.add("writeDataSourceAddress");
excluded.add("BCmptMode");
excluded.add("bitOutput");
// index PropertyDescriptors by name
Map<String, PropertyDescriptor> propertyDescriptors =

View File

@ -328,8 +328,8 @@ public class PgCallableStatementTest extends BaseTest4 {
String queryStr = "{? = call fn_ty_in_ty_out3(?)}";
cmt = con.prepareCall(queryStr);
{
cmt.registerOutParameter(1, Types.NUMERIC);
cmt.registerOutParameter(2, Types.NUMERIC);
cmt.registerOutParameter(1, Types.DECIMAL);
cmt.registerOutParameter(2, Types.DECIMAL);
}
cmt.execute();
assertEquals(new BigDecimal(0), cmt.getObject(1));

View File

@ -35,9 +35,6 @@ import java.util.UUID;
@RunWith(Parameterized.class)
public class ArrayTest extends BaseTest4 {
private Connection _conn;
public ArrayTest(BinaryMode binaryMode) {
setBinaryMode(binaryMode);
}
@ -54,26 +51,24 @@ public class ArrayTest extends BaseTest4 {
@Override
public void setUp() throws Exception {
super.setUp();
_conn = con;
TestUtil.createTable(_conn, "arrtest",
TestUtil.createTable(con, "arrtest",
"intarr int[], decarr decimal(2,1)[], strarr text[]"
+ (TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v8_3) ? ", uuidarr uuid[]" : "")
+ (TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_3) ? ", uuidarr uuid[]" : "")
+ ", floatarr float8[]"
+ ", intarr2 int4[][]");
TestUtil.createTable(_conn, "arrcompprnttest", "id serial, name character(10)");
TestUtil.createTable(_conn, "arrcompchldttest",
TestUtil.createTable(con, "arrcompprnttest", "id serial, name character(10)");
TestUtil.createTable(con, "arrcompchldttest",
"id serial, name character(10), description character varying, parent integer");
TestUtil.createTable(_conn, "\"correctcasing\"", "id serial");
TestUtil.createTable(_conn, "\"evil.table\"", "id serial");
TestUtil.createTable(con, "\"correctcasing\"", "id serial");
TestUtil.createTable(con, "\"evil.table\"", "id serial");
}
@Override
public void tearDown() throws SQLException {
TestUtil.dropTable(_conn, "arrtest");
TestUtil.dropTable(_conn, "arrcompprnttest");
TestUtil.dropTable(_conn, "arrcompchldttest");
TestUtil.dropTable(_conn, "\"CorrectCasing\"");
TestUtil.dropTable(con, "arrtest");
TestUtil.dropTable(con, "arrcompprnttest");
TestUtil.dropTable(con, "arrcompchldttest");
TestUtil.dropTable(con, "\"CorrectCasing\"");
super.tearDown();
}
@ -81,8 +76,8 @@ public class ArrayTest extends BaseTest4 {
@Ignore
// TODO PG修复了这个
public void testCreateArrayOfBool() throws SQLException {
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::bool[]");
Array list= _conn.createArrayOf("boolean", new Object[]{ true, true, false });
PreparedStatement pstmt = con.prepareStatement("SELECT ?::bool[]");
Array list= con.createArrayOf("boolean", new Object[]{ true, true, false });
pstmt.setArray(1, list);
ResultSet rs = pstmt.executeQuery();
@ -98,12 +93,12 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCreateArrayOfInt() throws SQLException {
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::int[]");
PreparedStatement pstmt = con.prepareStatement("SELECT ?::int[]");
Integer[] in = new Integer[3];
in[0] = 0;
in[1] = -1;
in[2] = 2;
pstmt.setArray(1, _conn.createArrayOf("int4", in));
pstmt.setArray(1, con.createArrayOf("int4", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
@ -118,12 +113,12 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCreateArrayOfSmallInt() throws SQLException {
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::smallint[]");
PreparedStatement pstmt = con.prepareStatement("SELECT ?::smallint[]");
Short[] in = new Short[3];
in[0] = 0;
in[1] = -1;
in[2] = 2;
pstmt.setArray(1, _conn.createArrayOf("int2", in));
pstmt.setArray(1, con.createArrayOf("int2", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
@ -138,13 +133,13 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCreateArrayOfMultiString() throws SQLException {
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::text[]");
PreparedStatement pstmt = con.prepareStatement("SELECT ?::text[]");
String[][] in = new String[2][2];
in[0][0] = "a";
in[0][1] = "";
in[1][0] = "\\";
in[1][1] = "\"\\'z";
pstmt.setArray(1, _conn.createArrayOf("text", in));
pstmt.setArray(1, con.createArrayOf("text", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
@ -161,29 +156,22 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCreateArrayOfMultiJson() throws SQLException {
if (!TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v9_2)) {
if (!TestUtil.haveMinimumServerVersion(con, ServerVersion.v9_2)) {
return;
}
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::json[]");
PGobject p1 = new PGobject();
p1.setType("json");
p1.setValue("{\"x\": 10}");
PGobject p2 = new PGobject();
p2.setType("json");
p2.setValue("{\"x\": 20}");
PGobject[] in = new PGobject[] { p1, p2 };
pstmt.setArray(1, _conn.createArrayOf("json", in));
PreparedStatement pstmt = con.prepareStatement("SELECT ?::json[]");
String[] in = new String[]{"{\"x\": 10}", "{\"x\": 20}"};
pstmt.setArray(1, con.createArrayOf("json", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
ResultSet arrRs = arr.getResultSet();
Assert.assertTrue(arrRs.next());
Assert.assertEquals(in[0], arrRs.getObject(2));
Assert.assertEquals(in[0], arrRs.getString(2));
Assert.assertTrue(arrRs.next());
Assert.assertEquals(in[1], arrRs.getObject(2));
Assert.assertEquals(in[1], arrRs.getString(2));
}
@Test
@ -192,8 +180,8 @@ public class ArrayTest extends BaseTest4 {
in[0] = new PGbox(1, 2, 3, 4);
in[1] = new PGbox(5, 6, 7, 8);
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::box[]");
pstmt.setArray(1, _conn.createArrayOf("box", in));
PreparedStatement pstmt = con.prepareStatement("SELECT ?::box[]");
pstmt.setArray(1, con.createArrayOf("box", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
@ -213,11 +201,11 @@ public class ArrayTest extends BaseTest4 {
sql = "SELECT ?::int8[]";
}
PreparedStatement pstmt = _conn.prepareStatement(sql);
PreparedStatement pstmt = con.prepareStatement(sql);
String[] in = new String[2];
in[0] = null;
in[1] = null;
pstmt.setArray(1, _conn.createArrayOf("int8", in));
pstmt.setArray(1, con.createArrayOf("int8", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
@ -231,9 +219,9 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCreateEmptyArrayOfIntViaAlias() throws SQLException {
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::int[]");
PreparedStatement pstmt = con.prepareStatement("SELECT ?::int[]");
Integer[] in = new Integer[0];
pstmt.setArray(1, _conn.createArrayOf("integer", in));
pstmt.setArray(1, con.createArrayOf("integer", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
@ -254,7 +242,7 @@ public class ArrayTest extends BaseTest4 {
in[1][0] = "\\";
in[1][1] = "\"\\'z";
Array arr = _conn.createArrayOf("varchar", in);
Array arr = con.createArrayOf("varchar", in);
String[][] out = (String[][]) arr.getArray();
Assert.assertEquals(2, out.length);
@ -273,7 +261,7 @@ public class ArrayTest extends BaseTest4 {
in[1][0] = 10.0 / 3;
in[1][1] = 77;
Array arr = _conn.createArrayOf("float8", in);
Array arr = con.createArrayOf("float8", in);
Double[][] out = (Double[][]) arr.getArray();
Assert.assertEquals(2, out.length);
@ -289,19 +277,19 @@ public class ArrayTest extends BaseTest4 {
Assume.assumeTrue("UUID is not supported in PreferQueryMode.SIMPLE",
preferQueryMode != PreferQueryMode.SIMPLE);
Assume.assumeTrue("UUID requires PostgreSQL 8.3+",
TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v8_3));
TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_3));
UUID uuid1 = UUID.randomUUID();
UUID uuid2 = UUID.randomUUID();
UUID uuid3 = UUID.randomUUID();
// insert a uuid array, and check
PreparedStatement pstmt1 = _conn.prepareStatement("INSERT INTO arrtest(uuidarr) VALUES (?)");
pstmt1.setArray(1, _conn.createArrayOf("uuid", new UUID[]{uuid1, uuid2, uuid3}));
PreparedStatement pstmt1 = con.prepareStatement("INSERT INTO arrtest(uuidarr) VALUES (?)");
pstmt1.setArray(1, con.createArrayOf("uuid", new UUID[]{uuid1, uuid2, uuid3}));
pstmt1.executeUpdate();
PreparedStatement pstmt2 =
_conn.prepareStatement("SELECT uuidarr FROM arrtest WHERE uuidarr @> ?");
pstmt2.setObject(1, _conn.createArrayOf("uuid", new UUID[]{uuid1}), Types.OTHER);
con.prepareStatement("SELECT uuidarr FROM arrtest WHERE uuidarr @> ?");
pstmt2.setObject(1, con.createArrayOf("uuid", new UUID[]{uuid1}), Types.OTHER);
ResultSet rs = pstmt2.executeQuery();
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
@ -315,13 +303,13 @@ public class ArrayTest extends BaseTest4 {
// concatenate a uuid, and check
UUID uuid4 = UUID.randomUUID();
PreparedStatement pstmt3 =
_conn.prepareStatement("UPDATE arrtest SET uuidarr = uuidarr || ? WHERE uuidarr @> ?");
con.prepareStatement("UPDATE arrtest SET uuidarr = uuidarr || ? WHERE uuidarr @> ?");
pstmt3.setObject(1, uuid4, Types.OTHER);
pstmt3.setArray(2, _conn.createArrayOf("uuid", new UUID[]{uuid1}));
pstmt3.setArray(2, con.createArrayOf("uuid", new UUID[]{uuid1}));
pstmt3.executeUpdate();
// --
pstmt2.setObject(1, _conn.createArrayOf("uuid", new UUID[]{uuid4}), Types.OTHER);
pstmt2.setObject(1, con.createArrayOf("uuid", new UUID[]{uuid4}), Types.OTHER);
rs = pstmt2.executeQuery();
Assert.assertTrue(rs.next());
arr = rs.getArray(1);
@ -339,7 +327,7 @@ public class ArrayTest extends BaseTest4 {
String[] strArray = new String[]{"a", "b", "c"};
Object[] objCopy = Arrays.copyOf(strArray, strArray.length, Object[].class);
PreparedStatement pstmt = _conn.prepareStatement("INSERT INTO arrtest(strarr) VALUES (?)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO arrtest(strarr) VALUES (?)");
//cannot handle generic Object[]
try {
@ -366,7 +354,7 @@ public class ArrayTest extends BaseTest4 {
// Correct way, though the use of "text" as a type is non-portable.
// Only supported for JDK 1.6 and JDBC4
Array sqlArray = _conn.createArrayOf("text", strArray);
Array sqlArray = con.createArrayOf("text", strArray);
pstmt.setArray(1, sqlArray);
pstmt.executeUpdate();
@ -376,10 +364,10 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testGetArrayOfComposites() throws SQLException {
Assume.assumeTrue("array_agg(expression) requires PostgreSQL 8.4+",
TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v8_4));
TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_4));
PreparedStatement insert_parent_pstmt =
_conn.prepareStatement("INSERT INTO arrcompprnttest (name) "
con.prepareStatement("INSERT INTO arrcompprnttest (name) "
+ "VALUES ('aParent');");
insert_parent_pstmt.execute();
@ -390,7 +378,7 @@ public class ArrayTest extends BaseTest4 {
"5\",3\""};
PreparedStatement insert_children_pstmt =
_conn.prepareStatement("INSERT INTO arrcompchldttest (name,description,parent) "
con.prepareStatement("INSERT INTO arrcompchldttest (name,description,parent) "
+ "VALUES ('child1',?,1),"
+ "('child2',?,1),"
+ "('child3',?,1),"
@ -403,7 +391,7 @@ public class ArrayTest extends BaseTest4 {
insert_children_pstmt.execute();
PreparedStatement pstmt = _conn.prepareStatement(
PreparedStatement pstmt = con.prepareStatement(
"SELECT arrcompprnttest.name, "
+ "array_agg("
+ "DISTINCT(arrcompchldttest.id, "
@ -444,7 +432,7 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCasingComposite() throws SQLException {
Assume.assumeTrue("Arrays of composite types requires PostgreSQL 8.3+",
TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v8_3));
TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_3));
PGobject cc = new PGobject();
cc.setType("correctcasing");
@ -452,8 +440,8 @@ public class ArrayTest extends BaseTest4 {
Object[] in = new Object[1];
in[0] = cc;
Array arr = _conn.createArrayOf("correctcasing", in);
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::correctcasing[]");
Array arr = con.createArrayOf("correctcasing", in);
PreparedStatement pstmt = con.prepareStatement("SELECT ?::correctcasing[]");
pstmt.setArray(1, arr);
ResultSet rs = pstmt.executeQuery();
@ -467,8 +455,8 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCasingBuiltinAlias() throws SQLException {
Array arr = _conn.createArrayOf("INT", new Integer[]{1, 2, 3});
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::INT[]");
Array arr = con.createArrayOf("INT", new Integer[]{1, 2, 3});
PreparedStatement pstmt = con.prepareStatement("SELECT ?::INT[]");
pstmt.setArray(1, arr);
ResultSet rs = pstmt.executeQuery();
@ -480,8 +468,8 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testCasingBuiltinNonAlias() throws SQLException {
Array arr = _conn.createArrayOf("int4", new Integer[]{1, 2, 3});
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::int4[]");
Array arr = con.createArrayOf("int4", new Integer[]{1, 2, 3});
PreparedStatement pstmt = con.prepareStatement("SELECT ?::int4[]");
pstmt.setArray(1, arr);
ResultSet rs = pstmt.executeQuery();
@ -494,7 +482,7 @@ public class ArrayTest extends BaseTest4 {
@Test
public void testEvilCasing() throws SQLException {
Assume.assumeTrue("Arrays of composite types requires PostgreSQL 8.3+",
TestUtil.haveMinimumServerVersion(_conn, ServerVersion.v8_3));
TestUtil.haveMinimumServerVersion(con, ServerVersion.v8_3));
PGobject cc = new PGobject();
cc.setType("\"evil.table\"");
@ -502,8 +490,8 @@ public class ArrayTest extends BaseTest4 {
Object[] in = new Object[1];
in[0] = cc;
Array arr = _conn.createArrayOf("\"evil.table\"", in);
PreparedStatement pstmt = _conn.prepareStatement("SELECT ?::\"evil.table\"[]");
Array arr = con.createArrayOf("\"evil.table\"", in);
PreparedStatement pstmt = con.prepareStatement("SELECT ?::\"evil.table\"[]");
pstmt.setArray(1, arr);
ResultSet rs = pstmt.executeQuery();
@ -599,4 +587,41 @@ public class ArrayTest extends BaseTest4 {
TestUtil.closeQuietly(rs);
TestUtil.closeQuietly(ps);
}
@Test
public void testBooleanArray() throws SQLException {
PreparedStatement pstmt = con.prepareStatement("select array_replace(?,'true','f');");
Boolean[][] in = new Boolean[][]{{false,false,false}, {true,true,true}};
pstmt.setArray(1, con.createArrayOf("boolean", in));
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Boolean[][] out = (Boolean[][]) arr.getArray();
Assert.assertEquals(2, out.length);
Assert.assertEquals(3, out[0].length);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
Assert.assertFalse(out[i][j]);
}
}
}
@Test
public void testBooleanArray2() throws SQLException {
PreparedStatement pstmt = con.prepareStatement("select array_replace(array[[false,FALSE,false],[false,TRUE,false]],'false','t');");
ResultSet rs = pstmt.executeQuery();
Assert.assertTrue(rs.next());
Array arr = rs.getArray(1);
Boolean[][] out = (Boolean[][]) arr.getArray();
Assert.assertEquals(2, out.length);
Assert.assertEquals(3, out[0].length);
for (int i = 0; i < 2; i++) {
for (int j = 0; j < 2; j++) {
Assert.assertTrue(out[i][j]);
}
}
}
}

View File

@ -0,0 +1,69 @@
package org.postgresql.test.jdbc4;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
public class BitTest extends BaseTest4 {
/*
* Tests bit type
*/
@Test
public void testBit() throws Exception {
TestUtil.createTable(con, "test_bit", "c1 bit(1),c2 bit(10),c3 bit(6)");
PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_bit VALUES (0::bit(1), 1234::bit(10), 88::bit(6))");
pstmt.executeUpdate();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT c1,c2,c3 FROM test_bit");
assertTrue(rs.next());
Object o1 = rs.getObject(1);
assertNotNull(o1);
assertEquals(false, o1);
Object o2 = rs.getObject(2);
assertNotNull(o2);
assertEquals(true, o2);
Object o3 = rs.getObject(3);
assertNotNull(o3);
assertEquals(true, o3);
TestUtil.dropTable(con, "test_bit");
}
/*
* Tests bit by getBytes()
*/
@Test
public void testBitToBytes() throws Exception {
TestUtil.createTable(con, "test_bitToBytes", "c1 bit(10),c2 bit(18)");
String sql = "INSERT INTO test_bitToBytes VALUES (123::bit(10), 18437::bit(18))";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.executeUpdate();
}
try (Statement ps = con.createStatement();
ResultSet rs = ps.executeQuery("SELECT c1,c2 FROM test_bitToBytes")) {
assertTrue(rs.next());
String r1 = rs.getString(1);
assertNotNull(r1);
assertEquals("0001111011", r1);
String r2 = rs.getString(2);
assertNotNull(r2);
assertEquals("000100100000000101", r2);
} finally {
TestUtil.dropTable(con, "test_bitToBytes");
}
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.jdbc4;
import org.junit.Test;
import org.postgresql.core.types.PGBlob;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4;
import java.nio.charset.StandardCharsets;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
/**
* test blob
*
* @author zhangting
* @since 2024-08-23
*/
public class BlobTest extends BaseTest4 {
@Test
public void testStringToBlob() throws SQLException {
TestUtil.createTable(con, "test_blob_a", "id int, c1 blob");
try (PreparedStatement pstmt = con.prepareStatement("INSERT INTO test_blob_a VALUES (?,?)")) {
pstmt.setInt(1, 1);
PGBlob blob = new PGBlob();
blob.setBytes(1, "1234".getBytes(StandardCharsets.UTF_8));
pstmt.setBlob(2, blob);
pstmt.execute();
}
String sql = "INSERT INTO test_blob_a VALUES (2,'31323334'::blob)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.execute();
}
try (Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery("SELECT * FROM test_blob_a")) {
while (rs.next()) {
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(Types.BLOB, rsmd.getColumnType(2));
assertEquals("1234", new String(rs.getBlob(2).getBytes(1, 4),
StandardCharsets.UTF_8));
assertEquals("1234", new String(rs.getBytes(2), StandardCharsets.UTF_8));
}
}
TestUtil.dropTable(con, "test_blob_a");
}
}

View File

@ -0,0 +1,120 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024-2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.jdbc4;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.ResultSet;
import java.util.Properties;
import java.util.stream.IntStream;
import static org.junit.Assert.assertEquals;
/**
* Test case for cleanupSavepoints property
*
* @author zhangting
* @since 2024-09-10
*/
public class CleanUpSavePointsPropertyTest extends BaseTest4 {
@Before
public void setUp() throws Exception {
Properties props = new Properties();
props.put("autosave", "always");
props.put("cleanupSavepoints", "true");
con = TestUtil.openDB(props);
TestUtil.createTable(con, "savepoint_table", "id int primary key, name varchar(16)");
con.setAutoCommit(false);
}
@After
public void tearDown() throws SQLException {
con.setAutoCommit(true);
TestUtil.dropTable(con, "savepoint_table");
super.tearDown();
}
@Test
public void test() throws SQLException {
// add record
IntStream.range(1, 6).forEach(i -> {
try {
addRecord(i, "xw" + i);
} catch (SQLException ex) {
ex.printStackTrace();
}
});
// update record
IntStream.range(1, 3).forEach(i -> {
try {
updateRecord(i, "name" + i + "-" + i);
} catch (SQLException e) {
e.printStackTrace();
}
});
// delete record
IntStream.range(4, 6).forEach(i -> {
try {
deleteRecord(i);
} catch (SQLException e) {
e.printStackTrace();
}
});
// count record
assertEquals(3, countRecord());
}
private void addRecord(int id, String name) throws SQLException {
String sql = "INSERT INTO savepoint_table(id, name) VALUES (?, ?)";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setInt(1, id);
pstmt.setString(2, name);
pstmt.executeUpdate();
}
}
private void updateRecord(int id, String name) throws SQLException {
String sql = "update savepoint_table set name= ? where id= ?";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setString(1, name);
pstmt.setInt(2, id);
pstmt.executeUpdate();
}
}
private void deleteRecord(int id) throws SQLException {
String sql = "delete from savepoint_table where id= ?";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.setInt(1, id);
pstmt.executeUpdate();
}
}
private int countRecord() throws SQLException {
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT COUNT(*) FROM savepoint_table")) {
rs.next();
return rs.getInt(1);
}
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
package org.postgresql.test.jdbc4;
import org.junit.Test;
import org.postgresql.test.TestUtil;
import org.postgresql.test.jdbc2.BaseTest4;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
/**
* test json
*
* @author zhangting
* @since 2024-08-20
*/
public class JsonTest extends BaseTest4 {
/*
* test json to string
*/
@Test
public void testJsonToString() throws Exception {
TestUtil.createTable(con, "test_json", "id json");
String sql = "INSERT INTO test_json VALUES ('{\"k1\":\"v1\",\"k2\":\"v2\"}')";
try (PreparedStatement pstmt = con.prepareStatement(sql)) {
pstmt.executeUpdate();
}
try (Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM test_json")) {
assertTrue(rs.next());
ResultSetMetaData rsmd = rs.getMetaData();
assertEquals(1, rsmd.getColumnCount());
assertEquals(Types.VARCHAR, rsmd.getColumnType(1));
assertEquals("{\"k1\":\"v1\",\"k2\":\"v2\"}", rs.getString(1));
}
TestUtil.dropTable(con, "test_json");
}
}