sqlpostgres 1.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (207) hide show
  1. data/Gemfile +8 -0
  2. data/Gemfile.lock +22 -0
  3. data/LICENSE.md +23 -0
  4. data/README.rdoc +59 -0
  5. data/Rakefile +32 -0
  6. data/VERSION +1 -0
  7. data/doc/BUGS +2 -0
  8. data/doc/examples/README +6 -0
  9. data/doc/examples/connection.rb +16 -0
  10. data/doc/examples/connection_auto.rb +22 -0
  11. data/doc/examples/connection_ctor.rb +18 -0
  12. data/doc/examples/connection_default.rb +15 -0
  13. data/doc/examples/connection_exec.rb +18 -0
  14. data/doc/examples/connection_manual.rb +12 -0
  15. data/doc/examples/connection_wrapped_new.rb +13 -0
  16. data/doc/examples/connection_wrapped_open.rb +13 -0
  17. data/doc/examples/cursor.rb +38 -0
  18. data/doc/examples/include_module.rb +9 -0
  19. data/doc/examples/include_module2.rb +12 -0
  20. data/doc/examples/insert.rb +30 -0
  21. data/doc/examples/insert2.rb +36 -0
  22. data/doc/examples/insert_bytea.rb +16 -0
  23. data/doc/examples/insert_bytea_array.rb +17 -0
  24. data/doc/examples/insert_default_values.rb +16 -0
  25. data/doc/examples/insert_insert.rb +16 -0
  26. data/doc/examples/insert_insert_default.rb +16 -0
  27. data/doc/examples/insert_insert_select.rb +20 -0
  28. data/doc/examples/insert_select.rb +20 -0
  29. data/doc/examples/interval.rb +17 -0
  30. data/doc/examples/savepoint.rb +38 -0
  31. data/doc/examples/select.rb +33 -0
  32. data/doc/examples/select2.rb +36 -0
  33. data/doc/examples/select_cross_join.rb +18 -0
  34. data/doc/examples/select_distinct.rb +18 -0
  35. data/doc/examples/select_distinct_on +19 -0
  36. data/doc/examples/select_for_update.rb +18 -0
  37. data/doc/examples/select_from.rb +17 -0
  38. data/doc/examples/select_from_subselect.rb +20 -0
  39. data/doc/examples/select_group_by.rb +19 -0
  40. data/doc/examples/select_having.rb +20 -0
  41. data/doc/examples/select_join_on.rb +18 -0
  42. data/doc/examples/select_join_using.rb +18 -0
  43. data/doc/examples/select_limit.rb +19 -0
  44. data/doc/examples/select_natural_join.rb +18 -0
  45. data/doc/examples/select_offset.rb +19 -0
  46. data/doc/examples/select_order_by.rb +20 -0
  47. data/doc/examples/select_select.rb +30 -0
  48. data/doc/examples/select_select_alias.rb +30 -0
  49. data/doc/examples/select_select_expression.rb +31 -0
  50. data/doc/examples/select_select_literal.rb +24 -0
  51. data/doc/examples/select_union.rb +21 -0
  52. data/doc/examples/select_where_array.rb +18 -0
  53. data/doc/examples/select_where_in.rb +18 -0
  54. data/doc/examples/select_where_string.rb +18 -0
  55. data/doc/examples/simple.rb +34 -0
  56. data/doc/examples/transaction.rb +30 -0
  57. data/doc/examples/transaction_abort.rb +30 -0
  58. data/doc/examples/transaction_commit.rb +34 -0
  59. data/doc/examples/translate_substitute_values.rb +17 -0
  60. data/doc/examples/update.rb +32 -0
  61. data/doc/examples/update2.rb +44 -0
  62. data/doc/examples/update_only.rb +17 -0
  63. data/doc/examples/update_set.rb +17 -0
  64. data/doc/examples/update_set_array.rb +16 -0
  65. data/doc/examples/update_set_bytea.rb +16 -0
  66. data/doc/examples/update_set_expression.rb +16 -0
  67. data/doc/examples/update_set_subselect.rb +20 -0
  68. data/doc/examples/update_where.rb +17 -0
  69. data/doc/examples/use_prefix.rb +8 -0
  70. data/doc/examples/use_prefix2.rb +11 -0
  71. data/doc/index.html +31 -0
  72. data/doc/insertexamples.rb +9 -0
  73. data/doc/makemanual +4 -0
  74. data/doc/makerdoc +5 -0
  75. data/doc/manual.dbk +622 -0
  76. data/lib/sqlpostgres/Connection.rb +198 -0
  77. data/lib/sqlpostgres/Cursor.rb +157 -0
  78. data/lib/sqlpostgres/Delete.rb +67 -0
  79. data/lib/sqlpostgres/Exceptions.rb +15 -0
  80. data/lib/sqlpostgres/Insert.rb +279 -0
  81. data/lib/sqlpostgres/NullConnection.rb +22 -0
  82. data/lib/sqlpostgres/PgBit.rb +73 -0
  83. data/lib/sqlpostgres/PgBox.rb +37 -0
  84. data/lib/sqlpostgres/PgCidr.rb +21 -0
  85. data/lib/sqlpostgres/PgCircle.rb +75 -0
  86. data/lib/sqlpostgres/PgInet.rb +21 -0
  87. data/lib/sqlpostgres/PgInterval.rb +208 -0
  88. data/lib/sqlpostgres/PgLineSegment.rb +37 -0
  89. data/lib/sqlpostgres/PgMacAddr.rb +21 -0
  90. data/lib/sqlpostgres/PgPath.rb +64 -0
  91. data/lib/sqlpostgres/PgPoint.rb +65 -0
  92. data/lib/sqlpostgres/PgPolygon.rb +56 -0
  93. data/lib/sqlpostgres/PgTime.rb +77 -0
  94. data/lib/sqlpostgres/PgTimeWithTimeZone.rb +98 -0
  95. data/lib/sqlpostgres/PgTimestamp.rb +93 -0
  96. data/lib/sqlpostgres/PgTwoPoints.rb +54 -0
  97. data/lib/sqlpostgres/PgType.rb +34 -0
  98. data/lib/sqlpostgres/PgWrapper.rb +41 -0
  99. data/lib/sqlpostgres/Savepoint.rb +98 -0
  100. data/lib/sqlpostgres/Select.rb +855 -0
  101. data/lib/sqlpostgres/Transaction.rb +120 -0
  102. data/lib/sqlpostgres/Translate.rb +436 -0
  103. data/lib/sqlpostgres/Update.rb +188 -0
  104. data/lib/sqlpostgres.rb +67 -0
  105. data/test/Assert.rb +72 -0
  106. data/test/Connection.test.rb +246 -0
  107. data/test/Cursor.test.rb +190 -0
  108. data/test/Delete.test.rb +68 -0
  109. data/test/Insert.test.rb +123 -0
  110. data/test/MockPGconn.rb +62 -0
  111. data/test/NullConnection.test.rb +32 -0
  112. data/test/PgBit.test.rb +98 -0
  113. data/test/PgBox.test.rb +108 -0
  114. data/test/PgCidr.test.rb +61 -0
  115. data/test/PgCircle.test.rb +107 -0
  116. data/test/PgInet.test.rb +61 -0
  117. data/test/PgInterval.test.rb +180 -0
  118. data/test/PgLineSegment.test.rb +108 -0
  119. data/test/PgMacAddr.test.rb +61 -0
  120. data/test/PgPath.test.rb +106 -0
  121. data/test/PgPoint.test.rb +100 -0
  122. data/test/PgPolygon.test.rb +95 -0
  123. data/test/PgTime.test.rb +120 -0
  124. data/test/PgTimeWithTimeZone.test.rb +117 -0
  125. data/test/PgTimestamp.test.rb +134 -0
  126. data/test/RandomThings.rb +25 -0
  127. data/test/Savepoint.test.rb +286 -0
  128. data/test/Select.test.rb +930 -0
  129. data/test/Test.rb +62 -0
  130. data/test/TestConfig.rb +21 -0
  131. data/test/TestSetup.rb +13 -0
  132. data/test/TestUtil.rb +92 -0
  133. data/test/Transaction.test.rb +275 -0
  134. data/test/Translate.test.rb +354 -0
  135. data/test/Update.test.rb +227 -0
  136. data/test/roundtrip.test.rb +565 -0
  137. data/test/test +34 -0
  138. data/tools/exampleinserter/ExampleInserter.rb +177 -0
  139. data/tools/rdoc/ChangeLog +796 -0
  140. data/tools/rdoc/EXAMPLE.rb +48 -0
  141. data/tools/rdoc/MANIFEST +58 -0
  142. data/tools/rdoc/Makefile +27 -0
  143. data/tools/rdoc/NEW_FEATURES +226 -0
  144. data/tools/rdoc/README +390 -0
  145. data/tools/rdoc/ToDo +6 -0
  146. data/tools/rdoc/contrib/Index +6 -0
  147. data/tools/rdoc/contrib/xslfo/ChangeLog +181 -0
  148. data/tools/rdoc/contrib/xslfo/README +106 -0
  149. data/tools/rdoc/contrib/xslfo/TODO +10 -0
  150. data/tools/rdoc/contrib/xslfo/convert.xsl +151 -0
  151. data/tools/rdoc/contrib/xslfo/demo/README +21 -0
  152. data/tools/rdoc/contrib/xslfo/demo/rdocfo +99 -0
  153. data/tools/rdoc/contrib/xslfo/fcm.xsl +54 -0
  154. data/tools/rdoc/contrib/xslfo/files.xsl +62 -0
  155. data/tools/rdoc/contrib/xslfo/labeled-lists.xsl +66 -0
  156. data/tools/rdoc/contrib/xslfo/lists.xsl +44 -0
  157. data/tools/rdoc/contrib/xslfo/modules.xsl +152 -0
  158. data/tools/rdoc/contrib/xslfo/rdoc.xsl +75 -0
  159. data/tools/rdoc/contrib/xslfo/source.xsl +66 -0
  160. data/tools/rdoc/contrib/xslfo/styles.xsl +69 -0
  161. data/tools/rdoc/contrib/xslfo/tables.xsl +67 -0
  162. data/tools/rdoc/contrib/xslfo/utils.xsl +21 -0
  163. data/tools/rdoc/debian/changelog +33 -0
  164. data/tools/rdoc/debian/compat +1 -0
  165. data/tools/rdoc/debian/control +20 -0
  166. data/tools/rdoc/debian/copyright +10 -0
  167. data/tools/rdoc/debian/dirs +2 -0
  168. data/tools/rdoc/debian/docs +2 -0
  169. data/tools/rdoc/debian/rdoc.1 +252 -0
  170. data/tools/rdoc/debian/rdoc.manpages +1 -0
  171. data/tools/rdoc/debian/rdoc.pod +149 -0
  172. data/tools/rdoc/debian/rules +9 -0
  173. data/tools/rdoc/dot/dot.rb +255 -0
  174. data/tools/rdoc/etc/rdoc.dtd +203 -0
  175. data/tools/rdoc/install.rb +137 -0
  176. data/tools/rdoc/markup/install.rb +43 -0
  177. data/tools/rdoc/markup/sample/sample.rb +42 -0
  178. data/tools/rdoc/markup/simple_markup/fragments.rb +323 -0
  179. data/tools/rdoc/markup/simple_markup/inline.rb +348 -0
  180. data/tools/rdoc/markup/simple_markup/lines.rb +147 -0
  181. data/tools/rdoc/markup/simple_markup/preprocess.rb +68 -0
  182. data/tools/rdoc/markup/simple_markup/to_html.rb +281 -0
  183. data/tools/rdoc/markup/simple_markup.rb +474 -0
  184. data/tools/rdoc/markup/test/AllTests.rb +2 -0
  185. data/tools/rdoc/markup/test/TestInline.rb +151 -0
  186. data/tools/rdoc/markup/test/TestParse.rb +411 -0
  187. data/tools/rdoc/rdoc/code_objects.rb +536 -0
  188. data/tools/rdoc/rdoc/diagram.rb +331 -0
  189. data/tools/rdoc/rdoc/generators/chm_generator.rb +112 -0
  190. data/tools/rdoc/rdoc/generators/html_generator.rb +1268 -0
  191. data/tools/rdoc/rdoc/generators/template/chm/chm.rb +86 -0
  192. data/tools/rdoc/rdoc/generators/template/html/html.rb +705 -0
  193. data/tools/rdoc/rdoc/generators/template/html/kilmer.rb +377 -0
  194. data/tools/rdoc/rdoc/generators/template/xml/rdf.rb +110 -0
  195. data/tools/rdoc/rdoc/generators/template/xml/xml.rb +110 -0
  196. data/tools/rdoc/rdoc/generators/xml_generator.rb +130 -0
  197. data/tools/rdoc/rdoc/options.rb +451 -0
  198. data/tools/rdoc/rdoc/parsers/parse_c.rb +287 -0
  199. data/tools/rdoc/rdoc/parsers/parse_f95.rb +118 -0
  200. data/tools/rdoc/rdoc/parsers/parse_rb.rb +2311 -0
  201. data/tools/rdoc/rdoc/parsers/parse_simple.rb +37 -0
  202. data/tools/rdoc/rdoc/parsers/parserfactory.rb +75 -0
  203. data/tools/rdoc/rdoc/rdoc.rb +219 -0
  204. data/tools/rdoc/rdoc/template.rb +234 -0
  205. data/tools/rdoc/rdoc/tokenstream.rb +25 -0
  206. data/tools/rdoc/rdoc.rb +9 -0
  207. metadata +291 -0
