activerecord-postgresql-extensions 0.0.10 → 0.0.11
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|