activerecord-jdbc-alt-adapter 50.3.0-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +35 -0
  3. data/.travis.yml +100 -0
  4. data/.yardopts +4 -0
  5. data/CONTRIBUTING.md +50 -0
  6. data/Gemfile +92 -0
  7. data/History.md +1191 -0
  8. data/LICENSE.txt +26 -0
  9. data/README.md +240 -0
  10. data/RUNNING_TESTS.md +127 -0
  11. data/Rakefile +336 -0
  12. data/Rakefile.jdbc +20 -0
  13. data/activerecord-jdbc-adapter.gemspec +55 -0
  14. data/activerecord-jdbc-alt-adapter.gemspec +56 -0
  15. data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
  16. data/lib/active_record/connection_adapters/db2_adapter.rb +1 -0
  17. data/lib/active_record/connection_adapters/derby_adapter.rb +1 -0
  18. data/lib/active_record/connection_adapters/firebird_adapter.rb +1 -0
  19. data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
  20. data/lib/active_record/connection_adapters/hsqldb_adapter.rb +1 -0
  21. data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
  22. data/lib/active_record/connection_adapters/jdbc_adapter.rb +1 -0
  23. data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
  24. data/lib/active_record/connection_adapters/mariadb_adapter.rb +1 -0
  25. data/lib/active_record/connection_adapters/mssql_adapter.rb +1 -0
  26. data/lib/active_record/connection_adapters/mysql2_adapter.rb +1 -0
  27. data/lib/active_record/connection_adapters/mysql_adapter.rb +1 -0
  28. data/lib/active_record/connection_adapters/postgresql_adapter.rb +1 -0
  29. data/lib/active_record/connection_adapters/sqlite3_adapter.rb +1 -0
  30. data/lib/active_record/connection_adapters/sqlserver_adapter.rb +1 -0
  31. data/lib/activerecord-jdbc-adapter.rb +1 -0
  32. data/lib/arel/visitors/compat.rb +60 -0
  33. data/lib/arel/visitors/db2.rb +137 -0
  34. data/lib/arel/visitors/derby.rb +112 -0
  35. data/lib/arel/visitors/firebird.rb +79 -0
  36. data/lib/arel/visitors/h2.rb +25 -0
  37. data/lib/arel/visitors/hsqldb.rb +32 -0
  38. data/lib/arel/visitors/postgresql_jdbc.rb +6 -0
  39. data/lib/arel/visitors/sql_server.rb +225 -0
  40. data/lib/arel/visitors/sql_server/ng42.rb +294 -0
  41. data/lib/arel/visitors/sqlserver.rb +214 -0
  42. data/lib/arjdbc.rb +19 -0
  43. data/lib/arjdbc/abstract/connection_management.rb +35 -0
  44. data/lib/arjdbc/abstract/core.rb +74 -0
  45. data/lib/arjdbc/abstract/database_statements.rb +64 -0
  46. data/lib/arjdbc/abstract/statement_cache.rb +58 -0
  47. data/lib/arjdbc/abstract/transaction_support.rb +86 -0
  48. data/lib/arjdbc/db2.rb +4 -0
  49. data/lib/arjdbc/db2/adapter.rb +789 -0
  50. data/lib/arjdbc/db2/as400.rb +130 -0
  51. data/lib/arjdbc/db2/column.rb +167 -0
  52. data/lib/arjdbc/db2/connection_methods.rb +44 -0
  53. data/lib/arjdbc/derby.rb +3 -0
  54. data/lib/arjdbc/derby/active_record_patch.rb +13 -0
  55. data/lib/arjdbc/derby/adapter.rb +540 -0
  56. data/lib/arjdbc/derby/connection_methods.rb +20 -0
  57. data/lib/arjdbc/derby/schema_creation.rb +15 -0
  58. data/lib/arjdbc/discover.rb +104 -0
  59. data/lib/arjdbc/firebird.rb +4 -0
  60. data/lib/arjdbc/firebird/adapter.rb +434 -0
  61. data/lib/arjdbc/firebird/connection_methods.rb +23 -0
  62. data/lib/arjdbc/h2.rb +3 -0
  63. data/lib/arjdbc/h2/adapter.rb +303 -0
  64. data/lib/arjdbc/h2/connection_methods.rb +27 -0
  65. data/lib/arjdbc/hsqldb.rb +3 -0
  66. data/lib/arjdbc/hsqldb/adapter.rb +297 -0
  67. data/lib/arjdbc/hsqldb/connection_methods.rb +28 -0
  68. data/lib/arjdbc/hsqldb/explain_support.rb +35 -0
  69. data/lib/arjdbc/hsqldb/schema_creation.rb +11 -0
  70. data/lib/arjdbc/informix.rb +5 -0
  71. data/lib/arjdbc/informix/adapter.rb +162 -0
  72. data/lib/arjdbc/informix/connection_methods.rb +9 -0
  73. data/lib/arjdbc/jdbc.rb +59 -0
  74. data/lib/arjdbc/jdbc/adapter.rb +475 -0
  75. data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
  76. data/lib/arjdbc/jdbc/base_ext.rb +15 -0
  77. data/lib/arjdbc/jdbc/callbacks.rb +53 -0
  78. data/lib/arjdbc/jdbc/column.rb +97 -0
  79. data/lib/arjdbc/jdbc/connection.rb +14 -0
  80. data/lib/arjdbc/jdbc/connection_methods.rb +37 -0
  81. data/lib/arjdbc/jdbc/error.rb +65 -0
  82. data/lib/arjdbc/jdbc/extension.rb +59 -0
  83. data/lib/arjdbc/jdbc/java.rb +13 -0
  84. data/lib/arjdbc/jdbc/railtie.rb +2 -0
  85. data/lib/arjdbc/jdbc/rake_tasks.rb +3 -0
  86. data/lib/arjdbc/jdbc/serialized_attributes_helper.rb +3 -0
  87. data/lib/arjdbc/jdbc/type_cast.rb +166 -0
  88. data/lib/arjdbc/jdbc/type_converter.rb +142 -0
  89. data/lib/arjdbc/mssql.rb +7 -0
  90. data/lib/arjdbc/mssql/adapter.rb +384 -0
  91. data/lib/arjdbc/mssql/column.rb +29 -0
  92. data/lib/arjdbc/mssql/connection_methods.rb +79 -0
  93. data/lib/arjdbc/mssql/database_statements.rb +134 -0
  94. data/lib/arjdbc/mssql/errors.rb +6 -0
  95. data/lib/arjdbc/mssql/explain_support.rb +129 -0
  96. data/lib/arjdbc/mssql/extensions.rb +36 -0
  97. data/lib/arjdbc/mssql/limit_helpers.rb +231 -0
  98. data/lib/arjdbc/mssql/lock_methods.rb +77 -0
  99. data/lib/arjdbc/mssql/old_adapter.rb +804 -0
  100. data/lib/arjdbc/mssql/old_column.rb +200 -0
  101. data/lib/arjdbc/mssql/quoting.rb +101 -0
  102. data/lib/arjdbc/mssql/schema_creation.rb +31 -0
  103. data/lib/arjdbc/mssql/schema_definitions.rb +74 -0
  104. data/lib/arjdbc/mssql/schema_statements.rb +329 -0
  105. data/lib/arjdbc/mssql/transaction.rb +69 -0
  106. data/lib/arjdbc/mssql/types.rb +52 -0
  107. data/lib/arjdbc/mssql/types/binary_types.rb +33 -0
  108. data/lib/arjdbc/mssql/types/date_and_time_types.rb +134 -0
  109. data/lib/arjdbc/mssql/types/deprecated_types.rb +40 -0
  110. data/lib/arjdbc/mssql/types/numeric_types.rb +71 -0
  111. data/lib/arjdbc/mssql/types/string_types.rb +56 -0
  112. data/lib/arjdbc/mssql/utils.rb +66 -0
  113. data/lib/arjdbc/mysql.rb +3 -0
  114. data/lib/arjdbc/mysql/adapter.rb +140 -0
  115. data/lib/arjdbc/mysql/connection_methods.rb +166 -0
  116. data/lib/arjdbc/oracle/adapter.rb +863 -0
  117. data/lib/arjdbc/postgresql.rb +3 -0
  118. data/lib/arjdbc/postgresql/adapter.rb +687 -0
  119. data/lib/arjdbc/postgresql/base/array_decoder.rb +26 -0
  120. data/lib/arjdbc/postgresql/base/array_encoder.rb +25 -0
  121. data/lib/arjdbc/postgresql/base/array_parser.rb +95 -0
  122. data/lib/arjdbc/postgresql/base/pgconn.rb +11 -0
  123. data/lib/arjdbc/postgresql/column.rb +51 -0
  124. data/lib/arjdbc/postgresql/connection_methods.rb +67 -0
  125. data/lib/arjdbc/postgresql/name.rb +24 -0
  126. data/lib/arjdbc/postgresql/oid_types.rb +266 -0
  127. data/lib/arjdbc/railtie.rb +11 -0
  128. data/lib/arjdbc/sqlite3.rb +3 -0
  129. data/lib/arjdbc/sqlite3/adapter.rb +678 -0
  130. data/lib/arjdbc/sqlite3/connection_methods.rb +59 -0
  131. data/lib/arjdbc/sybase.rb +2 -0
  132. data/lib/arjdbc/sybase/adapter.rb +47 -0
  133. data/lib/arjdbc/tasks.rb +13 -0
  134. data/lib/arjdbc/tasks/database_tasks.rb +31 -0
  135. data/lib/arjdbc/tasks/databases.rake +48 -0
  136. data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
  137. data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
  138. data/lib/arjdbc/tasks/h2_database_tasks.rb +31 -0
  139. data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
  140. data/lib/arjdbc/tasks/jdbc_database_tasks.rb +169 -0
  141. data/lib/arjdbc/tasks/mssql_database_tasks.rb +46 -0
  142. data/lib/arjdbc/util/quoted_cache.rb +60 -0
  143. data/lib/arjdbc/util/serialized_attributes.rb +98 -0
  144. data/lib/arjdbc/util/table_copier.rb +110 -0
  145. data/lib/arjdbc/version.rb +3 -0
  146. data/lib/generators/jdbc/USAGE +9 -0
  147. data/lib/generators/jdbc/jdbc_generator.rb +17 -0
  148. data/lib/jdbc_adapter.rb +2 -0
  149. data/lib/jdbc_adapter/rake_tasks.rb +4 -0
  150. data/lib/jdbc_adapter/version.rb +4 -0
  151. data/pom.xml +114 -0
  152. data/rails_generators/jdbc_generator.rb +15 -0
  153. data/rails_generators/templates/config/initializers/jdbc.rb +10 -0
  154. data/rails_generators/templates/lib/tasks/jdbc.rake +11 -0
  155. data/rakelib/01-tomcat.rake +51 -0
  156. data/rakelib/02-test.rake +132 -0
  157. data/rakelib/bundler_ext.rb +11 -0
  158. data/rakelib/db.rake +75 -0
  159. data/rakelib/rails.rake +223 -0
  160. data/src/java/arjdbc/ArJdbcModule.java +276 -0
  161. data/src/java/arjdbc/db2/DB2Module.java +76 -0
  162. data/src/java/arjdbc/db2/DB2RubyJdbcConnection.java +126 -0
  163. data/src/java/arjdbc/derby/DerbyModule.java +178 -0
  164. data/src/java/arjdbc/derby/DerbyRubyJdbcConnection.java +152 -0
  165. data/src/java/arjdbc/firebird/FirebirdRubyJdbcConnection.java +174 -0
  166. data/src/java/arjdbc/h2/H2Module.java +50 -0
  167. data/src/java/arjdbc/h2/H2RubyJdbcConnection.java +85 -0
  168. data/src/java/arjdbc/hsqldb/HSQLDBModule.java +73 -0
  169. data/src/java/arjdbc/informix/InformixRubyJdbcConnection.java +75 -0
  170. data/src/java/arjdbc/jdbc/AdapterJavaService.java +43 -0
  171. data/src/java/arjdbc/jdbc/Callable.java +44 -0
  172. data/src/java/arjdbc/jdbc/ConnectionFactory.java +45 -0
  173. data/src/java/arjdbc/jdbc/DataSourceConnectionFactory.java +156 -0
  174. data/src/java/arjdbc/jdbc/DriverConnectionFactory.java +63 -0
  175. data/src/java/arjdbc/jdbc/DriverWrapper.java +119 -0
  176. data/src/java/arjdbc/jdbc/JdbcResult.java +130 -0
  177. data/src/java/arjdbc/jdbc/RubyConnectionFactory.java +61 -0
  178. data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +3979 -0
  179. data/src/java/arjdbc/mssql/MSSQLModule.java +90 -0
  180. data/src/java/arjdbc/mssql/MSSQLRubyJdbcConnection.java +508 -0
  181. data/src/java/arjdbc/mysql/MySQLModule.java +152 -0
  182. data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +294 -0
  183. data/src/java/arjdbc/oracle/OracleModule.java +80 -0
  184. data/src/java/arjdbc/oracle/OracleRubyJdbcConnection.java +455 -0
  185. data/src/java/arjdbc/postgresql/ByteaUtils.java +157 -0
  186. data/src/java/arjdbc/postgresql/PgDateTimeUtils.java +52 -0
  187. data/src/java/arjdbc/postgresql/PostgreSQLModule.java +77 -0
  188. data/src/java/arjdbc/postgresql/PostgreSQLResult.java +192 -0
  189. data/src/java/arjdbc/postgresql/PostgreSQLRubyJdbcConnection.java +948 -0
  190. data/src/java/arjdbc/sqlite3/SQLite3Module.java +73 -0
  191. data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +525 -0
  192. data/src/java/arjdbc/util/CallResultSet.java +826 -0
  193. data/src/java/arjdbc/util/DateTimeUtils.java +699 -0
  194. data/src/java/arjdbc/util/ObjectSupport.java +65 -0
  195. data/src/java/arjdbc/util/QuotingUtils.java +137 -0
  196. data/src/java/arjdbc/util/StringCache.java +63 -0
  197. data/src/java/arjdbc/util/StringHelper.java +145 -0
  198. 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
+ }