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.
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
+ }