activerecord-postgresql-extensions 0.0.10 → 0.0.11
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/Rakefile +2 -2
- data/VERSION +1 -1
- data/activerecord-postgresql-extensions.gemspec +20 -17
- data/lib/activerecord-postgresql-extensions.rb +2 -0
- data/lib/postgresql_extensions/postgresql_adapter_extensions.rb +50 -53
- data/lib/postgresql_extensions/postgresql_constraints.rb +142 -153
- data/lib/postgresql_extensions/postgresql_extensions.rb +246 -0
- data/lib/postgresql_extensions/postgresql_functions.rb +31 -33
- data/lib/postgresql_extensions/postgresql_geometry.rb +2 -2
- data/lib/postgresql_extensions/postgresql_indexes.rb +13 -14
- data/lib/postgresql_extensions/postgresql_languages.rb +4 -4
- data/lib/postgresql_extensions/postgresql_permissions.rb +12 -14
- data/lib/postgresql_extensions/postgresql_roles.rb +2 -2
- data/lib/postgresql_extensions/postgresql_rules.rb +11 -10
- data/lib/postgresql_extensions/postgresql_schemas.rb +4 -4
- data/lib/postgresql_extensions/postgresql_sequences.rb +15 -16
- data/lib/postgresql_extensions/postgresql_tables.rb +20 -21
- data/lib/postgresql_extensions/postgresql_text_search.rb +313 -0
- data/lib/postgresql_extensions/postgresql_triggers.rb +13 -14
- data/lib/postgresql_extensions/postgresql_types.rb +1 -1
- data/lib/postgresql_extensions/postgresql_views.rb +13 -14
- data/test/{adapter_test.rb → adapter_tests.rb} +6 -6
- data/test/{constraints_test.rb → constraints_tests.rb} +13 -13
- data/test/extensions_tests.rb +275 -0
- data/test/{functions_test.rb → functions_tests.rb} +10 -10
- data/test/{geometry_test.rb → geometry_tests.rb} +16 -16
- data/test/{index_test.rb → index_tests.rb} +11 -11
- data/test/{languages_test.rb → languages_tests.rb} +6 -6
- data/test/{permissions_test.rb → permissions_tests.rb} +36 -36
- data/test/{roles_test.rb → roles_tests.rb} +6 -6
- data/test/{rules_test.rb → rules_tests.rb} +3 -3
- data/test/{schemas_test.rb → schemas_tests.rb} +6 -6
- data/test/{sequences_test.rb → sequences_tests.rb} +10 -10
- data/test/{tables_test.rb → tables_tests.rb} +2 -2
- data/test/text_search_tests.rb +263 -0
- metadata +19 -16
- data/postgresql-extensions.gemspec +0 -50
@@ -0,0 +1,246 @@
|
|
1
|
+
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
|
4
|
+
module ActiveRecord
|
5
|
+
module ConnectionAdapters
|
6
|
+
class PostgreSQLAdapter < AbstractAdapter
|
7
|
+
# Creates a new PostgreSQL text search configuration. You must provide
|
8
|
+
# either a parser_name or a source_config option as per the PostgreSQL
|
9
|
+
# text search docs.
|
10
|
+
def create_extension(name, options = {})
|
11
|
+
sql = "CREATE EXTENSION "
|
12
|
+
sql << "IF NOT EXISTS " if options[:if_not_exists]
|
13
|
+
sql << quote_generic(name)
|
14
|
+
sql << " SCHEMA #{quote_generic(options[:schema])}" if options[:schema]
|
15
|
+
sql << " VERSION #{quote_generic(options[:version])}" if options[:version]
|
16
|
+
sql << " FROM #{quote_generic(options[:old_version])}" if options[:old_version]
|
17
|
+
|
18
|
+
execute("#{sql};")
|
19
|
+
end
|
20
|
+
|
21
|
+
# ==== Options
|
22
|
+
#
|
23
|
+
# * <tt>if_exists</tt> - adds IF EXISTS.
|
24
|
+
# * <tt>cascade</tt> - adds CASCADE.
|
25
|
+
def drop_extension(*args)
|
26
|
+
options = args.extract_options!
|
27
|
+
|
28
|
+
sql = 'DROP EXTENSION '
|
29
|
+
sql << 'IF EXISTS ' if options[:if_exists]
|
30
|
+
sql << Array(args).collect { |name| quote_generic(name) }.join(', ')
|
31
|
+
sql << ' CASCADE' if options[:cascade]
|
32
|
+
|
33
|
+
execute("#{sql};")
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_extension(name, new_version = nil)
|
37
|
+
sql = "ALTER EXTENSION #{quote_generic(name)} UPDATE"
|
38
|
+
sql << " TO #{quote_generic(new_version)}" if new_version;
|
39
|
+
execute("#{sql};")
|
40
|
+
end
|
41
|
+
|
42
|
+
def alter_extension_schema(name, schema)
|
43
|
+
execute "ALTER EXTENSION #{quote_generic(name)} SET SCHEMA #{quote_schema(schema)};"
|
44
|
+
end
|
45
|
+
|
46
|
+
# Alters an extension. Can be used with an options Hash or in a bloack.
|
47
|
+
# For instance, all of the following examples should produce the
|
48
|
+
# same output.
|
49
|
+
#
|
50
|
+
# # with options Hash
|
51
|
+
# alter_extension(:foo, :collation => 'en_CA.UTF-8')
|
52
|
+
# alter_extension(:foo, :add_collation => 'en_CA.UTF-8')
|
53
|
+
#
|
54
|
+
# # block mode
|
55
|
+
# alter_extension(:foo) do |e|
|
56
|
+
# e.collation 'en_CA.UTF-8'
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# alter_extension(:foo) do |e|
|
60
|
+
# e.add_collation 'en_CA.UTF-8'
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # All produce
|
64
|
+
# #
|
65
|
+
# # ALTER EXTENSION "foo" ADD COLLATION "en_CA.UTF-8";
|
66
|
+
#
|
67
|
+
# Three versions of each option are available:
|
68
|
+
#
|
69
|
+
# * add_OPTION;
|
70
|
+
# * drop_OPTION; and
|
71
|
+
# * OPTION, which is equiavlent to add_OPTION.
|
72
|
+
#
|
73
|
+
# See the PostgreSQL docs for a list of all of the available extension
|
74
|
+
# options.
|
75
|
+
#
|
76
|
+
# ==== Per-Option, uh... Options
|
77
|
+
#
|
78
|
+
# <tt>:cast</tt>, <tt>:operator</tt>, <tt>:operator_class</tt> and
|
79
|
+
# <tt>:operator_family</tt> can be set their options as a Hash like so:
|
80
|
+
#
|
81
|
+
# # With the options Hash being the actual values:
|
82
|
+
# alter_extension(:foo, :cast => { :hello => :world })
|
83
|
+
#
|
84
|
+
# # With the options Hash containing key-values:
|
85
|
+
# alter_extension(:foo, :cast => {
|
86
|
+
# :source => :hello,
|
87
|
+
# :target => :world
|
88
|
+
# })
|
89
|
+
#
|
90
|
+
# # Or with an Array thusly:
|
91
|
+
# alter_extension(:foo, :cast => [ :source_type, :target_type ])
|
92
|
+
#
|
93
|
+
# # Or with arguments like this here:
|
94
|
+
# alter_extension(:foo) do |e|
|
95
|
+
# e.cast :source_type, :target_type
|
96
|
+
# end
|
97
|
+
#
|
98
|
+
# The options themselves even have options! It's options all the way
|
99
|
+
# down!
|
100
|
+
#
|
101
|
+
# * <tt>:aggregate</tt> - <tt>:name</tt> and <tt>:types</tt>.
|
102
|
+
#
|
103
|
+
# * <tt>:cast</tt> - <tt>:source</tt> and <tt>:target</tt>.
|
104
|
+
#
|
105
|
+
# * <tt>:function</tt> - <tt>:name</tt> and <tt>:arguments</tt>. The
|
106
|
+
# <tt>:arguments</tt> option is just a straight up String like in
|
107
|
+
# the other function manipulation methods.
|
108
|
+
#
|
109
|
+
# * <tt>:operator</tt> - <tt>:name</tt>, <tt>:left_type</tt> and
|
110
|
+
# <tt>:right_type</tt>.
|
111
|
+
#
|
112
|
+
# * <tt>:operator_class</tt> and <tt>:operator_family</tt> - <tt>:name</tt>
|
113
|
+
# and <tt>:indexing_method</tt>.
|
114
|
+
def alter_extension(name, options = {})
|
115
|
+
alterer = PostgreSQLExtensionAlterer.new(self, name, options)
|
116
|
+
|
117
|
+
if block_given?
|
118
|
+
yield alterer
|
119
|
+
end
|
120
|
+
|
121
|
+
execute(alterer.to_s) unless alterer.empty?
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class PostgreSQLExtensionAlterer
|
126
|
+
def initialize(base, name, options = {}) #:nodoc:
|
127
|
+
@base, @name, @options = base, name, options
|
128
|
+
@sql = options.collect { |k, v| build_statement(k, v) }
|
129
|
+
end
|
130
|
+
|
131
|
+
def empty? #:nodoc:
|
132
|
+
@sql.empty?
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_sql #:nodoc:
|
136
|
+
"#{@sql.join(";\n")};"
|
137
|
+
end
|
138
|
+
alias :to_s :to_sql
|
139
|
+
|
140
|
+
%w{
|
141
|
+
aggregate cast collation conversion domain foreign_data_wrapper
|
142
|
+
foreign_table function operator operator_class operator_family
|
143
|
+
language schema sequence server table
|
144
|
+
text_search_configuration text_search_dictionary text_search_parser text_search_template
|
145
|
+
type view
|
146
|
+
}.each do |f|
|
147
|
+
self.class_eval(<<-EOF, __FILE__, __LINE__ + 1)
|
148
|
+
def add_#{f}(*args)
|
149
|
+
@sql << build_statement(:add_#{f}, *args)
|
150
|
+
end
|
151
|
+
alias :#{f} :add_#{f}
|
152
|
+
|
153
|
+
def drop_#{f}(*args)
|
154
|
+
@sql << build_statement(:drop_#{f}, *args)
|
155
|
+
end
|
156
|
+
EOF
|
157
|
+
end
|
158
|
+
|
159
|
+
private
|
160
|
+
ACTIONS = %w{ add drop }.freeze
|
161
|
+
|
162
|
+
def build_statement(k, *args) #:nodoc:
|
163
|
+
option = k.to_s
|
164
|
+
|
165
|
+
if option =~ /^(add|drop)_/
|
166
|
+
action = $1
|
167
|
+
option = option.gsub(/^(add|drop)_/, '')
|
168
|
+
else
|
169
|
+
action = :add
|
170
|
+
end
|
171
|
+
|
172
|
+
sql = "ALTER EXTENSION #{@base.quote_generic(@name || name)} #{action.to_s.upcase} "
|
173
|
+
sql << case option
|
174
|
+
when 'aggregate'
|
175
|
+
name, types = case v = args[0]
|
176
|
+
when Hash
|
177
|
+
v.values_at(:name, :types)
|
178
|
+
else
|
179
|
+
[ args.shift, args ]
|
180
|
+
end
|
181
|
+
|
182
|
+
"AGGREGATE %s (%s)" % [
|
183
|
+
@base.quote_generic(name),
|
184
|
+
Array(types).collect { |t|
|
185
|
+
@base.quote_generic(t)
|
186
|
+
}.join(', ')
|
187
|
+
]
|
188
|
+
|
189
|
+
when 'cast'
|
190
|
+
source, target = extract_hash_or_array_options(args, :source, :target)
|
191
|
+
|
192
|
+
"CAST (#{@base.quote_generic(source)} AS #{@base.quote_generic(target)})"
|
193
|
+
when *%w{ collation conversion domain foreign_data_wrapper
|
194
|
+
foreign_table language schema sequence server table
|
195
|
+
text_search_configuration text_search_dictionary text_search_parser
|
196
|
+
text_search_template type view }
|
197
|
+
|
198
|
+
"#{option.upcase.gsub('_', ' ')} #{@base.quote_generic(args[0])}"
|
199
|
+
when 'function'
|
200
|
+
name, arguments = case v = args[0]
|
201
|
+
when Hash
|
202
|
+
v.values_at(:name, :arguments)
|
203
|
+
else
|
204
|
+
args.flatten!
|
205
|
+
[ args.shift, *args ]
|
206
|
+
end
|
207
|
+
|
208
|
+
"FUNCTION #{@base.quote_function(name)}(#{Array(arguments).join(', ')})"
|
209
|
+
when 'operator'
|
210
|
+
name, left_type, right_type =
|
211
|
+
extract_hash_or_array_options(args, :name, :left_type, :right_type)
|
212
|
+
|
213
|
+
"OPERATOR #{@base.quote_generic(name)} (#{@base.quote_generic(left_type)}, #{@base.quote_generic(right_type)})"
|
214
|
+
when 'operator_class', 'operator_family'
|
215
|
+
object_name, indexing_method =
|
216
|
+
extract_hash_or_array_options(args, :name, :indexing_method)
|
217
|
+
|
218
|
+
"#{option.upcase.gsub('_', ' ')} #{@base.quote_generic(object_name)} USING #{@base.quote_generic(indexing_method)})"
|
219
|
+
end
|
220
|
+
sql
|
221
|
+
end
|
222
|
+
|
223
|
+
def assert_valid_action(option) #:nodoc:
|
224
|
+
if !ACTIONS.include? option.to_s.downcase
|
225
|
+
raise ArgumentError.new("Excepted :add or :drop for PostgreSQLExtensionAlterer action.")
|
226
|
+
end unless option.nil?
|
227
|
+
end
|
228
|
+
|
229
|
+
def extract_hash_or_array_options(hash_or_array, *keys) #:nodoc:
|
230
|
+
case v = hash_or_array[0]
|
231
|
+
when Hash
|
232
|
+
if (keys - (sliced = v.slice(*keys)).keys).length == 0
|
233
|
+
keys.collect do |k|
|
234
|
+
sliced[k]
|
235
|
+
end
|
236
|
+
else
|
237
|
+
[ v.keys.first, v.values.first ]
|
238
|
+
end
|
239
|
+
else
|
240
|
+
v = hash_or_array.flatten
|
241
|
+
[ v.shift, *v ]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
@@ -91,20 +91,19 @@ module ActiveRecord
|
|
91
91
|
#
|
92
92
|
# ==== Example
|
93
93
|
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
# end
|
94
|
+
# create_function('tester_function', 'integer',
|
95
|
+
# 'integer', 'sql', :behavior => :immutable, :set => { :search_path => :from_current }, :force => true) do
|
96
|
+
# "select $1;"
|
97
|
+
# end
|
99
98
|
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
99
|
+
# # Produces:
|
100
|
+
# #
|
101
|
+
# # CREATE OR REPLACE FUNCTION "tester_function"(integer) RETURNS integer AS $$
|
102
|
+
# # select $1;
|
103
|
+
# # $$
|
104
|
+
# # LANGUAGE "sql"
|
105
|
+
# # IMMUTABLE
|
106
|
+
# # SET "search_path" FROM CURRENT;
|
108
107
|
def create_function(name, args, returns, language, options = {})
|
109
108
|
body = yield.to_s
|
110
109
|
execute PostgreSQLFunctionDefinition.new(self, name, args, returns, language, body, options).to_s
|
@@ -122,7 +121,7 @@ module ActiveRecord
|
|
122
121
|
sql << 'IF EXISTS ' if options[:if_exists]
|
123
122
|
sql << "#{quote_function(name)}(#{args})"
|
124
123
|
sql << ' CASCADE' if options[:cascade]
|
125
|
-
execute sql
|
124
|
+
execute "#{sql};"
|
126
125
|
end
|
127
126
|
|
128
127
|
# Renames a function.
|
@@ -155,29 +154,28 @@ module ActiveRecord
|
|
155
154
|
#
|
156
155
|
# Both of the following examples should produce the same output.
|
157
156
|
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
# alter_function('another_function', 'integer', :owner_to => 'jdoe')
|
157
|
+
# # with options Hash
|
158
|
+
# alter_function('my_function', 'integer', :rename_to => 'another_function')
|
159
|
+
# alter_function('another_function', 'integer', :owner_to => 'jdoe')
|
162
160
|
#
|
163
|
-
#
|
164
|
-
#
|
165
|
-
#
|
166
|
-
#
|
167
|
-
#
|
161
|
+
# # block mode
|
162
|
+
# alter_function('my_function', 'integer') do |f|
|
163
|
+
# f.rename_to 'another_function'
|
164
|
+
# f.owner_to 'jdoe'
|
165
|
+
# end
|
168
166
|
#
|
169
|
-
#
|
170
|
-
#
|
171
|
-
#
|
172
|
-
#
|
167
|
+
# # Produces:
|
168
|
+
# #
|
169
|
+
# # ALTER FUNCTION "my_function"(integer) OWNER TO "jdoe";
|
170
|
+
# # ALTER FUNCTION "my_function"(integer) RENAME TO "another_function";
|
173
171
|
def alter_function(name, args, options = {})
|
172
|
+
alterer = PostgreSQLFunctionAlterer.new(self, name, args, options)
|
173
|
+
|
174
174
|
if block_given?
|
175
|
-
alterer = PostgreSQLFunctionAlterer.new(self, name, args)
|
176
175
|
yield alterer
|
177
|
-
execute alterer.to_s unless alterer.empty?
|
178
|
-
else
|
179
|
-
execute PostgreSQLFunctionAlterer.new(self, name, args, options).to_s
|
180
176
|
end
|
177
|
+
|
178
|
+
execute alterer.to_s unless alterer.empty?
|
181
179
|
end
|
182
180
|
end
|
183
181
|
|
@@ -271,7 +269,7 @@ module ActiveRecord
|
|
271
269
|
sql << " COST #{options[:cost].to_i}\n" if options[:cost]
|
272
270
|
sql << " ROWS #{options[:rows].to_i}\n" if options[:rows]
|
273
271
|
sql << " " << (set_options(options[:set]) * "\n ") if options[:set]
|
274
|
-
sql.strip
|
272
|
+
"#{sql.strip};"
|
275
273
|
end
|
276
274
|
alias :to_s :to_sql
|
277
275
|
end
|
@@ -291,7 +289,7 @@ module ActiveRecord
|
|
291
289
|
end
|
292
290
|
|
293
291
|
def to_sql #:nodoc:
|
294
|
-
@sql.join(";\n")
|
292
|
+
"#{@sql.join(";\n")};"
|
295
293
|
end
|
296
294
|
alias :to_s :to_sql
|
297
295
|
|
@@ -127,14 +127,14 @@ module ActiveRecord
|
|
127
127
|
"DELETE FROM \"geometry_columns\" WHERE f_table_catalog = '' AND " +
|
128
128
|
"f_table_schema = %s AND " +
|
129
129
|
"f_table_name = %s AND " +
|
130
|
-
"f_geometry_column = %s",
|
130
|
+
"f_geometry_column = %s;",
|
131
131
|
base.quote(current_schema.to_s),
|
132
132
|
base.quote(current_table_name.to_s),
|
133
133
|
base.quote(column_name.to_s)
|
134
134
|
)
|
135
135
|
|
136
136
|
@post_processing << sprintf(
|
137
|
-
"INSERT INTO \"geometry_columns\" VALUES ('', %s, %s, %s, %d, %d, %s)",
|
137
|
+
"INSERT INTO \"geometry_columns\" VALUES ('', %s, %s, %s, %d, %d, %s);",
|
138
138
|
base.quote(current_schema.to_s),
|
139
139
|
base.quote(current_table_name.to_s),
|
140
140
|
base.quote(column_name.to_s),
|
@@ -93,18 +93,17 @@ module ActiveRecord
|
|
93
93
|
#
|
94
94
|
# ==== Examples
|
95
95
|
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
# # => CREATE INDEX "this_is_my_index" ON "foo"("id", "ref_id");
|
96
|
+
# # using multiple columns
|
97
|
+
# create_index('this_is_my_index', :foo, [ :id, :ref_id ], :using => :gin)
|
98
|
+
# # => CREATE INDEX "this_is_my_index" ON "foo"("id", "ref_id");
|
100
99
|
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
100
|
+
# # using expressions
|
101
|
+
# create_index('this_is_another_idx', :foo, { :expression => 'COALESCE(ref_id, 0)' })
|
102
|
+
# # => CREATE INDEX "this_is_another_idx" ON "foo"((COALESCE(ref_id, 0)));
|
104
103
|
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
104
|
+
# # additional options
|
105
|
+
# create_index('search_idx', :foo, :tsvector, :using => :gin)
|
106
|
+
# # => CREATE INDEX "search_idx" ON "foo" USING "gin"("tsvector");
|
108
107
|
def create_index(name, table, columns, options = {})
|
109
108
|
execute PostgreSQLIndexDefinition.new(self, name, table, columns, options).to_s
|
110
109
|
end
|
@@ -125,17 +124,17 @@ module ActiveRecord
|
|
125
124
|
sql << 'IF EXISTS ' if options[:if_exists]
|
126
125
|
sql << Array(name).collect { |i| quote_generic(i) }.join(', ')
|
127
126
|
sql << ' CASCADE' if options[:cascade]
|
128
|
-
execute
|
127
|
+
execute("#{sql};")
|
129
128
|
end
|
130
129
|
|
131
130
|
# Renames an index.
|
132
131
|
def rename_index(name, new_name, options = {})
|
133
|
-
execute "ALTER INDEX #{quote_generic(name)} RENAME TO #{quote_generic(new_name)}"
|
132
|
+
execute "ALTER INDEX #{quote_generic(name)} RENAME TO #{quote_generic(new_name)};"
|
134
133
|
end
|
135
134
|
|
136
135
|
# Changes an index's tablespace.
|
137
136
|
def alter_index_tablespace(name, tablespace, options = {})
|
138
|
-
execute "ALTER INDEX #{quote_generic(name)} SET TABLESPACE #{quote_tablespace(tablespace)}"
|
137
|
+
execute "ALTER INDEX #{quote_generic(name)} SET TABLESPACE #{quote_tablespace(tablespace)};"
|
139
138
|
end
|
140
139
|
end
|
141
140
|
|
@@ -181,7 +180,7 @@ module ActiveRecord
|
|
181
180
|
sql << " WITH (FILLFACTOR = #{options[:fill_factor].to_i})" if options[:fill_factor]
|
182
181
|
sql << " TABLESPACE #{base.quote_tablespace(options[:tablespace])}" if options[:tablespace]
|
183
182
|
sql << " WHERE #{options[:conditions] || options[:where]}" if options[:conditions] || options[:where]
|
184
|
-
sql
|
183
|
+
"#{sql};"
|
185
184
|
end
|
186
185
|
alias :to_s :to_sql
|
187
186
|
|
@@ -37,7 +37,7 @@ module ActiveRecord
|
|
37
37
|
sql << "PROCEDURAL LANGUAGE #{quote_language(language)}"
|
38
38
|
sql << " HANDLER #{quote_language(options[:call_handler])}" if options[:call_handler]
|
39
39
|
sql << " VALIDATOR #{options[:validator]}" if options[:validator]
|
40
|
-
execute
|
40
|
+
execute("#{sql};")
|
41
41
|
end
|
42
42
|
|
43
43
|
# Drops a language.
|
@@ -51,17 +51,17 @@ module ActiveRecord
|
|
51
51
|
sql << 'IF EXISTS ' if options[:if_exists]
|
52
52
|
sql << quote_language(language)
|
53
53
|
sql << ' CASCADE' if options[:cascade]
|
54
|
-
execute
|
54
|
+
execute("#{sql};")
|
55
55
|
end
|
56
56
|
|
57
57
|
# Renames a language.
|
58
58
|
def alter_language_name old_language, new_language, options = {}
|
59
|
-
execute "ALTER PROCEDURAL LANGUAGE #{quote_language(old_language)} RENAME TO #{quote_language(new_language)}"
|
59
|
+
execute "ALTER PROCEDURAL LANGUAGE #{quote_language(old_language)} RENAME TO #{quote_language(new_language)};"
|
60
60
|
end
|
61
61
|
|
62
62
|
# Changes a language's owner.
|
63
63
|
def alter_language_owner language, role, options = {}
|
64
|
-
execute "ALTER PROCEDURAL LANGUAGE #{quote_language(language)} OWNER TO #{quote_language(role)}"
|
64
|
+
execute "ALTER PROCEDURAL LANGUAGE #{quote_language(language)} OWNER TO #{quote_language(role)};"
|
65
65
|
end
|
66
66
|
|
67
67
|
# Returns an Array of available languages.
|