sqlpostgres 1.2.4

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 (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: