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,855 @@
|
|
|
1
|
+
require 'date'
|
|
2
|
+
|
|
3
|
+
module SqlPostgres
|
|
4
|
+
|
|
5
|
+
# This class creates and executes an SQL select statement.
|
|
6
|
+
#
|
|
7
|
+
# Example (assuming the values 1, 2 and null are in the database):
|
|
8
|
+
#
|
|
9
|
+
#** Example: select
|
|
10
|
+
# select = Select.new(connection)
|
|
11
|
+
# select.select('i')
|
|
12
|
+
# select.from('foo')
|
|
13
|
+
# select.order_by('i')
|
|
14
|
+
# p select.statement # "select i from foo order by i"
|
|
15
|
+
# p select.exec # [{"i"=>1}, {"i"=>2}, {"i"=>nil}]
|
|
16
|
+
#**
|
|
17
|
+
|
|
18
|
+
class Select
|
|
19
|
+
|
|
20
|
+
# Constructor. If no connection is given, uses the default.
|
|
21
|
+
|
|
22
|
+
def initialize(connection = Connection.default)
|
|
23
|
+
@connection = connection
|
|
24
|
+
@tables = []
|
|
25
|
+
@columns = []
|
|
26
|
+
@joins = []
|
|
27
|
+
@order_by = []
|
|
28
|
+
@where = []
|
|
29
|
+
@group_by = []
|
|
30
|
+
@having = []
|
|
31
|
+
@limit = nil
|
|
32
|
+
@offset = nil
|
|
33
|
+
@distinct = false
|
|
34
|
+
@distinct_on = []
|
|
35
|
+
@set_ops = []
|
|
36
|
+
@for_update = false
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Add an expression (usually just a simple column name)
|
|
40
|
+
# to the select statement.
|
|
41
|
+
#
|
|
42
|
+
# [expression]
|
|
43
|
+
# The expression to put in the select statement. Should be one of:
|
|
44
|
+
# [An instance of Select] The Select's SQL statement is put in
|
|
45
|
+
# parentheses and added to this statement.
|
|
46
|
+
# [String or Array] Converted by #substitute_values
|
|
47
|
+
# [as]
|
|
48
|
+
# The alias name to put in the statement and to use as the hash key
|
|
49
|
+
# in the result. If nil, then no alias name appears in the statement
|
|
50
|
+
# and the expression is used as the hash key.
|
|
51
|
+
#
|
|
52
|
+
# Example:
|
|
53
|
+
#** Example: select_select
|
|
54
|
+
# select = Select.new(connection)
|
|
55
|
+
# select.select('i')
|
|
56
|
+
# select.from('foo')
|
|
57
|
+
# p select.statement # "select i from foo"
|
|
58
|
+
# p select.exec # [{"i"=>1}]
|
|
59
|
+
#**
|
|
60
|
+
#
|
|
61
|
+
# Example (alias)
|
|
62
|
+
#** Example: select_select_alias
|
|
63
|
+
# select = Select.new(connection)
|
|
64
|
+
# select.select('i', 'number')
|
|
65
|
+
# select.from('foo')
|
|
66
|
+
# p select.statement # "select i as number from foo"
|
|
67
|
+
# p select.exec # [{"number"=>1}]
|
|
68
|
+
#**
|
|
69
|
+
#
|
|
70
|
+
# Example (expression)
|
|
71
|
+
#** Example: select_select_expression
|
|
72
|
+
# pi = 3.14
|
|
73
|
+
# select = Select.new(connection)
|
|
74
|
+
# select.select(['d * %s', pi], 'c')
|
|
75
|
+
# select.from('circles')
|
|
76
|
+
# p select.statement # "select d * 3.14 as c from circles"
|
|
77
|
+
# p select.exec # [{"c"=>6.28}]
|
|
78
|
+
#**
|
|
79
|
+
|
|
80
|
+
def select(expression, as = nil, &converter)
|
|
81
|
+
converter ||= AutoConverter
|
|
82
|
+
expression = if expression.is_a?(Select)
|
|
83
|
+
"(#{expression.statement})"
|
|
84
|
+
else
|
|
85
|
+
Translate.substitute_values(expression)
|
|
86
|
+
end
|
|
87
|
+
@columns << Column.new(expression, as, converter)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Select a literal, automatically selecting its result type.
|
|
91
|
+
#
|
|
92
|
+
# [value]
|
|
93
|
+
# The value to put in the statement. This can be any of these types:
|
|
94
|
+
# * nil
|
|
95
|
+
# * Integer
|
|
96
|
+
# * Float
|
|
97
|
+
# * String
|
|
98
|
+
# * true or false
|
|
99
|
+
# * #PgTime
|
|
100
|
+
# * #PgInterval
|
|
101
|
+
# * #PgTimeWithTimeZone
|
|
102
|
+
# * #PgTimestamp
|
|
103
|
+
# * #PgPoint
|
|
104
|
+
# * #PgLineSegment
|
|
105
|
+
# * #PgBox
|
|
106
|
+
# * #PgPath
|
|
107
|
+
# * #PgPolygon
|
|
108
|
+
# * #PgCircle
|
|
109
|
+
# * #PgBit
|
|
110
|
+
# * #PgInet
|
|
111
|
+
# * #PgCidr
|
|
112
|
+
# * #PgMacAddr
|
|
113
|
+
#
|
|
114
|
+
# [as]
|
|
115
|
+
# The alias name to put in the statement and to use as the hash
|
|
116
|
+
# key in the result. If nil, then no alias name appears in the
|
|
117
|
+
# statement and the value itself is used as the hash key.
|
|
118
|
+
#
|
|
119
|
+
# Example:
|
|
120
|
+
#** Example: select_select_literal
|
|
121
|
+
# select = Select.new(connection)
|
|
122
|
+
# select.select_literal(2, 'n')
|
|
123
|
+
# select.select_literal('foo', 't')
|
|
124
|
+
# p select.statement # "select 2 as n, E'foo' as t"
|
|
125
|
+
# p select.exec # [{"n"=>2, "t"=>"foo"}]
|
|
126
|
+
#**
|
|
127
|
+
|
|
128
|
+
def select_literal(value, as = nil)
|
|
129
|
+
select(["%s", value], as)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# Add "distinct" to this statement.
|
|
133
|
+
#
|
|
134
|
+
# Example:
|
|
135
|
+
#** Example: select_distinct
|
|
136
|
+
# select = Select.new
|
|
137
|
+
# select.distinct
|
|
138
|
+
# select.select('i')
|
|
139
|
+
# select.from('foo')
|
|
140
|
+
# p select.statement # "select distinct i from foo"
|
|
141
|
+
#**
|
|
142
|
+
|
|
143
|
+
def distinct
|
|
144
|
+
@distinct = true
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Add "distinct on" to this statement.
|
|
148
|
+
# "distinct on" is a postgres extension.
|
|
149
|
+
#
|
|
150
|
+
# Example:
|
|
151
|
+
#** Example: select_distinct_on
|
|
152
|
+
# select = Select.new
|
|
153
|
+
# select.distinct_on('i')
|
|
154
|
+
# select.select('integer', 'i')
|
|
155
|
+
# select.select('integer', 'j')
|
|
156
|
+
# select.from('foo')
|
|
157
|
+
# p select.statement # "select distinct on (i) i, j from
|
|
158
|
+
# # foo"
|
|
159
|
+
#**
|
|
160
|
+
|
|
161
|
+
def distinct_on(expression)
|
|
162
|
+
@distinct_on << expression
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Add the "from" clause to the statement.
|
|
166
|
+
#
|
|
167
|
+
# [table]
|
|
168
|
+
# What's being selected from, which is either
|
|
169
|
+
# * A table name, or
|
|
170
|
+
# * a Select statement
|
|
171
|
+
# [as]
|
|
172
|
+
# The alias name, or nil if there isn't one
|
|
173
|
+
#
|
|
174
|
+
# Table example:
|
|
175
|
+
#** Example: select_from
|
|
176
|
+
# select = Select.new
|
|
177
|
+
# select.select('i')
|
|
178
|
+
# select.from('foo')
|
|
179
|
+
# p select.statement # "select i from foo"
|
|
180
|
+
#**
|
|
181
|
+
#
|
|
182
|
+
# Subselect example:
|
|
183
|
+
#** Example: select_from_subselect
|
|
184
|
+
# subselect = Select.new
|
|
185
|
+
# subselect.select('i')
|
|
186
|
+
# subselect.from('foo')
|
|
187
|
+
# select = Select.new
|
|
188
|
+
# select.select('i')
|
|
189
|
+
# select.from(subselect, 'bar')
|
|
190
|
+
# p select.statement # "select i from (select i from foo) as bar"
|
|
191
|
+
#**
|
|
192
|
+
|
|
193
|
+
def from(table, as = nil)
|
|
194
|
+
table = "(#{table.statement})" if table.is_a?(Select)
|
|
195
|
+
@tables << [table, as].compact.join(' as ')
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
# Add the "union" set operation to this statement.
|
|
199
|
+
# You may call this multiple times.
|
|
200
|
+
#
|
|
201
|
+
# The right-hand-side of the union is put in parentheses.
|
|
202
|
+
# This makes it possible to force the order when doing multiple
|
|
203
|
+
# set operations.
|
|
204
|
+
#
|
|
205
|
+
# Example
|
|
206
|
+
#** Example: select_union
|
|
207
|
+
# select2 = Select.new
|
|
208
|
+
# select2.select('i')
|
|
209
|
+
# select2.from('bar')
|
|
210
|
+
# select1 = Select.new
|
|
211
|
+
# select1.select('i')
|
|
212
|
+
# select1.from('foo')
|
|
213
|
+
# select1.union(select2)
|
|
214
|
+
# p select1.statement # "select i from foo union (select i from
|
|
215
|
+
# # bar)"
|
|
216
|
+
#**
|
|
217
|
+
|
|
218
|
+
def union(select)
|
|
219
|
+
add_set_op('union', select)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Add the "union all" set operation to this statement.
|
|
223
|
+
# See #union.
|
|
224
|
+
|
|
225
|
+
def union_all(select)
|
|
226
|
+
add_set_op('union all', select)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
# Add the "intersect" set operation to this statement.
|
|
230
|
+
# See #union.
|
|
231
|
+
|
|
232
|
+
def intersect(select)
|
|
233
|
+
add_set_op('intersect', select)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Add the "intersect all" set operation to this statement.
|
|
237
|
+
# See #union.
|
|
238
|
+
|
|
239
|
+
def intersect_all(select)
|
|
240
|
+
add_set_op('intersect all', select)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Add the "except" set operation to this statement.
|
|
244
|
+
# See #union.
|
|
245
|
+
|
|
246
|
+
def except(select)
|
|
247
|
+
add_set_op('except', select)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Add the "except all" set operation to this statement.
|
|
251
|
+
# See #union.
|
|
252
|
+
|
|
253
|
+
def except_all(select)
|
|
254
|
+
add_set_op('except all', select)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# Add a natural join to this statement.
|
|
258
|
+
#
|
|
259
|
+
# Example:
|
|
260
|
+
#** Example: select_natural_join
|
|
261
|
+
# select = Select.new
|
|
262
|
+
# select.select('i')
|
|
263
|
+
# select.from('foo')
|
|
264
|
+
# select.natural_join('bar')
|
|
265
|
+
# p select.statement # "select i from foo natural join bar"
|
|
266
|
+
#**
|
|
267
|
+
|
|
268
|
+
def natural_join(table)
|
|
269
|
+
@joins << "natural join #{table}"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Add a "join using" to this statement.
|
|
273
|
+
#
|
|
274
|
+
# [joinType]
|
|
275
|
+
# One of:
|
|
276
|
+
# * 'inner'
|
|
277
|
+
# * 'left outer'
|
|
278
|
+
# * 'right outer'
|
|
279
|
+
# * 'full outer'
|
|
280
|
+
# [table]
|
|
281
|
+
# The table being joined
|
|
282
|
+
# [*columns]
|
|
283
|
+
# One or more column names.
|
|
284
|
+
#
|
|
285
|
+
# Example:
|
|
286
|
+
#** Example: select_join_using
|
|
287
|
+
# select = Select.new
|
|
288
|
+
# select.select('i')
|
|
289
|
+
# select.from('foo')
|
|
290
|
+
# select.join_using('inner', 'bar', 'i', 'j')
|
|
291
|
+
# p select.statement # "select i from foo inner join bar using (i, j)"
|
|
292
|
+
#**
|
|
293
|
+
|
|
294
|
+
def join_using(joinType, table, *columns)
|
|
295
|
+
@joins << "#{joinType} join #{table} using (#{columns.join(', ')})"
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
# Add a "join on" to this statement.
|
|
299
|
+
#
|
|
300
|
+
# [joinType]
|
|
301
|
+
# One of:
|
|
302
|
+
# * 'inner'
|
|
303
|
+
# * 'left outer'
|
|
304
|
+
# * 'right outer'
|
|
305
|
+
# * 'full outer'
|
|
306
|
+
# [table]
|
|
307
|
+
# The table being joined
|
|
308
|
+
# [condition]
|
|
309
|
+
# A string or array that will be converted by #substitute_values
|
|
310
|
+
# and inserted into the statement.
|
|
311
|
+
#
|
|
312
|
+
# Example:
|
|
313
|
+
#** Example: select_join_on
|
|
314
|
+
# select = Select.new
|
|
315
|
+
# select.select('i')
|
|
316
|
+
# select.from('foo')
|
|
317
|
+
# select.join_on('inner', 'bar', 'foo.i = bar.j')
|
|
318
|
+
# p select.statement # "select i from foo inner join bar on (foo.i =
|
|
319
|
+
# # bar.j)"
|
|
320
|
+
#**
|
|
321
|
+
|
|
322
|
+
def join_on(joinType, table, condition)
|
|
323
|
+
@joins << ("#{joinType} join #{table} on "\
|
|
324
|
+
"(#{Translate.substitute_values(condition)})")
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
# Add a "cross join" to this statement.
|
|
328
|
+
#
|
|
329
|
+
# Example:
|
|
330
|
+
#** Example: select_cross_join
|
|
331
|
+
# select = Select.new
|
|
332
|
+
# select.select('i')
|
|
333
|
+
# select.from('foo')
|
|
334
|
+
# select.cross_join('bar')
|
|
335
|
+
# p select.statement # "select i from foo cross join bar"
|
|
336
|
+
#**
|
|
337
|
+
|
|
338
|
+
def cross_join(table)
|
|
339
|
+
@joins << "cross join #{table}"
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
# Add an "order by" to this statement. You can call this as many
|
|
343
|
+
# times as you need.
|
|
344
|
+
#
|
|
345
|
+
# [expression]
|
|
346
|
+
# A string or array that will be converted by #substitute_values
|
|
347
|
+
# and inserted into the statement.
|
|
348
|
+
# [ordering]
|
|
349
|
+
# One of:
|
|
350
|
+
# 'asc':: ascending
|
|
351
|
+
# 'desc':: descending
|
|
352
|
+
# nil:: default ordering, which is ascending
|
|
353
|
+
#
|
|
354
|
+
# Example:
|
|
355
|
+
#** Example: select_order_by
|
|
356
|
+
# select = Select.new
|
|
357
|
+
# select.select('i')
|
|
358
|
+
# select.select('j')
|
|
359
|
+
# select.from('foo')
|
|
360
|
+
# select.order_by('i')
|
|
361
|
+
# select.order_by('j', 'desc')
|
|
362
|
+
# p select.statement # "select i, j from foo order by i, j desc"
|
|
363
|
+
#**
|
|
364
|
+
|
|
365
|
+
def order_by(expression, ordering = nil)
|
|
366
|
+
@order_by <<
|
|
367
|
+
[Translate.substitute_values(expression), ordering].compact.join(' ')
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
# Add a "where" condition to this statement.
|
|
371
|
+
#
|
|
372
|
+
# [expression]
|
|
373
|
+
# The condition. Should be one of:
|
|
374
|
+
# [A string] The expression
|
|
375
|
+
# [An array] An expression converted using #substitute_values
|
|
376
|
+
#
|
|
377
|
+
# Example (string)
|
|
378
|
+
#** Example: select_where_string
|
|
379
|
+
# select = Select.new
|
|
380
|
+
# select.select('i')
|
|
381
|
+
# select.from('foo')
|
|
382
|
+
# select.where('i > 0')
|
|
383
|
+
# p select.statement # "select i from foo where i > 0"
|
|
384
|
+
#**
|
|
385
|
+
#
|
|
386
|
+
# Example (array)
|
|
387
|
+
#** Example: select_where_array
|
|
388
|
+
# select = Select.new
|
|
389
|
+
# select.select('age')
|
|
390
|
+
# select.from('person')
|
|
391
|
+
# select.where(['name = %s', 'Smith'])
|
|
392
|
+
# p select.statement # "select age from person where name =
|
|
393
|
+
# # E'Smith'"
|
|
394
|
+
#**
|
|
395
|
+
#
|
|
396
|
+
# Example (in)
|
|
397
|
+
#** Example: select_where_in
|
|
398
|
+
# select = Select.new
|
|
399
|
+
# select.select('s')
|
|
400
|
+
# select.from('foo')
|
|
401
|
+
# select.where(['s in %s', [:in, 'foo', 'bar']])
|
|
402
|
+
# p select.statement # "select s from foo where s in (E'foo',
|
|
403
|
+
# # E'bar')"
|
|
404
|
+
#**
|
|
405
|
+
|
|
406
|
+
def where(expression)
|
|
407
|
+
@where << Translate.substitute_values(expression)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
# Add a "group by" to this statement.
|
|
411
|
+
#
|
|
412
|
+
# [expression]
|
|
413
|
+
# A string or array that will be converted by #substitute_values
|
|
414
|
+
# and inserted into the statement.
|
|
415
|
+
#
|
|
416
|
+
# Example
|
|
417
|
+
#** Example: select_group_by
|
|
418
|
+
# select = Select.new
|
|
419
|
+
# select.select('i')
|
|
420
|
+
# select.select('count(*)', 'count')
|
|
421
|
+
# select.from('foo')
|
|
422
|
+
# select.group_by('i')
|
|
423
|
+
# p select.statement # "select i, count(*) as count from foo group
|
|
424
|
+
# # by i"
|
|
425
|
+
#**
|
|
426
|
+
|
|
427
|
+
def group_by(expression)
|
|
428
|
+
@group_by << Translate.substitute_values(expression)
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
# Add a "having" clause to this statement.
|
|
432
|
+
#
|
|
433
|
+
# [expression]
|
|
434
|
+
# A string or array that will be converted by #substitute_values
|
|
435
|
+
# and inserted into the statement.
|
|
436
|
+
#
|
|
437
|
+
# Example
|
|
438
|
+
#** Example: select_having
|
|
439
|
+
# select = Select.new
|
|
440
|
+
# select.select('i')
|
|
441
|
+
# select.select('count(*)', 'count')
|
|
442
|
+
# select.from('foo')
|
|
443
|
+
# select.group_by('i')
|
|
444
|
+
# select.having('i < 10')
|
|
445
|
+
# p select.statement # "select i, count(*) as count from foo
|
|
446
|
+
# # group by i having i < 10"
|
|
447
|
+
#**
|
|
448
|
+
|
|
449
|
+
def having(expression)
|
|
450
|
+
@having << Translate.substitute_values(expression)
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
# Add a "limit" clause to the statement.
|
|
454
|
+
#
|
|
455
|
+
# Example:
|
|
456
|
+
#** Example: select_limit
|
|
457
|
+
# select = Select.new
|
|
458
|
+
# select.select('i')
|
|
459
|
+
# select.from('foo')
|
|
460
|
+
# select.order_by('i')
|
|
461
|
+
# select.limit(1)
|
|
462
|
+
# p select.statement # "select i from foo order by i limit 1"
|
|
463
|
+
#**
|
|
464
|
+
|
|
465
|
+
def limit(value)
|
|
466
|
+
@limit = value
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
# Add an "offset" clause to the statement.
|
|
470
|
+
#
|
|
471
|
+
# Example:
|
|
472
|
+
#** Example: select_offset
|
|
473
|
+
# select = Select.new
|
|
474
|
+
# select.select('i')
|
|
475
|
+
# select.from('foo')
|
|
476
|
+
# select.order_by('i')
|
|
477
|
+
# select.offset(1)
|
|
478
|
+
# p select.statement # "select i from foo order by i offset 1"
|
|
479
|
+
#**
|
|
480
|
+
|
|
481
|
+
def offset(value)
|
|
482
|
+
@offset = value
|
|
483
|
+
end
|
|
484
|
+
|
|
485
|
+
# Add "for update" to the statement.
|
|
486
|
+
#
|
|
487
|
+
# Example:
|
|
488
|
+
#** Example: select_for_update
|
|
489
|
+
# select = Select.new
|
|
490
|
+
# select.select('i')
|
|
491
|
+
# select.from('foo')
|
|
492
|
+
# select.for_update
|
|
493
|
+
# p select.statement # "select i from foo for update"
|
|
494
|
+
#**
|
|
495
|
+
|
|
496
|
+
def for_update
|
|
497
|
+
@for_update = true
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
# Return the SQL statement.
|
|
501
|
+
|
|
502
|
+
def statement
|
|
503
|
+
"select#{distinct_clause} #{expression_list}"\
|
|
504
|
+
"#{tableExpression}#{join_clause}"\
|
|
505
|
+
"#{where_clause}#{set_ops_clause}#{group_by_clause}#{having_clause}#{order_by_clause}"\
|
|
506
|
+
"#{limit_clause}#{offset_clause}#{for_update_clause}"
|
|
507
|
+
end
|
|
508
|
+
|
|
509
|
+
# Execute the statement and return an array of hashes with the result.
|
|
510
|
+
#
|
|
511
|
+
# [connection]
|
|
512
|
+
# If present, the connection to use.
|
|
513
|
+
# If nil, uses the connection passed to new or, if no connection was
|
|
514
|
+
# passed to new, uses the default connection.
|
|
515
|
+
|
|
516
|
+
def exec(connection = @connection)
|
|
517
|
+
query_and_translate(connection, statement)
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
# Fetch a row or rows from the cursor. Not intended for consumer
|
|
521
|
+
# use; it's hanging out here in public for the use of the Cursor
|
|
522
|
+
# class.
|
|
523
|
+
#
|
|
524
|
+
# [cursor_name]
|
|
525
|
+
# The cursor's name
|
|
526
|
+
# [direction]
|
|
527
|
+
# A string specifying which row or rows to fetch (see Cursor.fetch)
|
|
528
|
+
# [connection]
|
|
529
|
+
# If present, the connection to use.
|
|
530
|
+
# If nil, uses the connection passed to new or, if no connection was
|
|
531
|
+
# passed to new, uses the default connection.
|
|
532
|
+
|
|
533
|
+
def fetch_by_cursor(cursor_name, direction, connection = @connection)
|
|
534
|
+
statement = "fetch #{direction} from #{cursor_name}"
|
|
535
|
+
query_and_translate(connection, statement)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
private
|
|
539
|
+
|
|
540
|
+
Column = Struct.new(:value, :as, :converter)
|
|
541
|
+
|
|
542
|
+
# OIDs for Postgresql data types. These must match
|
|
543
|
+
# postgresql/server/catalog/pg_type.h.
|
|
544
|
+
|
|
545
|
+
module Types
|
|
546
|
+
BOOLEAN = 16
|
|
547
|
+
BYTEA = 17
|
|
548
|
+
QCHAR = 18
|
|
549
|
+
NAME = 19
|
|
550
|
+
BIGINT = INT8 = BIGSERIAL = SERIAL8 = 20
|
|
551
|
+
SMALLINT = 21
|
|
552
|
+
INTEGER = INT = INT4 = SERIAL = 23
|
|
553
|
+
TEXT = 25
|
|
554
|
+
OID = 26
|
|
555
|
+
POINT = 600
|
|
556
|
+
LSEG = 601
|
|
557
|
+
PATH = 602
|
|
558
|
+
BOX = 603
|
|
559
|
+
POLYGON = 604
|
|
560
|
+
CIDR = 650
|
|
561
|
+
ARRAY_CIDR = 651
|
|
562
|
+
REAL = 700
|
|
563
|
+
DOUBLE_PRECISION = FLOAT8 = 701
|
|
564
|
+
UNKNOWN = 705
|
|
565
|
+
CIRCLE = 718
|
|
566
|
+
ARRAY_CIRCLE = 719
|
|
567
|
+
MACADDR = 829
|
|
568
|
+
INET = 869
|
|
569
|
+
ARRAY_BOOLEAN = 1000
|
|
570
|
+
ARRAY_BYTEA = 1001
|
|
571
|
+
ARRAY_QCHAR = 1002
|
|
572
|
+
ARRAY_NAME = 1003
|
|
573
|
+
ARRAY_SMALLINT = 1005
|
|
574
|
+
ARRAY_INTEGER = 1007
|
|
575
|
+
ARRAY_TEXT = 1009
|
|
576
|
+
ARRAY_CHARACTER = 1014
|
|
577
|
+
ARRAY_VARCHAR = 1015
|
|
578
|
+
ARRAY_BIGINT = 1016
|
|
579
|
+
ARRAY_POINT = 1017
|
|
580
|
+
ARRAY_LSEG = 1018
|
|
581
|
+
ARRAY_PATH = 1019
|
|
582
|
+
ARRAY_BOX = 1020
|
|
583
|
+
ARRAY_REAL = 1021
|
|
584
|
+
ARRAY_DOUBLE_PRECISION = 1022
|
|
585
|
+
ARRAY_POLYGON = 1027
|
|
586
|
+
ARRAY_MACADDR = 1040
|
|
587
|
+
ARRAY_INET = 1041
|
|
588
|
+
CHARACTER = CHAR = 1042
|
|
589
|
+
VARCHAR = CHARACTER_VARYING = 1043
|
|
590
|
+
DATE = 1082
|
|
591
|
+
TIME = 1083
|
|
592
|
+
TIMESTAMP = TIMESTAMP_WITHOUT_TIME_ZONE = 1114
|
|
593
|
+
ARRAY_TIMESTAMP = 1115
|
|
594
|
+
ARRAY_DATE = 1182
|
|
595
|
+
ARRAY_TIME = 1183
|
|
596
|
+
TIMESTAMP_WITH_TIME_ZONE = 1184
|
|
597
|
+
ARRAY_TIMESTAMP_WITH_TIME_ZONE = 1185
|
|
598
|
+
INTERVAL = 1186
|
|
599
|
+
ARRAY_INTERVAL = 1187
|
|
600
|
+
ARRAY_NUMERIC = 1231
|
|
601
|
+
TIME_WITH_TIME_ZONE = 1266
|
|
602
|
+
ARRAY_TIME_WITH_TIME_ZONE = 1270
|
|
603
|
+
BIT = 1560
|
|
604
|
+
ARRAY_BIT = 1561
|
|
605
|
+
VARBIT = 1562
|
|
606
|
+
ARRAY_VARBIT = 1563
|
|
607
|
+
NUMERIC = DECIMAL = 1700
|
|
608
|
+
end
|
|
609
|
+
|
|
610
|
+
# Converters used to translate strings into Ruby types.
|
|
611
|
+
|
|
612
|
+
BitConverter = proc { |s| PgBit.from_sql(s) }
|
|
613
|
+
BooleanConverter = proc { |s| s == 't' }
|
|
614
|
+
BoxConverter = proc { |s| PgBox.from_sql(s) }
|
|
615
|
+
ByteaConverter = proc { |s| Translate.unescape_bytea(s) }
|
|
616
|
+
CidrConverter = proc { |s| PgCidr.from_sql(s) }
|
|
617
|
+
CircleConverter = proc { |s| PgCircle.from_sql(s) }
|
|
618
|
+
DateConverter = proc { |s| Translate.sql_to_date(s) }
|
|
619
|
+
FloatConverter = proc { |s| s.to_f }
|
|
620
|
+
InetConverter = proc { |s| PgInet.from_sql(s) }
|
|
621
|
+
IntegerConverter = proc { |s| s.to_i }
|
|
622
|
+
IntervalConverter = proc { |s| PgInterval.from_sql(s) }
|
|
623
|
+
LsegConverter = proc { |s| PgLineSegment.from_sql(s) }
|
|
624
|
+
MacAddrConverter = proc { |s| PgMacAddr.from_sql(s) }
|
|
625
|
+
PathConverter = proc { |s| PgPath.from_sql(s) }
|
|
626
|
+
PointConverter = proc { |s| PgPoint.from_sql(s) }
|
|
627
|
+
PolygonConverter = proc { |s| PgPolygon.from_sql(s) }
|
|
628
|
+
QCharConverter = proc { |s| Translate.unescape_qchar(s) }
|
|
629
|
+
StringConverter = proc { |s| s }
|
|
630
|
+
TimeConverter = proc { |s| PgTime.from_sql(s) }
|
|
631
|
+
TimeStringConverter = proc { |s| Time.local(*s.split(/:/)) }
|
|
632
|
+
TimeWithTimeZoneConverter = proc { |s| PgTimeWithTimeZone.from_sql(s) }
|
|
633
|
+
TimestampConverter = proc { |s| PgTimestamp.from_sql(s) }
|
|
634
|
+
TimestampTzConverter = proc { |s| Translate.sql_to_datetime(s) }
|
|
635
|
+
|
|
636
|
+
# Map each base (non-array) type to a converter.
|
|
637
|
+
|
|
638
|
+
CONVERTERS = {
|
|
639
|
+
Types::BIGINT => IntegerConverter,
|
|
640
|
+
Types::BIT => BitConverter,
|
|
641
|
+
Types::BOOLEAN => BooleanConverter,
|
|
642
|
+
Types::BOX => BoxConverter,
|
|
643
|
+
Types::BYTEA => ByteaConverter,
|
|
644
|
+
Types::CHARACTER => StringConverter,
|
|
645
|
+
Types::CIDR => CidrConverter,
|
|
646
|
+
Types::CIRCLE => CircleConverter,
|
|
647
|
+
Types::DATE => DateConverter,
|
|
648
|
+
Types::DOUBLE_PRECISION => FloatConverter,
|
|
649
|
+
Types::INET => InetConverter,
|
|
650
|
+
Types::INTEGER => IntegerConverter,
|
|
651
|
+
Types::INTERVAL => IntervalConverter,
|
|
652
|
+
Types::LSEG => LsegConverter,
|
|
653
|
+
Types::MACADDR => MacAddrConverter,
|
|
654
|
+
Types::NAME => StringConverter,
|
|
655
|
+
Types::NUMERIC => FloatConverter,
|
|
656
|
+
Types::OID => IntegerConverter,
|
|
657
|
+
Types::PATH => PathConverter,
|
|
658
|
+
Types::POINT => PointConverter,
|
|
659
|
+
Types::POLYGON => PolygonConverter,
|
|
660
|
+
Types::QCHAR => QCharConverter,
|
|
661
|
+
Types::REAL => FloatConverter,
|
|
662
|
+
Types::SMALLINT => IntegerConverter,
|
|
663
|
+
Types::TEXT => StringConverter,
|
|
664
|
+
Types::TIME => TimeConverter,
|
|
665
|
+
Types::TIMESTAMP => TimestampConverter,
|
|
666
|
+
Types::TIMESTAMP_WITH_TIME_ZONE => TimestampTzConverter,
|
|
667
|
+
Types::TIME_WITH_TIME_ZONE => TimeWithTimeZoneConverter,
|
|
668
|
+
Types::UNKNOWN => StringConverter,
|
|
669
|
+
Types::VARBIT => BitConverter,
|
|
670
|
+
Types::VARCHAR => StringConverter,
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
# Map each array type to its base type.
|
|
674
|
+
|
|
675
|
+
ARRAY_ELEMENT_TYPES = {
|
|
676
|
+
Types::ARRAY_BIGINT => Types::BIGINT,
|
|
677
|
+
Types::ARRAY_BIT => Types::BIT,
|
|
678
|
+
Types::ARRAY_BOOLEAN => Types::BOOLEAN,
|
|
679
|
+
Types::ARRAY_BOX => Types::BOX,
|
|
680
|
+
Types::ARRAY_BYTEA => Types::BYTEA,
|
|
681
|
+
Types::ARRAY_CHARACTER => Types::CHARACTER,
|
|
682
|
+
Types::ARRAY_INET => Types::INET,
|
|
683
|
+
Types::ARRAY_CIDR => Types::CIDR,
|
|
684
|
+
Types::ARRAY_CIRCLE => Types::CIRCLE,
|
|
685
|
+
Types::ARRAY_DATE => Types::DATE,
|
|
686
|
+
Types::ARRAY_DOUBLE_PRECISION => Types::DOUBLE_PRECISION,
|
|
687
|
+
Types::ARRAY_INTEGER => Types::INTEGER,
|
|
688
|
+
Types::ARRAY_INTERVAL => Types::INTERVAL,
|
|
689
|
+
Types::ARRAY_LSEG => Types::LSEG,
|
|
690
|
+
Types::ARRAY_MACADDR => Types::MACADDR,
|
|
691
|
+
Types::ARRAY_NAME => Types::NAME,
|
|
692
|
+
Types::ARRAY_NUMERIC => Types::NUMERIC,
|
|
693
|
+
Types::ARRAY_PATH => Types::PATH,
|
|
694
|
+
Types::ARRAY_POINT => Types::POINT,
|
|
695
|
+
Types::ARRAY_POLYGON => Types::POLYGON,
|
|
696
|
+
Types::ARRAY_QCHAR => Types::QCHAR,
|
|
697
|
+
Types::ARRAY_REAL => Types::REAL,
|
|
698
|
+
Types::ARRAY_SMALLINT => Types::SMALLINT,
|
|
699
|
+
Types::ARRAY_TEXT => Types::TEXT,
|
|
700
|
+
Types::ARRAY_TIME => Types::TIME,
|
|
701
|
+
Types::ARRAY_TIMESTAMP => Types::TIMESTAMP,
|
|
702
|
+
Types::ARRAY_TIMESTAMP_WITH_TIME_ZONE => Types::TIMESTAMP_WITH_TIME_ZONE,
|
|
703
|
+
Types::ARRAY_TIME_WITH_TIME_ZONE => Types::TIME_WITH_TIME_ZONE,
|
|
704
|
+
Types::ARRAY_VARBIT => Types::VARBIT,
|
|
705
|
+
Types::ARRAY_VARCHAR => Types::VARCHAR,
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
AutoConverter = proc { |s, type_code|
|
|
709
|
+
array_element_type = ARRAY_ELEMENT_TYPES[type_code]
|
|
710
|
+
if !array_element_type.nil?
|
|
711
|
+
s = Translate.sql_to_array(s)
|
|
712
|
+
type_code = array_element_type
|
|
713
|
+
end
|
|
714
|
+
converter = CONVERTERS[type_code] || StringConverter
|
|
715
|
+
Translate.deep_collect(s) do |e|
|
|
716
|
+
converter.call(e)
|
|
717
|
+
end
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
def data_type_for(value, as)
|
|
721
|
+
return nil if as.nil?
|
|
722
|
+
if value.is_a?(Float)
|
|
723
|
+
'float'
|
|
724
|
+
elsif value.is_a?(Integer)
|
|
725
|
+
'integer'
|
|
726
|
+
elsif value == true || value == false
|
|
727
|
+
'boolean'
|
|
728
|
+
elsif value.is_a?(Time)
|
|
729
|
+
'time'
|
|
730
|
+
else
|
|
731
|
+
'string'
|
|
732
|
+
end
|
|
733
|
+
end
|
|
734
|
+
|
|
735
|
+
def distinct_clause
|
|
736
|
+
if @distinct
|
|
737
|
+
" distinct"
|
|
738
|
+
elsif !@distinct_on.empty?
|
|
739
|
+
" distinct on (#{@distinct_on.join(', ')})"
|
|
740
|
+
else
|
|
741
|
+
""
|
|
742
|
+
end
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
def add_set_op(op, select)
|
|
746
|
+
@set_ops << [op, select.statement]
|
|
747
|
+
end
|
|
748
|
+
|
|
749
|
+
def expression_list
|
|
750
|
+
@columns.collect do |column|
|
|
751
|
+
[column.value, column.as].compact.join(' as ')
|
|
752
|
+
end.join(', ')
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
def tableExpression
|
|
756
|
+
if @tables.empty?
|
|
757
|
+
""
|
|
758
|
+
else
|
|
759
|
+
" from #{@tables.join(', ')}"
|
|
760
|
+
end
|
|
761
|
+
end
|
|
762
|
+
|
|
763
|
+
def join_clause
|
|
764
|
+
if @joins.empty?
|
|
765
|
+
""
|
|
766
|
+
else
|
|
767
|
+
" " + @joins.join(' ')
|
|
768
|
+
end
|
|
769
|
+
end
|
|
770
|
+
|
|
771
|
+
def set_ops_clause
|
|
772
|
+
if @set_ops.empty?
|
|
773
|
+
""
|
|
774
|
+
else
|
|
775
|
+
' ' + @set_ops.collect do |op, statement|
|
|
776
|
+
"#{op} (#{statement})"
|
|
777
|
+
end.join(' ')
|
|
778
|
+
end
|
|
779
|
+
end
|
|
780
|
+
|
|
781
|
+
def random_order?
|
|
782
|
+
ENV['RANDOM_SQL_ORDER'] && !@distinct && @distinct_on.empty? && @set_ops.empty?
|
|
783
|
+
end
|
|
784
|
+
|
|
785
|
+
def order_by_clause
|
|
786
|
+
order = @order_by.dup
|
|
787
|
+
order << 'random()' if random_order?
|
|
788
|
+
if order.empty?
|
|
789
|
+
""
|
|
790
|
+
else
|
|
791
|
+
" order by " + order.join(', ')
|
|
792
|
+
end
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def limit_clause
|
|
796
|
+
if @limit.nil?
|
|
797
|
+
""
|
|
798
|
+
else
|
|
799
|
+
" limit #{@limit}"
|
|
800
|
+
end
|
|
801
|
+
end
|
|
802
|
+
|
|
803
|
+
def offset_clause
|
|
804
|
+
if @offset.nil?
|
|
805
|
+
""
|
|
806
|
+
else
|
|
807
|
+
" offset #{@offset}"
|
|
808
|
+
end
|
|
809
|
+
end
|
|
810
|
+
|
|
811
|
+
def for_update_clause
|
|
812
|
+
if @for_update
|
|
813
|
+
" for update"
|
|
814
|
+
else
|
|
815
|
+
""
|
|
816
|
+
end
|
|
817
|
+
end
|
|
818
|
+
|
|
819
|
+
def where_clause
|
|
820
|
+
if @where.empty?
|
|
821
|
+
""
|
|
822
|
+
else
|
|
823
|
+
" where " + @where.join(' and ')
|
|
824
|
+
end
|
|
825
|
+
end
|
|
826
|
+
|
|
827
|
+
def group_by_clause
|
|
828
|
+
if @group_by.empty?
|
|
829
|
+
""
|
|
830
|
+
else
|
|
831
|
+
" group by " + @group_by.join(', ')
|
|
832
|
+
end
|
|
833
|
+
end
|
|
834
|
+
|
|
835
|
+
def having_clause
|
|
836
|
+
if @having.empty?
|
|
837
|
+
""
|
|
838
|
+
else
|
|
839
|
+
" having " + @having.join(' and ')
|
|
840
|
+
end
|
|
841
|
+
end
|
|
842
|
+
|
|
843
|
+
def query_and_translate(connection, statement)
|
|
844
|
+
connection.exec_and_translate(statement, @columns)
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
end
|
|
850
|
+
|
|
851
|
+
# Local Variables:
|
|
852
|
+
# tab-width: 2
|
|
853
|
+
# ruby-indent-level: 2
|
|
854
|
+
# indent-tabs-mode: nil
|
|
855
|
+
# End:
|