@@ -0,0 +1,120 @@
1
+ module SqlPostgres
2
+
3
+ # This class handles an SQL transaction.
4
+ #
5
+ # Example:
6
+ #** example: transaction
7
+ # Transaction.new(connection) do
8
+ #
9
+ # insert = Insert.new('foo', connection)
10
+ # insert.insert('i', 1)
11
+ # insert.exec
12
+ #
13
+ # insert = Insert.new('foo', connection)
14
+ # insert.insert('i', 2)
15
+ # insert.exec
16
+ #
17
+ # end
18
+ #**
19
+
20
+ class Transaction
21
+
22
+ # Create an SQL transaction, yield, and then end the transaction.
23
+ # If an exception occurs, the transaction is aborted.
24
+ #
25
+ # If no connection is given, then the default connection is used.
26
+
27
+ def initialize(connection = Connection.default)
28
+ @state = :open
29
+ @finished = false
30
+ @connection = connection
31
+ @connection.exec("begin transaction")
32
+ begin
33
+ result = yield(self)
34
+ commit
35
+ result
36
+ rescue Exception
37
+ abort
38
+ raise
39
+ end
40
+ end
41
+
42
+ # Commit this transaction. This is done for you unless an
43
+ # exception occurs within the block you passed to "new". Call
44
+ # this when you want to commit the transaction before raising an
45
+ # exception -- in other words, when you want to keep your database
46
+ # changes even though an exception is about to occur.
47
+ #
48
+ # Example:
49
+ #
50
+ #** example: transaction_commit
51
+ # begin
52
+ # Transaction.new(connection) do |transaction|
53
+ # insert = Insert.new('foo', connection)
54
+ # insert.insert('i', 1)
55
+ # insert.exec
56
+ # transaction.commit
57
+ # raise
58
+ # end
59
+ # rescue Exception => e
60
+ # end
61
+ #
62
+ # select = Select.new(connection)
63
+ # select.select('i')
64
+ # select.from('foo')
65
+ # p select.exec # [{"i"=>1}]
66
+ #**
67
+
68
+ def commit
69
+ unless @finished
70
+ do_commit
71
+ end
72
+ end
73
+
74
+ # Abort this transaction. This is done for you when an exception
75
+ # occurs within the block you passed to "new". Call this when you
76
+ # want to abort a transaction without throwing an exception.
77
+ #
78
+ # Example:
79
+ #
80
+ #** example: transaction_abort
81
+ # Transaction.new(connection) do |transaction|
82
+ # insert = Insert.new('foo', connection)
83
+ # insert.insert('i', 1)
84
+ # insert.exec
85
+ # transaction.abort
86
+ # end
87
+ #
88
+ # select = Select.new(connection)
89
+ # select.select('i')
90
+ # select.from('foo')
91
+ # p select.exec # []
92
+ #**
93
+
94
+ def abort
95
+ unless @finished
96
+ do_abort
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def do_commit
103
+ @connection.exec("end transaction")
104
+ @finished = true
105
+ end
106
+
107
+ def do_abort
108
+ @connection.exec("abort transaction")
109
+ @finished = true
110
+ end
111
+
112
+ end
113
+
114
+ end
115
+
116
+ # Local Variables:
117
+ # tab-width: 2
118
+ # ruby-indent-level: 2
119
+ # indent-tabs-mode: nil
120
+ # End:
@@ -0,0 +1,436 @@
1
+ require 'bigdecimal'
2
+
3
+ module SqlPostgres
4
+
5
+ # Translation functions. These are internal and should not be used
6
+ # by clients unless you want extra work when they change.
7
+
8
+ module Translate
9
+
10
+ # Turn a Ruby object into an SQL string.
11
+ #
12
+ # The conversion depends upon the type of thing:
13
+ #
14
+ # [[String, ...]]
15
+ # An arbitrary expression, possibly with value substitution.
16
+ # Converted by calling #substitute_values
17
+ #
18
+ # Examples:
19
+ # ['foo'] -> 'foo'
20
+ # ['%s + %s', 1, 1.414] -> '1 + 1.414'
21
+ #
22
+ # [[:in, ...]]
23
+ # A list of values that will be converted by recursively
24
+ # calling escape_sql, separated with commas, and surrounded
25
+ # by parentheses.
26
+ #
27
+ # Examples:
28
+ # [:in, 1, 2] -> "(1, 2)"
29
+ # [:in, 'foo', 'bar'] => "('foo', 'bar')"
30
+ #
31
+ # [String]
32
+ # Backslashes and single-quotes are escaped; the resulting
33
+ # string is then enclosed in single-quotes.
34
+ #
35
+ # Examples:
36
+ # "foo" -> "'foo'"
37
+ # "fool's gold' -> %q"'fool\\'s gold'"
38
+ # 'foo\\bar' -> %q"'foo\\\\bar'"
39
+ #
40
+ # [false]
41
+ # Converted to "false"
42
+ #
43
+ # [true]
44
+ # Converted to "true"
45
+ #
46
+ # [Integer]
47
+ # Converted to a string
48
+ #
49
+ # Examples:
50
+ # 123 -> "123"
51
+ # -2 -> "-2"
52
+ #
53
+ # [BigDecimal]
54
+ # Converted ot a a string
55
+ #
56
+ # Examples:
57
+ # BigDecimal("123.456789012345") -> "123.456789012345"
58
+ #
59
+ # [Float]
60
+ # Converted to a string with 15 digits of precision, using exponential
61
+ # notation of necessary.
62
+ #
63
+ # Examples:
64
+ # 0 -> "0"
65
+ # -1 -> "-1"
66
+ # 3.1415926535898 -> "3.1415926535898"
67
+ # 1e100 -> "1e+100"
68
+ #
69
+ # [Time]
70
+ # Converted to a timestamp with microseconds.
71
+ #
72
+ # Examples:
73
+ # Time.local(2000, 1, 2, 3, 4, 5, 6) ->
74
+ # "timestamp '2000-01-02 03:04:05.000006'"
75
+ #
76
+ # [:default]
77
+ # Converted to "default"
78
+ #
79
+ # [nil]
80
+ # Converted to "null"
81
+ #
82
+ # [Select]
83
+ # The statement method is called to get the SQL, which is then
84
+ # wrapped in parentheses.
85
+ #
86
+ # Example, supposing that select.statement is "select 1 as i":
87
+ # select -> "(select 1 as i)"
88
+ #
89
+ # [anything else]
90
+ # Treated as a String (after calling to_s on it)
91
+
92
+ def escape_sql(thing)
93
+ return "null" if thing.nil?
94
+ if thing.is_a?(Array)
95
+ substitute_values(thing)
96
+ elsif thing.respond_to?(:to_sql)
97
+ thing.to_sql
98
+ elsif thing.is_a?(Time)
99
+ "timestamp '#{timeToSql(thing)}'"
100
+ elsif thing.is_a?(DateTime)
101
+ "timestamp with time zone '#{datetime_to_sql(thing)}'"
102
+ elsif thing.is_a?(Integer)
103
+ thing.to_s
104
+ elsif thing.is_a?(Float)
105
+ "%.14g" % thing
106
+ elsif thing.is_a?(Date)
107
+ "date '#{thing}'"
108
+ elsif thing.is_a?(BigDecimal)
109
+ thing.to_s('f')
110
+ elsif thing == false
111
+ "false"
112
+ elsif thing == true
113
+ "true"
114
+ elsif thing == :default
115
+ "default"
116
+ elsif thing.respond_to?(:statement)
117
+ "(#{thing.statement})"
118
+ else
119
+ string_to_sql(thing.to_s, '\\')
120
+ end
121
+ end
122
+ module_function :escape_sql
123
+
124
+ # Convert an arbitrary expression to SQL, possibly with value
125
+ # substitution. expression is an array.
126
+ #
127
+ # If the first element of the array is a String, then it is the
128
+ # format specificer The format specifier contains a %s for each
129
+ # value. The remainin items, if they exist, are values. Each
130
+ # value is turned into a string by calling escape_sql and is then
131
+ # substituted for a %s in the format specifier.
132
+ #
133
+ # If the first element of the array is :in, then the remaining
134
+ # items are to be formatted using escape_sql, separated by commas,
135
+ # and surrounded by parentheses.
136
+ #
137
+ # Examples:
138
+ #** example: translate_substitute_values
139
+ # p Translate.substitute_values(['foo']) # "foo"
140
+ # p Translate.substitute_values(['%s + %s', 1, 2]) # "1 + 2"
141
+ # p Translate.substitute_values([:in, 1, 2]) # "(1, 2)"
142
+ # p Translate.substitute_values([:in, 'foo', 'bar']) # "(E'foo',
143
+ # # E'bar')"
144
+ #**
145
+
146
+ def substitute_values(expression)
147
+ if expression.is_a?(Array)
148
+ pieces = expression[1..-1].collect do |value|
149
+ escape_sql(value)
150
+ end
151
+ if expression.first == :in
152
+ "(#{pieces.join(', ')})"
153
+ else
154
+ expression[0] % pieces
155
+ end
156
+ else
157
+ expression
158
+ end
159
+ end
160
+ module_function :substitute_values
161
+
162
+ # Escape an array to be inserted into a Postgres array column.
163
+ # Array columns are a Postgres extension.
164
+
165
+ def escape_array(a)
166
+ if a.is_a?(Array)
167
+ if a.empty?
168
+ "'{}'"
169
+ else
170
+ pieces = a.collect do |e|
171
+ escape_array(e)
172
+ end
173
+ "ARRAY[#{pieces.join(', ')}]"
174
+ end
175
+ else
176
+ escape_sql(a)
177
+ end
178
+ end
179
+ module_function :escape_array
180
+
181
+ # Escape an array to be inserted into a Posgres bytea[] column.
182
+ # Array columns (and bytea columns) are a Postgres extension.
183
+
184
+ def escape_bytea_array(a)
185
+ escape_bytea_quote(a) do |e|
186
+ e.
187
+ gsub(/\\/, '\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\').
188
+ gsub(/\000/, "\\\\\\\\\\\\\\\\000")
189
+ end
190
+ end
191
+ module_function :escape_bytea_array
192
+
193
+ def escape_bytea_quote(a, &escaper)
194
+ return "null" if a.nil?
195
+ "'#{escape_array_noquote(a, &escaper)}'"
196
+ end
197
+ module_function :escape_bytea_quote
198
+ private_class_method :escape_bytea_quote
199
+
200
+ def escape_array_noquote(a, &escaper)
201
+ pieces = Array(a).map do |e|
202
+ if e.is_a?(Array)
203
+ escape_array_noquote(e, &escaper)
204
+ else
205
+ escaped = escaper.call(e.to_s).
206
+ gsub(/'/, "\\\\'").
207
+ gsub(/"/, "\\\\\\\"")
208
+ '"' + escaped + '"'
209
+ end
210
+ end
211
+ "{" + pieces.join(',') + "}"
212
+ end
213
+ module_function :escape_array_noquote
214
+ private_class_method :escape_array_noquote
215
+
216
+ # Translate a Postgres string representation of an array into a
217
+ # Ruby array of strings.
218
+
219
+ def sql_to_array(s)
220
+ begin
221
+ a, t = sql_to_array2(s)
222
+ raise ArgumentError unless t.empty?
223
+ a
224
+ rescue ArgumentError
225
+ raise ArgumentError, s.inspect
226
+ end
227
+ end
228
+ module_function :sql_to_array
229
+
230
+ def sql_to_array2(s)
231
+ if s !~ /\A\{/m
232
+ raise ArgumentError
233
+ else
234
+ t = $'
235
+ a = []
236
+ loop do
237
+ case t
238
+ when /\A\},?/
239
+ return [a, $']
240
+ when /\A\{/
241
+ e, t = sql_to_array2(t)
242
+ a << e
243
+ when /\A([^"][^\},]*),?/m
244
+ t = $' || ""
245
+ a << $1
246
+ when /\A"((?:[^\\]|\\\\|\\")*?)",?/m
247
+ t = $' || ""
248
+ a << $1.gsub(/\\\\/, "\\").gsub(/\\"/, '"')
249
+ else
250
+ raise ArgumentError
251
+ end
252
+ end
253
+ a
254
+ end
255
+ end
256
+ module_function :sql_to_array2
257
+ private_class_method :sql_to_array2
258
+
259
+ # Escape a string to be inserted into a bytea (byte array) column.
260
+ #
261
+ # [s]
262
+ # The value to convert. Should be one of:
263
+ # * String
264
+ # * nil
265
+ # * :default
266
+ #
267
+ # The following characters get converted to mega-backslashed octal:
268
+ # \x00-\x1f
269
+ # '
270
+ # \
271
+ # \x7f-\xff
272
+
273
+ def escape_bytea(s)
274
+ return "null" if s.nil?
275
+ return "default" if s == :default
276
+ "E'" + PGconn.escape_bytea(Array(s).join) + "'"
277
+ end
278
+ module_function :escape_bytea
279
+
280
+ # Unescape octal escape sequences, turning them back into bytes.
281
+
282
+ def unescape_octal_escapes(s)
283
+ s.gsub(/\\(\d{3})/) do
284
+ $1.oct.chr
285
+ end.gsub(/\\\\/, '\\')
286
+ end
287
+ module_function :unescape_octal_escapes
288
+
289
+ # Unescape a bytea string read from postgres.
290
+
291
+ def unescape_bytea(s)
292
+ if s.respond_to?(:force_encoding)
293
+ s = s.force_encoding("ASCII-8BIT")
294
+ end
295
+ s.gsub(/\\(\\|[0-3][0-7][0-7])/) do
296
+ if $1 == "\\"
297
+ "\\"
298
+ else
299
+ $1.oct.chr
300
+ end
301
+ end
302
+ end
303
+ module_function :unescape_bytea
304
+
305
+ # Unescape a text string read from postges.
306
+
307
+ def unescape_text(s)
308
+ unescape_bytea(s)
309
+ end
310
+ module_function :unescape_text
311
+
312
+ # Convert a time to SQL format, including microseconds:
313
+ # (YYYY-mm-dd HH:MM:SS.uuuuuu)
314
+
315
+ def timeToSql(time)
316
+ time.strftime("%Y-%m-%d %H:%M:%S.") + ("%06d" % time.usec)
317
+ end
318
+ module_function :timeToSql
319
+
320
+ # Convert a datetime to Postgres format (ie "2003-10-18
321
+ # 11:30:24.000000-07")
322
+
323
+ def datetime_to_sql(d)
324
+ d.strftime("%Y-%m-%d %H:%M:%S%z").gsub(/Z$/, "+0000")
325
+ end
326
+ module_function :datetime_to_sql
327
+
328
+ # Convert a date from Postgres format (ie "2003-10-18") to a Date
329
+
330
+ def sql_to_date(s)
331
+ Date.parse(s)
332
+ end
333
+ module_function :sql_to_date
334
+
335
+ # Convert a time with timezone from Postgres format (ie
336
+ # "2003-10-18 11:30:24-07") to a DateTime.
337
+
338
+ def sql_to_datetime(s)
339
+ DateTime.parse(s)
340
+ end
341
+ module_function :sql_to_datetime
342
+
343
+ # Escape a "char" type (the special Postgres internal type used in
344
+ # system tables).
345
+ #
346
+ # [s]
347
+ # A String of length 1.
348
+
349
+ def escape_qchar(s)
350
+ if s.nil?
351
+ "null"
352
+ else
353
+ "E'" + escape_char(s[0].ord) + "'"
354
+ end
355
+ end
356
+ module_function :escape_qchar
357
+
358
+ # # Escape a "char"[] type (the special Postgres internal type used
359
+ # # in system tables).
360
+ # #
361
+ # # [a]
362
+ # # An array (possibly nested) of String of length 1.
363
+
364
+ # def escape_qchar_array(a)
365
+ # escape_bytea_array(a)
366
+ # end
367
+ # module_function :escape_qchar_array
368
+
369
+ # Unescape a "char" type. This is a special internal type (yes, the
370
+ # quotes are part of the type name).
371
+ #
372
+ # [s]
373
+ # A String of length 1. If empty, it really means "\000".
374
+
375
+ def unescape_qchar(s)
376
+ if s.empty?
377
+ "\000"
378
+ else
379
+ return s
380
+ end
381
+ end
382
+ module_function :unescape_qchar
383
+
384
+ # Escape a character, converting non-printable (0x0-0x1f, 0x7f-0xff),
385
+ # backslash, and single-quote into an octal escape sequence.
386
+ #
387
+ # [c]
388
+ # The character code to convert (an integer between 0 and 255)
389
+ #
390
+ # [backslahes]
391
+ # The backslashes to use in the escape sequence
392
+
393
+ def escape_char(c, backslashes = '\\')
394
+ "#{backslashes}%03o" % c
395
+ end
396
+ module_function :escape_char
397
+ private_class_method :escape_char
398
+
399
+ # Escape a string, converting non-printable (\x0-\x1f, \x7f-\xff),
400
+ # backshlash, and single-quote into octal escape sequences and/or
401
+ # unicode.
402
+ #
403
+ # [thing]
404
+ # The string to convert
405
+ #
406
+ # [backslashes]
407
+ # The backslashes to use in the escape sequence.
408
+
409
+ def string_to_sql(thing, backslashes)
410
+ "E'" + thing.gsub(/[\x0-\x1f\x80-\xff'\\]/) do |c|
411
+ escape_char(c[0].ord, backslashes)
412
+ end + "'"
413
+ end
414
+ module_function :string_to_sql
415
+ private_class_method :string_to_sql
416
+
417
+ def deep_collect(a)
418
+ if a.is_a?(Array)
419
+ a.collect do |e|
420
+ deep_collect(e) do |v| yield(v) end
421
+ end
422
+ else
423
+ yield(a)
424
+ end
425
+ end
426
+ module_function :deep_collect
427
+
428
+ end
429
+
430
+ end
431
+
432
+ # Local Variables:
433
+ # tab-width: 2
434
+ # ruby-indent-level: 2
435
+ # indent-tabs-mode: nil
436
+ # End: