activerecord-jdbc-alt-adapter 50.3.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +100 -0
- data/.yardopts +4 -0
- data/CONTRIBUTING.md +50 -0
- data/Gemfile +92 -0
- data/History.md +1191 -0
- data/LICENSE.txt +26 -0
- data/README.md +240 -0
- data/RUNNING_TESTS.md +127 -0
- data/Rakefile +336 -0
- data/Rakefile.jdbc +20 -0
- data/activerecord-jdbc-adapter.gemspec +55 -0
- data/activerecord-jdbc-alt-adapter.gemspec +56 -0
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
- data/lib/activerecord-jdbc-adapter.rb +1 -0
- data/lib/arel/visitors/compat.rb +60 -0
- data/lib/arel/visitors/db2.rb +137 -0
- data/lib/arel/visitors/derby.rb +112 -0
- data/lib/arel/visitors/firebird.rb +79 -0
- data/lib/arel/visitors/h2.rb +25 -0
- data/lib/arel/visitors/hsqldb.rb +32 -0
- data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
- data/lib/arel/visitors/sql_server.rb +225 -0
- data/lib/arel/visitors/sql_server/ng42.rb +294 -0
- data/lib/arel/visitors/sqlserver.rb +214 -0
- data/lib/arjdbc.rb +19 -0
- data/lib/arjdbc/abstract/connection_management.rb +35 -0
- data/lib/arjdbc/abstract/core.rb +74 -0
- data/lib/arjdbc/abstract/database_statements.rb +64 -0
- data/lib/arjdbc/abstract/statement_cache.rb +58 -0
- data/lib/arjdbc/abstract/transaction_support.rb +86 -0
- data/lib/arjdbc/db2.rb +4 -0
- data/lib/arjdbc/db2/adapter.rb +789 -0
- data/lib/arjdbc/db2/as400.rb +130 -0
- data/lib/arjdbc/db2/column.rb +167 -0
- data/lib/arjdbc/db2/connection_methods.rb +44 -0
- data/lib/arjdbc/derby.rb +3 -0
- data/lib/arjdbc/derby/active_record_patch.rb +13 -0
- data/lib/arjdbc/derby/adapter.rb +540 -0
- data/lib/arjdbc/derby/connection_methods.rb +20 -0
- data/lib/arjdbc/derby/schema_creation.rb +15 -0
- data/lib/arjdbc/discover.rb +104 -0
- data/lib/arjdbc/firebird.rb +4 -0
- data/lib/arjdbc/firebird/adapter.rb +434 -0
- data/lib/arjdbc/firebird/connection_methods.rb +23 -0
- data/lib/arjdbc/h2.rb +3 -0
- data/lib/arjdbc/h2/adapter.rb +303 -0
- data/lib/arjdbc/h2/connection_methods.rb +27 -0
- data/lib/arjdbc/hsqldb.rb +3 -0
- data/lib/arjdbc/hsqldb/adapter.rb +297 -0
- data/lib/arjdbc/hsqldb/connection_methods.rb +28 -0
- data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
- data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
- data/lib/arjdbc/informix.rb +5 -0
- data/lib/arjdbc/informix/adapter.rb +162 -0
- data/lib/arjdbc/informix/connection_methods.rb +9 -0
- data/lib/arjdbc/jdbc.rb +59 -0
- data/lib/arjdbc/jdbc/adapter.rb +475 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/base_ext.rb +15 -0
- data/lib/arjdbc/jdbc/callbacks.rb +53 -0
- data/lib/arjdbc/jdbc/column.rb +97 -0
- data/lib/arjdbc/jdbc/connection.rb +14 -0
- data/lib/arjdbc/jdbc/connection_methods.rb +37 -0
- data/lib/arjdbc/jdbc/error.rb +65 -0
- data/lib/arjdbc/jdbc/extension.rb +59 -0
- data/lib/arjdbc/jdbc/java.rb +13 -0
- data/lib/arjdbc/jdbc/railtie.rb +2 -0
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -0
- data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
- data/lib/arjdbc/jdbc/type_cast.rb +166 -0
- data/lib/arjdbc/jdbc/type_converter.rb +142 -0
- data/lib/arjdbc/mssql.rb +7 -0
- data/lib/arjdbc/mssql/adapter.rb +384 -0
- data/lib/arjdbc/mssql/column.rb +29 -0
- data/lib/arjdbc/mssql/connection_methods.rb +79 -0
- data/lib/arjdbc/mssql/database_statements.rb +134 -0
- data/lib/arjdbc/mssql/errors.rb +6 -0
- data/lib/arjdbc/mssql/explain_support.rb +129 -0
- data/lib/arjdbc/mssql/extensions.rb +36 -0
- data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
- data/lib/arjdbc/mssql/lock_methods.rb +77 -0
- data/lib/arjdbc/mssql/old_adapter.rb +804 -0
- data/lib/arjdbc/mssql/old_column.rb +200 -0
- data/lib/arjdbc/mssql/quoting.rb +101 -0
- data/lib/arjdbc/mssql/schema_creation.rb +31 -0
- data/lib/arjdbc/mssql/schema_definitions.rb +74 -0
- data/lib/arjdbc/mssql/schema_statements.rb +329 -0
- data/lib/arjdbc/mssql/transaction.rb +69 -0
- data/lib/arjdbc/mssql/types.rb +52 -0
- data/lib/arjdbc/mssql/types/binary_types.rb +33 -0
- data/lib/arjdbc/mssql/types/date_and_time_types.rb +134 -0
- data/lib/arjdbc/mssql/types/deprecated_types.rb +40 -0
- data/lib/arjdbc/mssql/types/numeric_types.rb +71 -0
- data/lib/arjdbc/mssql/types/string_types.rb +56 -0
- data/lib/arjdbc/mssql/utils.rb +66 -0
- data/lib/arjdbc/mysql.rb +3 -0
- data/lib/arjdbc/mysql/adapter.rb +140 -0
- data/lib/arjdbc/mysql/connection_methods.rb +166 -0
- data/lib/arjdbc/oracle/adapter.rb +863 -0
- data/lib/arjdbc/postgresql.rb +3 -0
- data/lib/arjdbc/postgresql/adapter.rb +687 -0
- data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
- data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
- data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
- data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
- data/lib/arjdbc/postgresql/column.rb +51 -0
- data/lib/arjdbc/postgresql/connection_methods.rb +67 -0
- data/lib/arjdbc/postgresql/name.rb +24 -0
- data/lib/arjdbc/postgresql/oid_types.rb +266 -0
- data/lib/arjdbc/railtie.rb +11 -0
- data/lib/arjdbc/sqlite3.rb +3 -0
- data/lib/arjdbc/sqlite3/adapter.rb +678 -0
- data/lib/arjdbc/sqlite3/connection_methods.rb +59 -0
- data/lib/arjdbc/sybase.rb +2 -0
- data/lib/arjdbc/sybase/adapter.rb +47 -0
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/databases.rake +48 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
- data/lib/arjdbc/util/quoted_cache.rb +60 -0
- data/lib/arjdbc/util/serialized_attributes.rb +98 -0
- data/lib/arjdbc/util/table_copier.rb +110 -0
- data/lib/arjdbc/version.rb +3 -0
- data/lib/generators/jdbc/USAGE +9 -0
- data/lib/generators/jdbc/jdbc_generator.rb +17 -0
- data/lib/jdbc_adapter.rb +2 -0
- data/lib/jdbc_adapter/rake_tasks.rb +4 -0
- data/lib/jdbc_adapter/version.rb +4 -0
- data/pom.xml +114 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
- data/rakelib/01-tomcat.rake +51 -0
- data/rakelib/02-test.rake +132 -0
- data/rakelib/bundler_ext.rb +11 -0
- data/rakelib/db.rake +75 -0
- data/rakelib/rails.rake +223 -0
- data/src/java/arjdbc/ArJdbcModule.java +276 -0
- data/src/java/arjdbc/db2/DB2Module.java +76 -0
- data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
- data/src/java/arjdbc/derby/DerbyModule.java +178 -0
- data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
- data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
- data/src/java/arjdbc/h2/H2Module.java +50 -0
- data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +85 -0
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
- data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +75 -0
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
- data/src/java/arjdbc/jdbc/Callable.java +44 -0
- data/src/java/arjdbc/jdbc/ConnectionFactory.java +45 -0
- data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
- data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
- data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
- data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
- data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +61 -0
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3979 -0
- data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
- data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +508 -0
- data/src/java/arjdbc/mysql/MySQLModule.java +152 -0
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
- data/src/java/arjdbc/oracle/OracleModule.java +80 -0
- data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +455 -0
- data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
- data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +52 -0
- data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
- data/src/java/arjdbc/postgresql/PostgreSQLResult.java +192 -0
- data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +948 -0
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
- data/src/java/arjdbc/util/CallResultSet.java +826 -0
- data/src/java/arjdbc/util/DateTimeUtils.java +699 -0
- data/src/java/arjdbc/util/ObjectSupport.java +65 -0
- data/src/java/arjdbc/util/QuotingUtils.java +137 -0
- data/src/java/arjdbc/util/StringCache.java +63 -0
- data/src/java/arjdbc/util/StringHelper.java +145 -0
- metadata +269 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright 2015 Karol Bucek
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
package arjdbc.postgresql;
|
|
25
|
+
|
|
26
|
+
import org.jruby.util.ByteList;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Based on JDBC PostgreSQL driver's <code>org.postgresql.util.PGbytea</code>.
|
|
30
|
+
*
|
|
31
|
+
* @author kares
|
|
32
|
+
*/
|
|
33
|
+
abstract class ByteaUtils {
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Converts a PG bytea raw value (i.e. the raw binary representation
|
|
37
|
+
* of the bytea data type) into a java byte[]
|
|
38
|
+
*/
|
|
39
|
+
static ByteList toBytes(final byte[] s, final int off, final int len) {
|
|
40
|
+
// Starting with PG 9.0, a new hex format is supported
|
|
41
|
+
// that starts with "\x". Figure out which format we're
|
|
42
|
+
// dealing with here.
|
|
43
|
+
//
|
|
44
|
+
if ( s.length < 2 || s[0] != '\\' || s[1] != 'x' ) {
|
|
45
|
+
return toBytesOctalEscaped(s, off, len);
|
|
46
|
+
}
|
|
47
|
+
return new ByteList(toBytesHexEscaped(s, off, len), false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private static byte[] toBytesHexEscaped(final byte[] s, final int off, final int len) {
|
|
51
|
+
final byte[] out = new byte[(len - 2) / 2];
|
|
52
|
+
for (int i = 0; i < out.length; i++) {
|
|
53
|
+
final int j = off + (2 + i * 2);
|
|
54
|
+
byte b1 = hexByte( s[j] );
|
|
55
|
+
byte b2 = hexByte( s[j + 1] );
|
|
56
|
+
// squid:S3034
|
|
57
|
+
// Raw byte values should not be used in bitwise operations in combination with shifts
|
|
58
|
+
out[i] = (byte) ((b1 << 4) | (b2 & 0xff));
|
|
59
|
+
}
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private static byte hexByte(final byte b) {
|
|
64
|
+
// 0-9 == 48-57
|
|
65
|
+
if (b <= 57) return (byte) (b - 48);
|
|
66
|
+
|
|
67
|
+
// a-f == 97-102
|
|
68
|
+
if (b >= 97) return (byte) (b - 97 + 10);
|
|
69
|
+
|
|
70
|
+
// A-F == 65-70
|
|
71
|
+
return (byte) (b - 65 + 10);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private static final int MAX_3_BUFF_SIZE = 2 * 1024 * 1024;
|
|
75
|
+
|
|
76
|
+
private static ByteList toBytesOctalEscaped(final byte[] s, final int off, final int len) {
|
|
77
|
+
final byte[] out;
|
|
78
|
+
final int end = off + len;
|
|
79
|
+
int correctSize = len;
|
|
80
|
+
if ( len > MAX_3_BUFF_SIZE ) {
|
|
81
|
+
// count backslash escapes, they will be either
|
|
82
|
+
// backslashes or an octal escape \\ or \003
|
|
83
|
+
//
|
|
84
|
+
for ( int i = off; i < end; ++i ) {
|
|
85
|
+
if ( s[i] == (byte) '\\' ) {
|
|
86
|
+
if (s[ ++i ] == (byte) '\\') {
|
|
87
|
+
--correctSize;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
correctSize -= 3;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
out = new byte[correctSize];
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
out = new byte[len];
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
int pos = 0;
|
|
101
|
+
for ( int i = off; i < end; i++ ) {
|
|
102
|
+
final byte b = s[i];
|
|
103
|
+
if ( b == (byte) '\\' ) {
|
|
104
|
+
final byte b1 = s[++i];
|
|
105
|
+
if ( b1 == (byte) '\\' ) { // escaped \
|
|
106
|
+
out[ pos++ ] = (byte) '\\';
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
int thebyte = (b1 - 48) * 64 + (s[++i] - 48) * 8 + (s[++i] - 48);
|
|
110
|
+
if ( thebyte > 127 ) thebyte -= 256;
|
|
111
|
+
out[ pos++ ] = (byte) thebyte;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
out[ pos++ ] = b;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return new ByteList(out, 0, pos, false);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/*
|
|
123
|
+
* Converts a java byte[] into a PG bytea string (i.e. the text
|
|
124
|
+
* representation of the bytea data type)
|
|
125
|
+
*/
|
|
126
|
+
static ByteList toStr(final byte[] p_buf, final int off, final int len) {
|
|
127
|
+
ByteList l_strbuf = new ByteList(2 * p_buf.length);
|
|
128
|
+
for (int i = off; i < off + len; i++) {
|
|
129
|
+
int l_int = (int)p_buf[i];
|
|
130
|
+
if (l_int < 0) {
|
|
131
|
+
l_int = 256 + l_int;
|
|
132
|
+
}
|
|
133
|
+
//we escape the same non-printable characters as the backend
|
|
134
|
+
//we must escape all 8bit characters otherwise when convering
|
|
135
|
+
//from java unicode to the db character set we may end up with
|
|
136
|
+
//question marks if the character set is SQL_ASCII
|
|
137
|
+
if (l_int < 040 || l_int > 0176) {
|
|
138
|
+
//escape character with the form \000
|
|
139
|
+
l_strbuf.append((byte)'\\');
|
|
140
|
+
l_strbuf.append((((l_int >> 6) & 0x3) + 48));
|
|
141
|
+
l_strbuf.append((((l_int >> 3) & 0x7) + 48));
|
|
142
|
+
l_strbuf.append(((l_int & 0x07) + 48));
|
|
143
|
+
}
|
|
144
|
+
else if (p_buf[i] == (byte)'\\') {
|
|
145
|
+
//escape the backslash character as \\, but need four \\\\ because
|
|
146
|
+
//of the Java parser
|
|
147
|
+
l_strbuf.append((byte)'\\').append((byte)'\\');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
//other characters are left alone
|
|
151
|
+
l_strbuf.append(p_buf[i]);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return l_strbuf;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
package arjdbc.postgresql;
|
|
2
|
+
|
|
3
|
+
import arjdbc.util.DateTimeUtils;
|
|
4
|
+
import org.joda.time.DateTimeZone;
|
|
5
|
+
import org.jruby.RubyArray;
|
|
6
|
+
import org.jruby.RubyFloat;
|
|
7
|
+
import org.jruby.runtime.ThreadContext;
|
|
8
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* PostgreSQL specific DateTime/Timestamp helpers
|
|
12
|
+
* @author dritz
|
|
13
|
+
*/
|
|
14
|
+
public abstract class PgDateTimeUtils extends DateTimeUtils {
|
|
15
|
+
/**
|
|
16
|
+
* Convert a ruby value to a PostgreSQL timestamp string
|
|
17
|
+
* @param context
|
|
18
|
+
* @param value Ruby value, typically a Time instance
|
|
19
|
+
* @param zone DateTimeZone to adjust to, optional
|
|
20
|
+
* @param withZone include timezone in string?
|
|
21
|
+
* @return A string fit for PostgreSQL
|
|
22
|
+
*/
|
|
23
|
+
public static String timestampValueToString(final ThreadContext context, IRubyObject value, DateTimeZone zone,
|
|
24
|
+
boolean withZone) {
|
|
25
|
+
if (value instanceof RubyFloat) {
|
|
26
|
+
final double dv = ((RubyFloat) value).getValue();
|
|
27
|
+
if (dv == Double.POSITIVE_INFINITY) {
|
|
28
|
+
return "infinity";
|
|
29
|
+
} else if (dv == Double.NEGATIVE_INFINITY) {
|
|
30
|
+
return "-infinity";
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return timestampTimeToString(context, value, zone, withZone);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Converts a RubyArray with timestamp values to a java array of PostgreSQL timestamp strings
|
|
38
|
+
* @param context
|
|
39
|
+
* @param rubyArray
|
|
40
|
+
* @return Array of timestamp strings
|
|
41
|
+
*/
|
|
42
|
+
public static String[] timestampStringArray(final ThreadContext context, final RubyArray rubyArray) {
|
|
43
|
+
int size = rubyArray.size();
|
|
44
|
+
String[] values = new String[size];
|
|
45
|
+
|
|
46
|
+
for (int i = 0; i < size; i++) {
|
|
47
|
+
IRubyObject elem = rubyArray.eltInternal(i);
|
|
48
|
+
values[i] = timestampValueToString(context, elem, DateTimeZone.UTC, false);
|
|
49
|
+
}
|
|
50
|
+
return values;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright 2014 Karol Bucek.
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
* THE SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
package arjdbc.postgresql;
|
|
25
|
+
|
|
26
|
+
import static arjdbc.util.QuotingUtils.quoteCharAndDecorateWith;
|
|
27
|
+
import static arjdbc.util.QuotingUtils.quoteCharWith;
|
|
28
|
+
|
|
29
|
+
import org.jruby.Ruby;
|
|
30
|
+
import org.jruby.RubyModule;
|
|
31
|
+
import org.jruby.RubyString;
|
|
32
|
+
import org.jruby.anno.JRubyMethod;
|
|
33
|
+
import org.jruby.runtime.ThreadContext;
|
|
34
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
35
|
+
import org.jruby.util.ByteList;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* ArJdbc::PostgreSQL
|
|
39
|
+
*
|
|
40
|
+
* @author kares
|
|
41
|
+
*/
|
|
42
|
+
public class PostgreSQLModule {
|
|
43
|
+
|
|
44
|
+
public static RubyModule load(final RubyModule arJdbc) {
|
|
45
|
+
RubyModule postgreSQL = arJdbc.defineModuleUnder("PostgreSQL");
|
|
46
|
+
postgreSQL.defineAnnotatedMethods( PostgreSQLModule.class );
|
|
47
|
+
return postgreSQL;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public static RubyModule load(final Ruby runtime) {
|
|
51
|
+
return load( arjdbc.ArJdbcModule.get(runtime) );
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@JRubyMethod(name = "quote_column_name", required = 1)
|
|
55
|
+
public static IRubyObject quote_column_name(
|
|
56
|
+
final ThreadContext context,
|
|
57
|
+
final IRubyObject self,
|
|
58
|
+
final IRubyObject string) { // %("#{name.to_s.gsub("\"", "\"\"")}")
|
|
59
|
+
return quoteCharAndDecorateWith(context, string.asString(), '"', '"', (byte) '"', (byte) '"');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@JRubyMethod(name = "quote_string", required = 1)
|
|
63
|
+
public static IRubyObject quote_string(
|
|
64
|
+
final ThreadContext context,
|
|
65
|
+
final IRubyObject self,
|
|
66
|
+
final IRubyObject string) {
|
|
67
|
+
// NOTE: since AR 5.0 standard_conforming_strings are always set - no need for extra quoting
|
|
68
|
+
return quoteCharWith(context, string.asString(), '\'', '\''); // string.gsub("'", "''")
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@JRubyMethod(name = "unescape_bytea", meta = true)
|
|
72
|
+
public static RubyString unescape_bytea(final ThreadContext context, final IRubyObject self, final IRubyObject escaped) {
|
|
73
|
+
final ByteList bytes = ((RubyString) escaped).getByteList();
|
|
74
|
+
return RubyString.newString(context.runtime, ByteaUtils.toBytes(bytes.unsafeBytes(), bytes.getBegin(), bytes.getRealSize()));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
package arjdbc.postgresql;
|
|
2
|
+
|
|
3
|
+
import arjdbc.jdbc.JdbcResult;
|
|
4
|
+
import arjdbc.jdbc.RubyJdbcConnection;
|
|
5
|
+
|
|
6
|
+
import java.sql.ResultSet;
|
|
7
|
+
import java.sql.ResultSetMetaData;
|
|
8
|
+
import java.sql.SQLException;
|
|
9
|
+
import java.sql.Types;
|
|
10
|
+
|
|
11
|
+
import org.jruby.Ruby;
|
|
12
|
+
import org.jruby.RubyArray;
|
|
13
|
+
import org.jruby.RubyClass;
|
|
14
|
+
import org.jruby.RubyHash;
|
|
15
|
+
import org.jruby.RubyModule;
|
|
16
|
+
import org.jruby.RubyString;
|
|
17
|
+
import org.jruby.anno.JRubyMethod;
|
|
18
|
+
import org.jruby.runtime.Block;
|
|
19
|
+
import org.jruby.runtime.Helpers;
|
|
20
|
+
import org.jruby.runtime.ObjectAllocator;
|
|
21
|
+
import org.jruby.runtime.ThreadContext;
|
|
22
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
* This class mimics the PG:Result class enough to get by
|
|
26
|
+
*/
|
|
27
|
+
public class PostgreSQLResult extends JdbcResult {
|
|
28
|
+
|
|
29
|
+
// These are needed when generating an AR::Result
|
|
30
|
+
private final ResultSetMetaData resultSetMetaData;
|
|
31
|
+
|
|
32
|
+
/********* JRuby compat methods ***********/
|
|
33
|
+
|
|
34
|
+
static RubyClass createPostgreSQLResultClass(Ruby runtime, RubyClass postgreSQLConnection) {
|
|
35
|
+
RubyClass rubyClass = postgreSQLConnection.defineClassUnder("Result", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
|
|
36
|
+
rubyClass.defineAnnotatedMethods(PostgreSQLResult.class);
|
|
37
|
+
rubyClass.includeModule(runtime.getEnumerable());
|
|
38
|
+
return rubyClass;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Generates a new PostgreSQLResult object for the given result set
|
|
43
|
+
* @param context current thread context
|
|
44
|
+
* @param clazz metaclass for this result object
|
|
45
|
+
* @param resultSet the set of results that should be returned
|
|
46
|
+
* @return an instantiated result object
|
|
47
|
+
* @throws SQLException throws!
|
|
48
|
+
*/
|
|
49
|
+
static PostgreSQLResult newResult(ThreadContext context, RubyClass clazz, PostgreSQLRubyJdbcConnection connection,
|
|
50
|
+
ResultSet resultSet) throws SQLException {
|
|
51
|
+
return new PostgreSQLResult(context, clazz, connection, resultSet);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/********* End JRuby compat methods ***********/
|
|
55
|
+
|
|
56
|
+
private PostgreSQLResult(ThreadContext context, RubyClass clazz, RubyJdbcConnection connection,
|
|
57
|
+
ResultSet resultSet) throws SQLException {
|
|
58
|
+
super(context, clazz, connection, resultSet);
|
|
59
|
+
|
|
60
|
+
resultSetMetaData = resultSet.getMetaData();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generates a type map to be given to the AR::Result object
|
|
65
|
+
* @param context current thread context
|
|
66
|
+
* @return RubyHash RubyString - column name, Type::Value - type object)
|
|
67
|
+
* @throws SQLException if it fails to get the field
|
|
68
|
+
*/
|
|
69
|
+
@Override
|
|
70
|
+
protected IRubyObject columnTypeMap(final ThreadContext context) throws SQLException {
|
|
71
|
+
Ruby runtime = context.runtime;
|
|
72
|
+
RubyHash types = RubyHash.newHash(runtime);
|
|
73
|
+
int columnCount = columnNames.length;
|
|
74
|
+
|
|
75
|
+
IRubyObject adapter = connection.adapter(context);
|
|
76
|
+
for (int i = 0; i < columnCount; i++) {
|
|
77
|
+
int col = i + 1;
|
|
78
|
+
String typeName = resultSetMetaData.getColumnTypeName(col);
|
|
79
|
+
|
|
80
|
+
int mod = 0;
|
|
81
|
+
if ("numeric".equals(typeName)) {
|
|
82
|
+
// this field is only relevant for "numeric" type in AR
|
|
83
|
+
// AR checks (fmod - 4 & 0xffff).zero?
|
|
84
|
+
// pgjdbc:
|
|
85
|
+
// - for typmod == -1, getScale() and getPrecision() return 0
|
|
86
|
+
// - for typmod != -1, getScale() returns "(typmod - 4) & 0xFFFF;"
|
|
87
|
+
mod = resultSetMetaData.getScale(col);
|
|
88
|
+
mod = mod == 0 && resultSetMetaData.getPrecision(col) == 0 ? -1 : mod + 4;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
final RubyString name = columnNames[i];
|
|
92
|
+
final IRubyObject type = Helpers.invoke(context, adapter, "get_oid_type",
|
|
93
|
+
runtime.newString(typeName),
|
|
94
|
+
runtime.newFixnum(mod),
|
|
95
|
+
name);
|
|
96
|
+
|
|
97
|
+
if (!type.isNil()) types.fastASet(name, type);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return types;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* This is to support the Enumerable module.
|
|
105
|
+
* This is needed when setting up the type maps so the Enumerable methods work
|
|
106
|
+
* @param context the thread this is being executed on
|
|
107
|
+
* @param block which may handle each result
|
|
108
|
+
* @return this object or RubyNil
|
|
109
|
+
*/
|
|
110
|
+
@JRubyMethod
|
|
111
|
+
public IRubyObject each(ThreadContext context, Block block) {
|
|
112
|
+
// At this point we don't support calling this without a block
|
|
113
|
+
if (block.isGiven()) {
|
|
114
|
+
if (tuples == null) {
|
|
115
|
+
populateTuples(context);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
for (RubyHash tuple : tuples) {
|
|
119
|
+
block.yield(context, tuple);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return this;
|
|
123
|
+
} else {
|
|
124
|
+
return context.nil;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private RubyClass getBinaryDataClass(final ThreadContext context) {
|
|
129
|
+
return ((RubyModule) context.runtime.getModule("ActiveModel").getConstantAt("Type")).getClass("Binary").getClass("Data");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
private boolean isBinaryType(final int type) {
|
|
133
|
+
return type == Types.BLOB || type == Types.BINARY || type == Types.VARBINARY || type == Types.LONGVARBINARY;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Gives the number of rows to be returned.
|
|
138
|
+
* currently defined so we match existing returned results
|
|
139
|
+
* @param context current thread contect
|
|
140
|
+
* @return <code>Fixnum</code>
|
|
141
|
+
*/
|
|
142
|
+
@JRubyMethod
|
|
143
|
+
public IRubyObject length(final ThreadContext context) {
|
|
144
|
+
return values.length();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Creates an <code>ActiveRecord::Result</code> with the data from this result.
|
|
149
|
+
* Overriding the base method so we can modify binary data columns first to mark them
|
|
150
|
+
* as already unencoded
|
|
151
|
+
* @param context current thread context
|
|
152
|
+
* @return ActiveRecord::Result object with the data from this result set
|
|
153
|
+
* @throws SQLException can be caused by postgres generating its type map
|
|
154
|
+
*/
|
|
155
|
+
@Override @SuppressWarnings("unchecked")
|
|
156
|
+
public IRubyObject toARResult(final ThreadContext context) throws SQLException {
|
|
157
|
+
RubyClass BinaryDataClass = null;
|
|
158
|
+
int rowCount = 0;
|
|
159
|
+
|
|
160
|
+
// This is destructive, but since this is typically the final
|
|
161
|
+
// use of the rows I'm going to leave it this way unless it becomes an issue
|
|
162
|
+
for (int columnIndex = 0; columnIndex < columnTypes.length; columnIndex++) {
|
|
163
|
+
if (isBinaryType(columnTypes[columnIndex])) {
|
|
164
|
+
// Convert the values in this column to ActiveModel::Type::Binary::Data instances
|
|
165
|
+
// so AR knows it has already been unescaped
|
|
166
|
+
if (BinaryDataClass == null) {
|
|
167
|
+
BinaryDataClass = getBinaryDataClass(context);
|
|
168
|
+
rowCount = values.getLength();
|
|
169
|
+
}
|
|
170
|
+
for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) {
|
|
171
|
+
RubyArray row = (RubyArray) values.eltInternal(rowIndex);
|
|
172
|
+
IRubyObject value = row.eltInternal(columnIndex);
|
|
173
|
+
if (value != context.nil) {
|
|
174
|
+
row.eltInternalSet(columnIndex, BinaryDataClass.newInstance(context, value, Block.NULL_BLOCK));
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
return super.toARResult(context);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Returns an array of arrays of the values in the result.
|
|
185
|
+
* This is defined in PG::Result and is used by some Rails tests
|
|
186
|
+
* @return IRubyObject RubyArray of RubyArray of values
|
|
187
|
+
*/
|
|
188
|
+
@JRubyMethod
|
|
189
|
+
public IRubyObject values() {
|
|
190
|
+
return values;
|
|
191
|
+
}
|
|
192
|
+
}
|