Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
aeb3c2fc
Commit
aeb3c2fc
authored
Apr 21, 2009
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add agg/normal/trigger/window flags for psql \df and in \df output.
David Fetter
parent
02dec250
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
163 additions
and
38 deletions
+163
-38
doc/src/sgml/ref/psql-ref.sgml
doc/src/sgml/ref/psql-ref.sgml
+14
-11
src/bin/psql/command.c
src/bin/psql/command.c
+17
-3
src/bin/psql/describe.c
src/bin/psql/describe.c
+120
-13
src/bin/psql/describe.h
src/bin/psql/describe.h
+3
-3
src/bin/psql/help.c
src/bin/psql/help.c
+3
-2
src/test/regress/expected/polymorphism.out
src/test/regress/expected/polymorphism.out
+6
-6
No files found.
doc/src/sgml/ref/psql-ref.sgml
View file @
aeb3c2fc
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.22
3 2009/04/08 22:29:30 tgl
Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.22
4 2009/04/21 15:49:06 momjian
Exp $
PostgreSQL documentation
PostgreSQL documentation
-->
-->
...
@@ -1039,18 +1039,22 @@ testdb=>
...
@@ -1039,18 +1039,22 @@ testdb=>
<varlistentry>
<varlistentry>
<term><literal>\df[S+] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<term><literal>\df[S+] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<term><literal>\df[antw][S+] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<listitem>
<listitem>
<para>
<para>
Lists available functions, together with their argument and
Lists available functions, together with their arguments,
return types. If <replaceable
return types, and their function types: 'agg' (aggregate),
class="parameter">pattern</replaceable>
'normal', 'trigger', and 'window'. To display only functions
is specified, only functions whose names match the pattern are shown.
of a specific type, use the corresponding letters <literal>a</>,
If the form <literal>\df+</literal> is used, additional information about
<literal>n</>, <literal>t</>, or <literal>w</>. If <replaceable
each function, including volatility, language, source code and description, is shown.
class="parameter">pattern</replaceable> is specified, only
By default, only user-created objects are shown; supply a
functions whose names match the pattern are shown. If the
pattern or the <literal>S</literal> modifier to include system
form <literal>\df+</literal> is used, additional information
objects.
about each function, including volatility, language, source
code and description, is shown. By default, only user-created
objects are shown; supply a pattern or the <literal>S</literal>
modifier to include system objects.
</para>
</para>
<note>
<note>
...
@@ -1064,7 +1068,6 @@ testdb=>
...
@@ -1064,7 +1068,6 @@ testdb=>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><literal>\dF[+] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<term><literal>\dF[+] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<listitem>
<listitem>
...
...
src/bin/psql/command.c
View file @
aeb3c2fc
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
*
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
*
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.20
4 2009/03/25 13:07:26 petere
Exp $
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.20
5 2009/04/21 15:49:06 momjian
Exp $
*/
*/
#include "postgres_fe.h"
#include "postgres_fe.h"
#include "command.h"
#include "command.h"
...
@@ -365,8 +365,22 @@ exec_command(const char *cmd,
...
@@ -365,8 +365,22 @@ exec_command(const char *cmd,
case
'D'
:
case
'D'
:
success
=
listDomains
(
pattern
,
show_system
);
success
=
listDomains
(
pattern
,
show_system
);
break
;
break
;
case
'f'
:
case
'f'
:
/* function subsystem */
success
=
describeFunctions
(
pattern
,
show_verbose
,
show_system
);
switch
(
cmd
[
2
])
{
case
'\0'
:
case
'+'
:
case
'S'
:
case
'a'
:
case
'n'
:
case
't'
:
case
'w'
:
success
=
describeFunctions
(
&
cmd
[
2
],
pattern
,
show_verbose
,
show_system
);
break
;
default:
status
=
PSQL_CMD_UNKNOWN
;
break
;
}
break
;
break
;
case
'g'
:
case
'g'
:
/* no longer distinct from \du */
/* no longer distinct from \du */
...
...
src/bin/psql/describe.c
View file @
aeb3c2fc
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
*
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
*
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.20
8 2009/04/08 22:29:30 tgl
Exp $
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.20
9 2009/04/21 15:49:06 momjian
Exp $
*/
*/
#include "postgres_fe.h"
#include "postgres_fe.h"
...
@@ -183,15 +183,43 @@ describeTablespaces(const char *pattern, bool verbose)
...
@@ -183,15 +183,43 @@ describeTablespaces(const char *pattern, bool verbose)
/* \df
/* \df
* Takes an optional regexp to select particular functions
* Takes an optional regexp to select particular functions.
*
* As with \d, you can specify the kinds of functions you want:
*
* a for aggregates
* n for normal
* t for trigger
* w for window
*
* and you can mix and match these in any order.
*/
*/
bool
bool
describeFunctions
(
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
)
describeFunctions
(
const
char
*
functypes
,
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
)
{
{
bool
showAggregate
=
strchr
(
functypes
,
'a'
)
!=
NULL
;
bool
showNormal
=
strchr
(
functypes
,
'n'
)
!=
NULL
;
bool
showTrigger
=
strchr
(
functypes
,
't'
)
!=
NULL
;
bool
showWindow
=
strchr
(
functypes
,
'w'
)
!=
NULL
;
PQExpBufferData
buf
;
PQExpBufferData
buf
;
PGresult
*
res
;
PGresult
*
res
;
printQueryOpt
myopt
=
pset
.
popt
;
printQueryOpt
myopt
=
pset
.
popt
;
if
(
showWindow
&&
pset
.
sversion
<
80400
)
{
fprintf
(
stderr
,
_
(
"
\\
df does not take a
\"
w
\"
decorator in %d.%d.
\n
"
),
pset
.
sversion
/
10000
,
(
pset
.
sversion
/
100
)
%
100
);
return
true
;
}
if
(
!
showAggregate
&&
!
showNormal
&&
!
showTrigger
&&
!
showWindow
)
{
showAggregate
=
showNormal
=
showTrigger
=
true
;
if
(
pset
.
sversion
>=
80400
)
showWindow
=
true
;
}
initPQExpBuffer
(
&
buf
);
initPQExpBuffer
(
&
buf
);
printfPQExpBuffer
(
&
buf
,
printfPQExpBuffer
(
&
buf
,
...
@@ -203,9 +231,21 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
...
@@ -203,9 +231,21 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
if
(
pset
.
sversion
>=
80400
)
if
(
pset
.
sversion
>=
80400
)
appendPQExpBuffer
(
&
buf
,
appendPQExpBuffer
(
&
buf
,
" pg_catalog.pg_get_function_result(p.oid) as
\"
%s
\"
,
\n
"
" pg_catalog.pg_get_function_result(p.oid) as
\"
%s
\"
,
\n
"
" pg_catalog.pg_get_function_arguments(p.oid) as
\"
%s
\"
"
,
" pg_catalog.pg_get_function_arguments(p.oid) as
\"
%s
\"
,
\n
"
" CASE
\n
"
" WHEN p.proisagg THEN '%s'
\n
"
" WHEN p.proiswindow THEN '%s'
\n
"
" WHEN pg_catalog.pg_get_function_result(p.oid) = 'trigger' THEN '%s'
\n
"
" ELSE '%s'
\n
"
"END as
\"
%s
\"
"
,
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Argument data types"
));
gettext_noop
(
"Argument data types"
),
/* translator: "agg" is short for "aggregate" */
gettext_noop
(
"agg"
),
gettext_noop
(
"window"
),
gettext_noop
(
"trigger"
),
gettext_noop
(
"normal"
),
gettext_noop
(
"Type"
));
else
if
(
pset
.
sversion
>=
80100
)
else
if
(
pset
.
sversion
>=
80100
)
appendPQExpBuffer
(
&
buf
,
appendPQExpBuffer
(
&
buf
,
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||
\n
"
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||
\n
"
...
@@ -238,16 +278,36 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
...
@@ -238,16 +278,36 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
" FROM
\n
"
" FROM
\n
"
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)
\n
"
" pg_catalog.generate_series(0, pg_catalog.array_upper(p.proargtypes, 1)) AS s(i)
\n
"
" ), ', ')
\n
"
" ), ', ')
\n
"
" END AS
\"
%s
\"
,
\n
"
" CASE
\n
"
" WHEN p.proisagg THEN '%s'
\n
"
" WHEN 'trigger' = pg_catalog.format_type(p.prorettype, NULL) THEN '%s'
\n
"
" ELSE '%s'
\n
"
" END AS
\"
%s
\"
"
,
" END AS
\"
%s
\"
"
,
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Argument data types"
));
gettext_noop
(
"Argument data types"
),
/* translator: "agg" is short for "aggregate" */
gettext_noop
(
"agg"
),
gettext_noop
(
"trigger"
),
gettext_noop
(
"normal"
),
gettext_noop
(
"Type"
));
else
else
appendPQExpBuffer
(
&
buf
,
appendPQExpBuffer
(
&
buf
,
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||
\n
"
" CASE WHEN p.proretset THEN 'SETOF ' ELSE '' END ||
\n
"
" pg_catalog.format_type(p.prorettype, NULL) as
\"
%s
\"
,
\n
"
" pg_catalog.format_type(p.prorettype, NULL) as
\"
%s
\"
,
\n
"
" pg_catalog.oidvectortypes(p.proargtypes) as
\"
%s
\"
"
,
" pg_catalog.oidvectortypes(p.proargtypes) as
\"
%s
\"
,
\n
"
" CASE
\n
"
" WHEN p.proisagg THEN '%s'
\n
"
" WHEN 'trigger' = pg_catalog.format_type(p.prorettype, NULL) THEN '%s'
\n
"
" ELSE '%s'
\n
"
" END AS
\"
%s
\"
"
,
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Result data type"
),
gettext_noop
(
"Argument data types"
));
gettext_noop
(
"Argument data types"
),
/* translator: "agg" is short for "aggregate" */
gettext_noop
(
"agg"
),
gettext_noop
(
"trigger"
),
gettext_noop
(
"normal"
),
gettext_noop
(
"Type"
));
if
(
verbose
)
if
(
verbose
)
appendPQExpBuffer
(
&
buf
,
appendPQExpBuffer
(
&
buf
,
...
@@ -274,16 +334,63 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
...
@@ -274,16 +334,63 @@ describeFunctions(const char *pattern, bool verbose, bool showSystem)
appendPQExpBuffer
(
&
buf
,
appendPQExpBuffer
(
&
buf
,
" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang
\n
"
);
" LEFT JOIN pg_catalog.pg_language l ON l.oid = p.prolang
\n
"
);
appendPQExpBuffer
(
&
buf
,
"WHERE NOT p.proisagg
\n
"
);
processSQLNamePattern
(
pset
.
db
,
&
buf
,
pattern
,
false
,
true
,
"n.nspname"
,
"p.proname"
,
NULL
,
"pg_catalog.pg_function_is_visible(p.oid)"
);
if
(
showNormal
&&
showAggregate
&&
showTrigger
&&
showWindow
)
/* Do nothing */
;
else
if
(
showNormal
)
{
if
(
!
showWindow
&&
pset
.
sversion
>=
80400
)
appendPQExpBuffer
(
&
buf
,
" AND NOT p.proiswindow
\n
"
);
if
(
!
showAggregate
)
appendPQExpBuffer
(
&
buf
,
" AND NOT p.proisagg
\n
"
);
if
(
!
showTrigger
)
{
if
(
pset
.
sversion
>=
80400
)
appendPQExpBuffer
(
&
buf
,
" AND pg_catalog.pg_get_function_result(p.oid) <> 'trigger'
\n
"
);
else
appendPQExpBuffer
(
&
buf
,
" AND pg_catalog.format_type(p.prorettype, NULL) <> 'trigger'
\n
"
);
}
}
else
{
bool
needs_or
=
false
;
appendPQExpBuffer
(
&
buf
,
" AND (
\n
"
);
if
(
showAggregate
)
{
appendPQExpBuffer
(
&
buf
,
"p.proisagg
\n
"
);
needs_or
=
true
;
}
if
(
showTrigger
)
{
if
(
needs_or
)
appendPQExpBuffer
(
&
buf
,
" OR "
);
if
(
pset
.
sversion
>=
80400
)
appendPQExpBuffer
(
&
buf
,
"pg_catalog.pg_get_function_result(p.oid) = 'trigger'
\n
"
);
else
appendPQExpBuffer
(
&
buf
,
"'trigger' <> pg_catalog.format_type(p.prorettype, NULL)
\n
"
);
needs_or
=
true
;
}
if
(
showWindow
)
{
if
(
needs_or
)
appendPQExpBuffer
(
&
buf
,
" OR "
);
appendPQExpBuffer
(
&
buf
,
"p.proiswindow
\n
"
);
}
appendPQExpBuffer
(
&
buf
,
" )
\n
"
);
}
if
(
!
showSystem
&&
!
pattern
)
if
(
!
showSystem
&&
!
pattern
)
appendPQExpBuffer
(
&
buf
,
" AND n.nspname <> 'pg_catalog'
\n
"
appendPQExpBuffer
(
&
buf
,
" AND n.nspname <> 'pg_catalog'
\n
"
" AND n.nspname <> 'information_schema'
\n
"
);
" AND n.nspname <> 'information_schema'
\n
"
);
processSQLNamePattern
(
pset
.
db
,
&
buf
,
pattern
,
true
,
false
,
"n.nspname"
,
"p.proname"
,
NULL
,
"pg_catalog.pg_function_is_visible(p.oid)"
);
appendPQExpBuffer
(
&
buf
,
"ORDER BY 1, 2, 4;"
);
appendPQExpBuffer
(
&
buf
,
"ORDER BY 1, 2, 4;"
);
res
=
PSQLexec
(
buf
.
data
,
false
);
res
=
PSQLexec
(
buf
.
data
,
false
);
...
...
src/bin/psql/describe.h
View file @
aeb3c2fc
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
*
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
*
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.
39 2009/01/20 02:13:42
momjian Exp $
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.
40 2009/04/21 15:49:06
momjian Exp $
*/
*/
#ifndef DESCRIBE_H
#ifndef DESCRIBE_H
#define DESCRIBE_H
#define DESCRIBE_H
...
@@ -15,8 +15,8 @@ extern bool describeAggregates(const char *pattern, bool verbose, bool showSyste
...
@@ -15,8 +15,8 @@ extern bool describeAggregates(const char *pattern, bool verbose, bool showSyste
/* \db */
/* \db */
extern
bool
describeTablespaces
(
const
char
*
pattern
,
bool
verbose
);
extern
bool
describeTablespaces
(
const
char
*
pattern
,
bool
verbose
);
/* \df */
/* \df
, \dfa, \dfn, \dft, \dfw, etc.
*/
extern
bool
describeFunctions
(
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
);
extern
bool
describeFunctions
(
const
char
*
functypes
,
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
);
/* \dT */
/* \dT */
extern
bool
describeTypes
(
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
);
extern
bool
describeTypes
(
const
char
*
pattern
,
bool
verbose
,
bool
showSystem
);
...
...
src/bin/psql/help.c
View file @
aeb3c2fc
...
@@ -3,7 +3,7 @@
...
@@ -3,7 +3,7 @@
*
*
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
*
*
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.14
6 2009/04/11 14:11:21 petere
Exp $
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.14
7 2009/04/21 15:49:06 momjian
Exp $
*/
*/
#include "postgres_fe.h"
#include "postgres_fe.h"
...
@@ -196,7 +196,7 @@ slashUsage(unsigned short int pager)
...
@@ -196,7 +196,7 @@ slashUsage(unsigned short int pager)
fprintf
(
output
,
_
(
" (options: S = show system objects, + = additional detail)
\n
"
));
fprintf
(
output
,
_
(
" (options: S = show system objects, + = additional detail)
\n
"
));
fprintf
(
output
,
_
(
"
\\
d[S+] list tables, views, and sequences
\n
"
));
fprintf
(
output
,
_
(
"
\\
d[S+] list tables, views, and sequences
\n
"
));
fprintf
(
output
,
_
(
"
\\
d[S+] NAME describe table, view, sequence, or index
\n
"
));
fprintf
(
output
,
_
(
"
\\
d[S+] NAME describe table, view, sequence, or index
\n
"
));
fprintf
(
output
,
_
(
"
\\
da[
S] [PATTERN] list aggregate function
s
\n
"
));
fprintf
(
output
,
_
(
"
\\
da[
+] [PATTERN] list aggregate
s
\n
"
));
fprintf
(
output
,
_
(
"
\\
db[+] [PATTERN] list tablespaces
\n
"
));
fprintf
(
output
,
_
(
"
\\
db[+] [PATTERN] list tablespaces
\n
"
));
fprintf
(
output
,
_
(
"
\\
dc[S] [PATTERN] list conversions
\n
"
));
fprintf
(
output
,
_
(
"
\\
dc[S] [PATTERN] list conversions
\n
"
));
fprintf
(
output
,
_
(
"
\\
dC [PATTERN] list casts
\n
"
));
fprintf
(
output
,
_
(
"
\\
dC [PATTERN] list casts
\n
"
));
...
@@ -206,6 +206,7 @@ slashUsage(unsigned short int pager)
...
@@ -206,6 +206,7 @@ slashUsage(unsigned short int pager)
fprintf
(
output
,
_
(
"
\\
deu[+] [PATTERN] list user mappings
\n
"
));
fprintf
(
output
,
_
(
"
\\
deu[+] [PATTERN] list user mappings
\n
"
));
fprintf
(
output
,
_
(
"
\\
dew[+] [PATTERN] list foreign-data wrappers
\n
"
));
fprintf
(
output
,
_
(
"
\\
dew[+] [PATTERN] list foreign-data wrappers
\n
"
));
fprintf
(
output
,
_
(
"
\\
df[S+] [PATTERN] list functions
\n
"
));
fprintf
(
output
,
_
(
"
\\
df[S+] [PATTERN] list functions
\n
"
));
fprintf
(
output
,
_
(
"
\\
df[antwS+] [PATTERN] list only agg/normal/trigger/window functions
\n
"
));
fprintf
(
output
,
_
(
"
\\
dF[+] [PATTERN] list text search configurations
\n
"
));
fprintf
(
output
,
_
(
"
\\
dF[+] [PATTERN] list text search configurations
\n
"
));
fprintf
(
output
,
_
(
"
\\
dFd[+] [PATTERN] list text search dictionaries
\n
"
));
fprintf
(
output
,
_
(
"
\\
dFd[+] [PATTERN] list text search dictionaries
\n
"
));
fprintf
(
output
,
_
(
"
\\
dFp[+] [PATTERN] list text search parsers
\n
"
));
fprintf
(
output
,
_
(
"
\\
dFp[+] [PATTERN] list text search parsers
\n
"
));
...
...
src/test/regress/expected/polymorphism.out
View file @
aeb3c2fc
...
@@ -838,9 +838,9 @@ select dfunc();
...
@@ -838,9 +838,9 @@ select dfunc();
-- verify it lists properly
-- verify it lists properly
\df dfunc
\df dfunc
List of functions
List of functions
Schema | Name | Result data type | Argument data types
Schema | Name | Result data type | Argument data types
| Type
--------+-------+------------------+-----------------------------------------------------------
--------+-------+------------------+-----------------------------------------------------------
+--------
public | dfunc | integer | a integer DEFAULT 1, OUT sum integer, b integer DEFAULT 2
public | dfunc | integer | a integer DEFAULT 1, OUT sum integer, b integer DEFAULT 2
| normal
(1 row)
(1 row)
drop function dfunc(int, int);
drop function dfunc(int, int);
...
@@ -1006,9 +1006,9 @@ ERROR: cannot remove parameter defaults from existing function
...
@@ -1006,9 +1006,9 @@ ERROR: cannot remove parameter defaults from existing function
HINT: Use DROP FUNCTION first.
HINT: Use DROP FUNCTION first.
\df dfunc
\df dfunc
List of functions
List of functions
Schema | Name | Result data type | Argument data types
Schema | Name | Result data type | Argument data types
| Type
--------+-------+------------------+-------------------------------------------------
--------+-------+------------------+-------------------------------------------------
+--------
public | dfunc | integer | VARIADIC a integer[] DEFAULT ARRAY[]::integer[]
public | dfunc | integer | VARIADIC a integer[] DEFAULT ARRAY[]::integer[]
| normal
(1 row)
(1 row)
drop function dfunc(a variadic int[]);
drop function dfunc(a variadic int[]);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment