111 self.refresh_indexes() |
111 self.refresh_indexes() |
112 return self._indexes |
112 return self._indexes |
113 indexes = property(getindexes) |
113 indexes = property(getindexes) |
114 |
114 |
115 |
115 |
|
116 class Argument: |
|
117 def __init__(self, browser, function, name, type, mode, default): |
|
118 # PgBrowser instance |
|
119 self.browser = browser |
|
120 # Function instance |
|
121 self.function = function |
|
122 self.name = name |
|
123 self.type = type |
|
124 self.mode = mode |
|
125 self.default = default |
|
126 |
116 class Function: |
127 class Function: |
117 def __init__(self, browser, schema, oid, name, type, arguments, result, source): |
128 def __init__(self, browser, schema, oid, name, function_name, type, result, source): |
118 self.browser = browser |
129 self.browser = browser |
|
130 self.schema = schema |
119 self.oid = oid |
131 self.oid = oid |
120 self.name = name |
132 #: unique name - function name + arg types |
|
133 self.name = name |
|
134 #: pure function name without args |
|
135 self.function_name = function_name |
121 self.type = type |
136 self.type = type |
122 self.arguments = arguments |
|
123 self.result = result |
137 self.result = result |
124 self.source = source |
138 self.source = source |
|
139 self._arguments = None |
125 self._definition = None |
140 self._definition = None |
|
141 |
|
142 def refresh(self): |
|
143 self.refresh_args() |
|
144 |
|
145 def refresh_args(self): |
|
146 rows = self.browser.list_function_args(self.oid) |
|
147 self._arguments = OrderedDict([(x['name'], Argument(self.browser, self, **x)) for x in rows]) |
|
148 |
|
149 @property |
|
150 def arguments(self): |
|
151 if self._arguments is None: |
|
152 self.refresh_args() |
|
153 return self._arguments |
126 |
154 |
127 @property |
155 @property |
128 def definition(self): |
156 def definition(self): |
129 """Get full function definition including CREATE command.""" |
157 """Get full function definition including CREATE command.""" |
130 if not self._definition: |
158 if not self._definition: |
304 def list_functions(self, schema='public'): |
332 def list_functions(self, schema='public'): |
305 '''List functions in schema.''' |
333 '''List functions in schema.''' |
306 return self._query(''' |
334 return self._query(''' |
307 SELECT |
335 SELECT |
308 p.oid as "oid", |
336 p.oid as "oid", |
309 p.proname as "name", |
337 p.proname || '(' || array_to_string( |
|
338 array(SELECT pg_catalog.format_type(unnest(p.proargtypes), NULL)), |
|
339 ', ' |
|
340 ) || ')' as "name", |
|
341 p.proname as "function_name", |
310 pg_catalog.pg_get_function_result(p.oid) as "result", |
342 pg_catalog.pg_get_function_result(p.oid) as "result", |
311 pg_catalog.pg_get_function_arguments(p.oid) as "arguments", |
|
312 p.prosrc as "source", |
343 p.prosrc as "source", |
313 CASE |
344 CASE |
314 WHEN p.proisagg THEN 'agg' |
345 WHEN p.proisagg THEN 'agg' |
315 WHEN p.proiswindow THEN 'window' |
346 WHEN p.proiswindow THEN 'window' |
316 WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger' |
347 WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN 'trigger' |
317 ELSE 'normal' |
348 ELSE 'normal' |
318 END as "type" |
349 END as "type" |
319 FROM pg_catalog.pg_proc p |
350 FROM pg_catalog.pg_proc p |
320 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace |
351 LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace |
321 WHERE pg_catalog.pg_function_is_visible(p.oid) |
352 WHERE n.nspname = %s |
322 AND n.nspname = %s |
|
323 ORDER BY 1, 2, 4; |
353 ORDER BY 1, 2, 4; |
324 ''', [schema]) |
354 ''', [schema]) |
|
355 |
|
356 def list_function_args(self, oid): |
|
357 """List function arguments. |
|
358 |
|
359 Notes about query: |
|
360 type: Use allargtypes if present, argtypes otherwise. |
|
361 The trick with [0:999] moves lower bound from 0 to default 1 |
|
362 by slicing all elements (slices has always lower bound 1). |
|
363 mode: This trick makes array of NULLs of same length as argnames, |
|
364 in case argmodes is NULL. |
|
365 default: Use pg_get_expr, split output by ', ' |
|
366 FIXME: will fail if ', ' is present in default value string. |
|
367 """ |
|
368 return self._query(''' |
|
369 SELECT |
|
370 unnest(p.proargnames) AS "name", |
|
371 pg_catalog.format_type(unnest( |
|
372 COALESCE(p.proallargtypes, (p.proargtypes::oid[])[0:999]) |
|
373 ), NULL) AS "type", |
|
374 unnest( |
|
375 COALESCE( |
|
376 p.proargmodes::text[], |
|
377 array(SELECT NULL::text FROM generate_series(1, array_upper(p.proargnames, 1))) |
|
378 ) |
|
379 ) AS "mode", |
|
380 unnest(array_cat( |
|
381 array_fill(NULL::text, array[COALESCE(array_upper(p.proargnames,1),0) - p.pronargdefaults]), |
|
382 string_to_array(pg_get_expr(p.proargdefaults, 'pg_proc'::regclass, true), ', ') |
|
383 )) AS "default" |
|
384 FROM pg_proc p |
|
385 WHERE p.oid = %s''', [oid]) |
325 |
386 |
326 def get_function_definition(self, oid): |
387 def get_function_definition(self, oid): |
327 """Get full function definition, including CREATE command etc. |
388 """Get full function definition, including CREATE command etc. |
328 |
389 |
329 Args: |
390 Args: |