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.
- data/Gemfile +8 -0
- data/Gemfile.lock +22 -0
- data/LICENSE.md +23 -0
- data/README.rdoc +59 -0
- data/Rakefile +32 -0
- data/VERSION +1 -0
- data/doc/BUGS +2 -0
- data/doc/examples/README +6 -0
- data/doc/examples/connection.rb +16 -0
- data/doc/examples/connection_auto.rb +22 -0
- data/doc/examples/connection_ctor.rb +18 -0
- data/doc/examples/connection_default.rb +15 -0
- data/doc/examples/connection_exec.rb +18 -0
- data/doc/examples/connection_manual.rb +12 -0
- data/doc/examples/connection_wrapped_new.rb +13 -0
- data/doc/examples/connection_wrapped_open.rb +13 -0
- data/doc/examples/cursor.rb +38 -0
- data/doc/examples/include_module.rb +9 -0
- data/doc/examples/include_module2.rb +12 -0
- data/doc/examples/insert.rb +30 -0
- data/doc/examples/insert2.rb +36 -0
- data/doc/examples/insert_bytea.rb +16 -0
- data/doc/examples/insert_bytea_array.rb +17 -0
- data/doc/examples/insert_default_values.rb +16 -0
- data/doc/examples/insert_insert.rb +16 -0
- data/doc/examples/insert_insert_default.rb +16 -0
- data/doc/examples/insert_insert_select.rb +20 -0
- data/doc/examples/insert_select.rb +20 -0
- data/doc/examples/interval.rb +17 -0
- data/doc/examples/savepoint.rb +38 -0
- data/doc/examples/select.rb +33 -0
- data/doc/examples/select2.rb +36 -0
- data/doc/examples/select_cross_join.rb +18 -0
- data/doc/examples/select_distinct.rb +18 -0
- data/doc/examples/select_distinct_on +19 -0
- data/doc/examples/select_for_update.rb +18 -0
- data/doc/examples/select_from.rb +17 -0
- data/doc/examples/select_from_subselect.rb +20 -0
- data/doc/examples/select_group_by.rb +19 -0
- data/doc/examples/select_having.rb +20 -0
- data/doc/examples/select_join_on.rb +18 -0
- data/doc/examples/select_join_using.rb +18 -0
- data/doc/examples/select_limit.rb +19 -0
- data/doc/examples/select_natural_join.rb +18 -0
- data/doc/examples/select_offset.rb +19 -0
- data/doc/examples/select_order_by.rb +20 -0
- data/doc/examples/select_select.rb +30 -0
- data/doc/examples/select_select_alias.rb +30 -0
- data/doc/examples/select_select_expression.rb +31 -0
- data/doc/examples/select_select_literal.rb +24 -0
- data/doc/examples/select_union.rb +21 -0
- data/doc/examples/select_where_array.rb +18 -0
- data/doc/examples/select_where_in.rb +18 -0
- data/doc/examples/select_where_string.rb +18 -0
- data/doc/examples/simple.rb +34 -0
- data/doc/examples/transaction.rb +30 -0
- data/doc/examples/transaction_abort.rb +30 -0
- data/doc/examples/transaction_commit.rb +34 -0
- data/doc/examples/translate_substitute_values.rb +17 -0
- data/doc/examples/update.rb +32 -0
- data/doc/examples/update2.rb +44 -0
- data/doc/examples/update_only.rb +17 -0
- data/doc/examples/update_set.rb +17 -0
- data/doc/examples/update_set_array.rb +16 -0
- data/doc/examples/update_set_bytea.rb +16 -0
- data/doc/examples/update_set_expression.rb +16 -0
- data/doc/examples/update_set_subselect.rb +20 -0
- data/doc/examples/update_where.rb +17 -0
- data/doc/examples/use_prefix.rb +8 -0
- data/doc/examples/use_prefix2.rb +11 -0
- data/doc/index.html +31 -0
- data/doc/insertexamples.rb +9 -0
- data/doc/makemanual +4 -0
- data/doc/makerdoc +5 -0
- data/doc/manual.dbk +622 -0
- data/lib/sqlpostgres/Connection.rb +198 -0
- data/lib/sqlpostgres/Cursor.rb +157 -0
- data/lib/sqlpostgres/Delete.rb +67 -0
- data/lib/sqlpostgres/Exceptions.rb +15 -0
- data/lib/sqlpostgres/Insert.rb +279 -0
- data/lib/sqlpostgres/NullConnection.rb +22 -0
- data/lib/sqlpostgres/PgBit.rb +73 -0
- data/lib/sqlpostgres/PgBox.rb +37 -0
- data/lib/sqlpostgres/PgCidr.rb +21 -0
- data/lib/sqlpostgres/PgCircle.rb +75 -0
- data/lib/sqlpostgres/PgInet.rb +21 -0
- data/lib/sqlpostgres/PgInterval.rb +208 -0
- data/lib/sqlpostgres/PgLineSegment.rb +37 -0
- data/lib/sqlpostgres/PgMacAddr.rb +21 -0
- data/lib/sqlpostgres/PgPath.rb +64 -0
- data/lib/sqlpostgres/PgPoint.rb +65 -0
- data/lib/sqlpostgres/PgPolygon.rb +56 -0
- data/lib/sqlpostgres/PgTime.rb +77 -0
- data/lib/sqlpostgres/PgTimeWithTimeZone.rb +98 -0
- data/lib/sqlpostgres/PgTimestamp.rb +93 -0
- data/lib/sqlpostgres/PgTwoPoints.rb +54 -0
- data/lib/sqlpostgres/PgType.rb +34 -0
- data/lib/sqlpostgres/PgWrapper.rb +41 -0
- data/lib/sqlpostgres/Savepoint.rb +98 -0
- data/lib/sqlpostgres/Select.rb +855 -0
- data/lib/sqlpostgres/Transaction.rb +120 -0
- data/lib/sqlpostgres/Translate.rb +436 -0
- data/lib/sqlpostgres/Update.rb +188 -0
- data/lib/sqlpostgres.rb +67 -0
- data/test/Assert.rb +72 -0
- data/test/Connection.test.rb +246 -0
- data/test/Cursor.test.rb +190 -0
- data/test/Delete.test.rb +68 -0
- data/test/Insert.test.rb +123 -0
- data/test/MockPGconn.rb +62 -0
- data/test/NullConnection.test.rb +32 -0
- data/test/PgBit.test.rb +98 -0
- data/test/PgBox.test.rb +108 -0
- data/test/PgCidr.test.rb +61 -0
- data/test/PgCircle.test.rb +107 -0
- data/test/PgInet.test.rb +61 -0
- data/test/PgInterval.test.rb +180 -0
- data/test/PgLineSegment.test.rb +108 -0
- data/test/PgMacAddr.test.rb +61 -0
- data/test/PgPath.test.rb +106 -0
- data/test/PgPoint.test.rb +100 -0
- data/test/PgPolygon.test.rb +95 -0
- data/test/PgTime.test.rb +120 -0
- data/test/PgTimeWithTimeZone.test.rb +117 -0
- data/test/PgTimestamp.test.rb +134 -0
- data/test/RandomThings.rb +25 -0
- data/test/Savepoint.test.rb +286 -0
- data/test/Select.test.rb +930 -0
- data/test/Test.rb +62 -0
- data/test/TestConfig.rb +21 -0
- data/test/TestSetup.rb +13 -0
- data/test/TestUtil.rb +92 -0
- data/test/Transaction.test.rb +275 -0
- data/test/Translate.test.rb +354 -0
- data/test/Update.test.rb +227 -0
- data/test/roundtrip.test.rb +565 -0
- data/test/test +34 -0
- data/tools/exampleinserter/ExampleInserter.rb +177 -0
- data/tools/rdoc/ChangeLog +796 -0
- data/tools/rdoc/EXAMPLE.rb +48 -0
- data/tools/rdoc/MANIFEST +58 -0
- data/tools/rdoc/Makefile +27 -0
- data/tools/rdoc/NEW_FEATURES +226 -0
- data/tools/rdoc/README +390 -0
- data/tools/rdoc/ToDo +6 -0
- data/tools/rdoc/contrib/Index +6 -0
- data/tools/rdoc/contrib/xslfo/ChangeLog +181 -0
- data/tools/rdoc/contrib/xslfo/README +106 -0
- data/tools/rdoc/contrib/xslfo/TODO +10 -0
- data/tools/rdoc/contrib/xslfo/convert.xsl +151 -0
- data/tools/rdoc/contrib/xslfo/demo/README +21 -0
- data/tools/rdoc/contrib/xslfo/demo/rdocfo +99 -0
- data/tools/rdoc/contrib/xslfo/fcm.xsl +54 -0
- data/tools/rdoc/contrib/xslfo/files.xsl +62 -0
- data/tools/rdoc/contrib/xslfo/labeled-lists.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/lists.xsl +44 -0
- data/tools/rdoc/contrib/xslfo/modules.xsl +152 -0
- data/tools/rdoc/contrib/xslfo/rdoc.xsl +75 -0
- data/tools/rdoc/contrib/xslfo/source.xsl +66 -0
- data/tools/rdoc/contrib/xslfo/styles.xsl +69 -0
- data/tools/rdoc/contrib/xslfo/tables.xsl +67 -0
- data/tools/rdoc/contrib/xslfo/utils.xsl +21 -0
- data/tools/rdoc/debian/changelog +33 -0
- data/tools/rdoc/debian/compat +1 -0
- data/tools/rdoc/debian/control +20 -0
- data/tools/rdoc/debian/copyright +10 -0
- data/tools/rdoc/debian/dirs +2 -0
- data/tools/rdoc/debian/docs +2 -0
- data/tools/rdoc/debian/rdoc.1 +252 -0
- data/tools/rdoc/debian/rdoc.manpages +1 -0
- data/tools/rdoc/debian/rdoc.pod +149 -0
- data/tools/rdoc/debian/rules +9 -0
- data/tools/rdoc/dot/dot.rb +255 -0
- data/tools/rdoc/etc/rdoc.dtd +203 -0
- data/tools/rdoc/install.rb +137 -0
- data/tools/rdoc/markup/install.rb +43 -0
- data/tools/rdoc/markup/sample/sample.rb +42 -0
- data/tools/rdoc/markup/simple_markup/fragments.rb +323 -0
- data/tools/rdoc/markup/simple_markup/inline.rb +348 -0
- data/tools/rdoc/markup/simple_markup/lines.rb +147 -0
- data/tools/rdoc/markup/simple_markup/preprocess.rb +68 -0
- data/tools/rdoc/markup/simple_markup/to_html.rb +281 -0
- data/tools/rdoc/markup/simple_markup.rb +474 -0
- data/tools/rdoc/markup/test/AllTests.rb +2 -0
- data/tools/rdoc/markup/test/TestInline.rb +151 -0
- data/tools/rdoc/markup/test/TestParse.rb +411 -0
- data/tools/rdoc/rdoc/code_objects.rb +536 -0
- data/tools/rdoc/rdoc/diagram.rb +331 -0
- data/tools/rdoc/rdoc/generators/chm_generator.rb +112 -0
- data/tools/rdoc/rdoc/generators/html_generator.rb +1268 -0
- data/tools/rdoc/rdoc/generators/template/chm/chm.rb +86 -0
- data/tools/rdoc/rdoc/generators/template/html/html.rb +705 -0
- data/tools/rdoc/rdoc/generators/template/html/kilmer.rb +377 -0
- data/tools/rdoc/rdoc/generators/template/xml/rdf.rb +110 -0
- data/tools/rdoc/rdoc/generators/template/xml/xml.rb +110 -0
- data/tools/rdoc/rdoc/generators/xml_generator.rb +130 -0
- data/tools/rdoc/rdoc/options.rb +451 -0
- data/tools/rdoc/rdoc/parsers/parse_c.rb +287 -0
- data/tools/rdoc/rdoc/parsers/parse_f95.rb +118 -0
- data/tools/rdoc/rdoc/parsers/parse_rb.rb +2311 -0
- data/tools/rdoc/rdoc/parsers/parse_simple.rb +37 -0
- data/tools/rdoc/rdoc/parsers/parserfactory.rb +75 -0
- data/tools/rdoc/rdoc/rdoc.rb +219 -0
- data/tools/rdoc/rdoc/template.rb +234 -0
- data/tools/rdoc/rdoc/tokenstream.rb +25 -0
- data/tools/rdoc/rdoc.rb +9 -0
- 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:
|