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,198 @@
1
+ module SqlPostgres
2
+
3
+ # This class holds a connection to the database.
4
+
5
+ class Connection
6
+
7
+ require 'pg'
8
+
9
+ # If true, then PGError exceptions have the offending statement
10
+ # added to them.
11
+
12
+ attr_accessor 'statement_in_exception'
13
+
14
+ # The underlying instance of PGconn. This is for when PGconn does
15
+ # something that this library doesn't do.
16
+
17
+ attr_reader :pgconn
18
+
19
+ @@pgClass = PG
20
+ @@default = nil
21
+
22
+ # Get the default connection. If there isn't one, returns the
23
+ # NullConnection instead.
24
+
25
+ def Connection.default
26
+ if @@default.nil?
27
+ NullConnection.new
28
+ else
29
+ @@default
30
+ end
31
+ end
32
+
33
+ # Set the default connection.
34
+
35
+ def Connection.default=(value)
36
+ @@default = value
37
+ end
38
+
39
+ # Open a connection, pass it to the block, then close it.
40
+ # The connection is closed even if an exception occurs.
41
+ # Returns the result of the block.
42
+ #
43
+ # Takes the same arguments as new.
44
+ #
45
+ # Note: If an exception occurs, then any exception from closing
46
+ # the connection is ignored. This is to avoid masking the original
47
+ # (and presumably more important) exception.
48
+
49
+ def Connection.open(*args)
50
+ connection = Connection.new(*args)
51
+ begin
52
+ result = yield(connection)
53
+ rescue
54
+ begin
55
+ connection.close
56
+ rescue
57
+ end
58
+ raise
59
+ else
60
+ connection.close
61
+ end
62
+ result
63
+ end
64
+
65
+ # Create a connection.
66
+ #
67
+ # To create a new connection, pass zero or more of the following
68
+ # arguments They get passed through to PGconn.connect.
69
+ #
70
+ # 'host_name'::
71
+ # The host to connect to. Defaults to 'localhost'
72
+ # 'port'::
73
+ # The port to connect to. Defaults to 5432
74
+ # 'options'::
75
+ # Back end options. Defaults to ''
76
+ # 'tty'::
77
+ # Name of TTY for back end messages. Defaults to ''
78
+ # 'db_name'::
79
+ # Database name. '', the default, means to use the database
80
+ # with the same name as the user.
81
+ # 'login'::
82
+ # Login name. nil, the default, means to use the user's name.
83
+ # to nil.
84
+ # 'password'::
85
+ # Password. nil, the default, means no password.
86
+ #
87
+ # To wrap an existing connection, pass this argument:
88
+ #
89
+ # 'connection'::
90
+ # The PGConn instance to wrap.
91
+ #
92
+ # The following arguments influence SqlPostgres's behavior;
93
+ # they're not actually used to establish the connection to postgres:
94
+ #
95
+ # 'statement_in_exception'::
96
+ # If true, add the offending statement PGError exceptions. Defaults
97
+ # to true.
98
+
99
+ def initialize(args = {})
100
+ raise ArgumentError, "Block not allowed" if block_given?
101
+ @pgconn = args['connection']
102
+ if @pgconn.nil?
103
+ hostName = args['host_name'] || "localhost"
104
+ dbName = args['db_name'] || ""
105
+ port = args['port'] || 5432
106
+ options = args['options'] || ""
107
+ tty = args['tty'] || ""
108
+ login = args['login']
109
+ password = args['password']
110
+ @pgconn = @@pgClass.connect(hostName, port, options, tty, dbName,
111
+ login, password)
112
+ end
113
+ @statement_in_exception = args['statement_in_exception']
114
+ @statement_in_exception = true if @statement_in_exception.nil?
115
+ @pgconn.set_client_encoding("unicode")
116
+ end
117
+
118
+ # close the connection. If it's already closed, do nothing.
119
+
120
+ def close
121
+ return if @pgconn.nil?
122
+ @pgconn.close
123
+ @pgconn = nil
124
+ end
125
+
126
+ # Send an SQL statement to the backend. Returns a PGResult. This
127
+ # is just a thin wrapper around PGConn.exec, and exists for when
128
+ # you want to do some SQL that Insert, Update, Select, or
129
+ # Transaction won't do for you (ie, "create temporary table").
130
+ #
131
+ # If a PGError exception occurs and statement_in_exception is
132
+ # true, then statement is added to the exception.
133
+
134
+ def exec(statement)
135
+ begin
136
+ @pgconn.exec(statement)
137
+ rescue PGError => e
138
+ if statement_in_exception
139
+ e = e.exception(e.message +
140
+ "The offending statement is: #{statement.inspect}")
141
+ end
142
+ raise e
143
+ end
144
+ end
145
+
146
+ # Send an SQL statement to the backend. Returns an array of arrays.
147
+ #
148
+ # If a PGError exception occurs and statement_in_exception is
149
+ # true, then statement is added to the exception.
150
+
151
+ def query(statement)
152
+ result = exec(statement)
153
+ result.send(result_method(result))
154
+ end
155
+
156
+ # This is a hook for rspec (mock this method to find out what sql
157
+ # is being executed, and to inject translated results).
158
+
159
+ def exec_and_translate(statement, columns)
160
+ translate_pgresult(exec(statement), columns)
161
+ end
162
+
163
+ private
164
+
165
+ def result_method(result)
166
+ if result.respond_to?(:result)
167
+ :result
168
+ else
169
+ :values
170
+ end
171
+ end
172
+
173
+ def translate_pgresult(pgresult, columns)
174
+ pgresult.values.collect do |row|
175
+ hash = {}
176
+ columns.each_with_index do |column, i|
177
+ unless column.converter.nil?
178
+ typeCode = pgresult.ftype(i)
179
+ value = row[i]
180
+ args = [value]
181
+ args << typeCode if column.converter.arity == 2
182
+ hash[column.as || column.value] =
183
+ value && column.converter.call(*args)
184
+ end
185
+ end
186
+ hash
187
+ end
188
+ end
189
+
190
+ end
191
+
192
+ end
193
+
194
+ # Local Variables:
195
+ # tab-width: 2
196
+ # ruby-indent-level: 2
197
+ # indent-tabs-mode: nil
198
+ # End:
@@ -0,0 +1,157 @@
1
+ module SqlPostgres
2
+
3
+ # This class creates and manages a cursor.
4
+ #
5
+ # Example:
6
+ #** example: cursor
7
+ # Transaction.new(connection) do
8
+ # select = Select.new(connection)
9
+ # select.select('i')
10
+ # select.from('foo')
11
+ # Cursor.new('my_cursor', select, {}, connection) do |cursor|
12
+ # while !(rows = cursor.fetch).empty?
13
+ # for row in rows
14
+ # p row # {"i"=>0}
15
+ # # {"i"=>1}
16
+ # # {"i"=>2}
17
+ # # {"i"=>3}
18
+ # # {"i"=>4}
19
+ # end
20
+ # end
21
+ # end
22
+ # end
23
+ #**
24
+ #
25
+ # Fetching a single row at a time, the default for fetch, is slow.
26
+ # Usually you will want to speed things up by calling, for example,
27
+ # fetch(1000).
28
+
29
+ class Cursor
30
+
31
+ # Create a cursor. If a block is given, yield the cursor to the
32
+ # block, closing the cursor when the block returns, and returning
33
+ # results of the block.
34
+ #
35
+ # If no connection is given, then the default connection is used.
36
+ #
37
+ # [name]
38
+ # The cursor's name
39
+ # [select]
40
+ # a Select statement
41
+ # [opts]
42
+ # Options hash. Keys are:
43
+ # :scroll=>(boolean) If true, create a SCROLL cursor. If false,
44
+ # create a NO SCROLL cursor. If not specified,
45
+ # the default is to allow scrolling in cases
46
+ # where performance will not suffer.
47
+ # :hold=>(boolean) If true, create a WITH HOLD cursor. If
48
+ # false, create a HOLD cursor. WITHOUT HOLD
49
+ # is the default. A HOLD cursor can be used
50
+ # outside of the transaction that created it.
51
+ # [connection]
52
+ # The database connection
53
+
54
+ def initialize(name, select, opts = {}, connection = Connection.default)
55
+ if block_given?
56
+ cursor = self.class.new(name, select, opts, connection)
57
+ result = yield(cursor)
58
+ cursor.close
59
+ result
60
+ else
61
+ @name = name
62
+ @select = select
63
+ @opts = opts
64
+ @connection = connection
65
+ declare_cursor
66
+ end
67
+ end
68
+
69
+ # Fetch a row or rows from the cursor.
70
+ #
71
+ # [direction]
72
+ # A string specifying which row or rows to fetch. See the
73
+ # postgres documentation for the "DECLARE" statement.
74
+ # NEXT
75
+ # PRIOR
76
+ # FIRST
77
+ # LAST
78
+ # ABSOLUTE count
79
+ # RELATIVE count
80
+ # count
81
+ # ALL
82
+ # FORWARD
83
+ # FORWARD count
84
+ # FORWARD ALL
85
+ # BACKWARD
86
+ # BACKWARD count
87
+ # BACKWARD ALL
88
+
89
+ def fetch(direction = 'NEXT')
90
+ @select.fetch_by_cursor(@name, direction, @connection)
91
+ end
92
+
93
+ # Seek a cursor. Works exactly the same (and takes the same
94
+ # arguments) as fetch, but returns no rows.
95
+ #
96
+ # [direction]
97
+ # See #fetch
98
+
99
+ def move(direction = 'NEXT')
100
+ statement = "move #{direction} from #{@name}"
101
+ @connection.exec(statement)
102
+ end
103
+
104
+ # Close the cursor. Once closed, it may closed or fetched from
105
+ # again.
106
+
107
+ def close
108
+ statement = "close #{@name}"
109
+ @connection.exec(statement)
110
+ end
111
+
112
+ private
113
+
114
+ def declare_cursor
115
+ statement = [
116
+ 'declare',
117
+ @name,
118
+ scroll_declaration,
119
+ 'cursor',
120
+ hold_declaration,
121
+ 'for',
122
+ @select.statement
123
+ ].compact.join(' ')
124
+ @connection.exec(statement)
125
+ end
126
+
127
+ def scroll_declaration
128
+ value = @opts.fetch(:scroll, :default)
129
+ if value == :default
130
+ nil
131
+ elsif value
132
+ "SCROLL"
133
+ else
134
+ "NO SCROLL"
135
+ end
136
+ end
137
+
138
+ def hold_declaration
139
+ value = @opts.fetch(:hold, :default)
140
+ if value == :default
141
+ nil
142
+ elsif value
143
+ "WITH HOLD"
144
+ else
145
+ "WITHOUT HOLD"
146
+ end
147
+ end
148
+
149
+ end
150
+
151
+ end
152
+
153
+ # Local Variables:
154
+ # tab-width: 2
155
+ # ruby-indent-level: 2
156
+ # indent-tabs-mode: nil
157
+ # End:
@@ -0,0 +1,67 @@
1
+ module SqlPostgres
2
+
3
+ # This class creates and executes an SQL delete statement.
4
+
5
+ class Delete
6
+
7
+ # Create a delete statement
8
+ #
9
+ # [table]
10
+ # The table name
11
+ # [connection]
12
+ # If supplied, the connection to use. If not supplied, use the
13
+ # default.
14
+
15
+ def initialize(table, connection = Connection.default)
16
+ @table = table
17
+ @connection = connection
18
+ @where = []
19
+ end
20
+
21
+ # Add a "where" condition to this statement.
22
+ #
23
+ # [expression]
24
+ # The condition. Should be one of:
25
+ # [A string] The expression
26
+ # [An array] An expression converted using #substitute_values
27
+
28
+ def where(expression)
29
+ @where << Translate.substitute_values(expression)
30
+ end
31
+
32
+ # Return the SQL statement
33
+
34
+ def statement
35
+ "delete from #{@table}#{where_clause}"
36
+ end
37
+
38
+ # Execute the delete statement
39
+ #
40
+ # [connection]
41
+ # If present, the connection to use.
42
+ # If nil, uses the connection passed to new, or if no connection was
43
+ # passed to new, uses the default connection.
44
+
45
+ def exec(connection = @connection)
46
+ connection.exec(statement)
47
+ end
48
+
49
+ private
50
+
51
+ def where_clause
52
+ if @where.empty?
53
+ ""
54
+ else
55
+ " where " + @where.join(' and ')
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ end
62
+
63
+ # Local Variables:
64
+ # tab-width: 2
65
+ # ruby-indent-level: 2
66
+ # indent-tabs-mode: nil
67
+ # End:
@@ -0,0 +1,15 @@
1
+ module SqlPostgres
2
+
3
+ # A function requiring a database connection was called, but the object
4
+ # didn't have a database connection.
5
+
6
+ class NoConnection < Exception
7
+ end
8
+
9
+ end
10
+
11
+ # Local Variables:
12
+ # tab-width: 2
13
+ # ruby-indent-level: 2
14
+ # indent-tabs-mode: nil
15
+ # End:
@@ -0,0 +1,279 @@
1
+ module SqlPostgres
2
+
3
+ # This class creates and executes an SQL insert statement.
4
+ #
5
+ # Example:
6
+ #** Example: insert
7
+ # insert = Insert.new('foo', connection)
8
+ # insert.insert('i', 1)
9
+ # insert.insert('t', 'foo')
10
+ # p insert.statement # "insert into foo (i, t) values (1,
11
+ # # E'foo')"
12
+ # insert.exec
13
+ #**
14
+
15
+ class Insert
16
+
17
+ # Create an insert statement
18
+ #
19
+ # [table]
20
+ # The table name
21
+ # [connection]
22
+ # If supplied, the connection to use. If not supplied, use the
23
+ # default.
24
+
25
+ def initialize(table, connection = Connection.default)
26
+ @table = table
27
+ @connection = connection
28
+ @columns = []
29
+ @values = []
30
+ @query = nil
31
+ end
32
+
33
+ # Add a column to the statement. This is for all column types
34
+ # *except* bytea.
35
+ #
36
+ # [column]
37
+ # The column name
38
+ # [value]
39
+ # The value to add. The value is SQL escaped.
40
+ # Should be one of:
41
+ # * a String
42
+ # * an Integer
43
+ # * a Float
44
+ # * a Time
45
+ # * false
46
+ # * true
47
+ # * nil
48
+ # * a Select
49
+ # * :default
50
+ # * :no_value
51
+ #
52
+ # Special values:
53
+ # [a Select]
54
+ # The select's SQL is added in parentheses
55
+ # [:default]
56
+ # Add the SQL keyword "default" to the statement.
57
+ # [:no_value]
58
+ # Do not add a value for this column. This is used when the
59
+ # values are being provided by a Select statement.
60
+ #
61
+ # Example (simple)
62
+ #** Example: insert_insert
63
+ # insert = Insert.new('foo')
64
+ # insert.insert('t', 'bar')
65
+ # p insert.statement # "insert into foo (t) values (E'bar')"
66
+ #**
67
+ #
68
+ # Example (select)
69
+ #** Example: insert_insert_select
70
+ # select = Select.new
71
+ # select.select('j')
72
+ # select.from('bar')
73
+ # select.limit(1)
74
+ # insert = Insert.new('foo')
75
+ # insert.insert('i', select)
76
+ # p insert.statement # "insert into foo (i) values ((select j
77
+ # # from bar limit 1))"
78
+ #**
79
+ #
80
+ # Example (default)
81
+ #** Example: insert_insert_default
82
+ # insert = Insert.new('foo')
83
+ # insert.insert('i', :default)
84
+ # p insert.statement # "insert into foo (i) values
85
+ # # (default)"
86
+ #**
87
+
88
+ def insert(column, value = :no_value)
89
+ @columns << column
90
+ @values << Translate.escape_sql(value) unless value == :no_value
91
+ end
92
+
93
+ # Insert into an array (int[], text[], etc) column. This is not
94
+ # for byte array (bytea) column types: For that, call
95
+ # #insert_bytea.
96
+ #
97
+ # [column]
98
+ # The column name
99
+ # [value]
100
+ # The value to add.
101
+ #
102
+ # This is used for inserting literals and expressions. To insert
103
+ # the result of an SQL query, or to insert the default value,
104
+ # call #insert.
105
+
106
+ def insert_array(column, value)
107
+ @columns << column
108
+ @values << Translate.escape_array(value)
109
+ end
110
+
111
+ # Insert into a bytea column. You must use this function, not
112
+ # #insert, when inserting a string into a bytea column. That's
113
+ # because bytea columns need special escaping.
114
+ #
115
+ # [column]
116
+ # The column name
117
+ # [value]
118
+ # The value to add.
119
+ # Should be one of:
120
+ # * a String
121
+ # * :default
122
+ # * :no_value
123
+ #
124
+ # Special values:
125
+ # [a Select]
126
+ # The select's SQL is added in parentheses
127
+ # [:default]
128
+ # Add the SQL keyword "default" to the statement.
129
+ # [:no_value]
130
+ # Do not add a value for this column. This is used when the
131
+ # values are being provided by a Select statement.
132
+ #
133
+ # Example:
134
+ #** Example: insert_bytea
135
+ # insert = Insert.new('foo')
136
+ # insert.insert_bytea('t', "\000\001\002\003")
137
+ # p insert.statement # "insert into foo (t) values
138
+ # # (E'\\\\000\\\\001\\\\002\\\\003')"
139
+ #**
140
+
141
+ def insert_bytea(column, value = :no_value)
142
+ @columns << column
143
+ @values << Translate.escape_bytea(value) unless value == :no_value
144
+ end
145
+
146
+ # Insert into a bytea[] (bytea array) column. You must use this
147
+ # function, not #insert or #insert_array, because bytea[] columns
148
+ # need special escaping.
149
+ #
150
+ #** Example: insert_bytea_array
151
+ # insert = Insert.new('foo')
152
+ # insert.insert_bytea_array('t', ["foo", "\000bar\nbaz"])
153
+ # p insert.statement # "insert into foo (t) values
154
+ # # ('{\"foo\",\"\\\\\\\\000bar\nbaz\"}')"
155
+ #
156
+ #**
157
+
158
+ def insert_bytea_array(column, value = :no_value)
159
+ @columns << column
160
+ @values << Translate.escape_bytea_array(value) unless value == :no_value
161
+ end
162
+
163
+ # Insert into a "char" column. This is a Postgres specific data
164
+ # type that is different than char or character (yes, the quotes
165
+ # are part of the type name). "char" values are escaped
166
+ # differently than normal test, so be sure to use this method and
167
+ # not #insert when inserting into a "char" column.
168
+ #
169
+ # [column]
170
+ # The column name
171
+ # [value]
172
+ # A string of length 1
173
+ #
174
+ # Example:
175
+ #** Example: insert_qchar
176
+ #**
177
+
178
+ def insert_qchar(column, value = :no_value)
179
+ @columns << column
180
+ @values << Translate.escape_qchar(value)
181
+ end
182
+
183
+ # Insert the results of a select statement
184
+ #
185
+ # Example:
186
+ #** Example: insert_select
187
+ # select = Select.new
188
+ # select.select('i')
189
+ # select.from('bar')
190
+ # insert = Insert.new('foo')
191
+ # insert.insert('i')
192
+ # insert.select(select)
193
+ # p insert.statement # "insert into foo (i) select i from bar"
194
+ #**
195
+
196
+ def select(select)
197
+ @query = select.statement
198
+ end
199
+
200
+ # Define return clause
201
+ #
202
+ # Example: (simple)
203
+ #** Example: insert_returning
204
+ # insert = Insert.new('foo')
205
+ # insert.insert('i', 3)
206
+ # insert.returning('i')
207
+ # p insert.statement # "insert into foo (i) values (3) returning i
208
+ #
209
+ # Example: (expression_with_alias)
210
+ #** Example: insert_returning_with_alias
211
+ # insert = Insert.new('foo')
212
+ # insert.insert('i', 3)
213
+ # insert.returning('i*3', 'calc')
214
+ # p insert.statement # "insert into foo (i) values (3) returning i*3 as calc
215
+
216
+ def returning(expression, name=nil)
217
+ str = "returning #{expression}"
218
+ str += " as #{name}" if name
219
+ @returning_expression = str
220
+ end
221
+
222
+ # insert default values
223
+ #
224
+ # Example:
225
+ #** Example: insert_default_values
226
+ # insert = Insert.new('foo')
227
+ # insert.default_values
228
+ # p insert.statement # "insert into foo default values"
229
+ #**
230
+
231
+ def default_values
232
+ @query = "default values"
233
+ end
234
+
235
+ # Return the SQL statement. Especially useful for debugging.
236
+
237
+ def statement
238
+ [
239
+ "insert into",
240
+ @table,
241
+ column_list,
242
+ query_expression,
243
+ ].compact.join(' ')
244
+ end
245
+
246
+ # Execute the statement.
247
+ #
248
+ # [connection]
249
+ # If present, the connection to use.
250
+ # If nil, uses the connection passed to new or, if no connection was
251
+ # passed to new, uses the default connection.
252
+
253
+ def exec(connection = @connection)
254
+ connection.exec(statement)
255
+ end
256
+
257
+ private
258
+
259
+ def query_expression
260
+ @query || source
261
+ end
262
+
263
+ def column_list
264
+ "(#{@columns.join(', ')})" unless @columns.empty?
265
+ end
266
+
267
+ def source
268
+ "values (#{@values.join(', ')}) #{@returning_expression}".strip
269
+ end
270
+
271
+ end
272
+
273
+ end
274
+
275
+ # Local Variables:
276
+ # tab-width: 2
277
+ # ruby-indent-level: 2
278
+ # indent-tabs-mode: nil
279
+ # End: