diff --git a/pgcli/packages/parseutils/meta.py b/pgcli/packages/parseutils/meta.py index df41cf4ee..8879511ed 100644 --- a/pgcli/packages/parseutils/meta.py +++ b/pgcli/packages/parseutils/meta.py @@ -151,10 +151,13 @@ def fields(self): if self.return_type.lower() == "void": return [] - elif not self.arg_modes: - # For functions without output parameters, the function name - # is used as the name of the output column. + elif not self.arg_modes or not self.arg_names or not self.arg_types: + # For functions without output parameters, the function name is + # used as the name of the output column. # E.g. 'SELECT unnest FROM unnest(...);' + # arg_names/arg_types can also be None (e.g. an unnamed variadic + # argument), which args() already guards against; without this the + # zip() below raised 'NoneType is not iterable'. return [ColumnMetadata(self.func_name, self.return_type, [])] return [ diff --git a/tests/parseutils/test_function_metadata.py b/tests/parseutils/test_function_metadata.py index c4000ab1c..2943d975d 100644 --- a/tests/parseutils/test_function_metadata.py +++ b/tests/parseutils/test_function_metadata.py @@ -11,3 +11,14 @@ def test_function_metadata_eq(): assert not (f1 == f3) assert hash(f1) == hash(f2) assert hash(f1) != hash(f3) + + +def test_function_metadata_fields_with_unnamed_variadic_arg(): + # A variadic argument can arrive with no name, so arg_names is None while + # arg_modes is set. fields() used to raise 'NoneType is not iterable' on + # the zip() (issue #1204); it now falls back to the function-name column. + f = FunctionMetadata( + 'public', 'labels', None, ['text[]'], ['v'], 'hstore', + False, False, False, False, None, + ) + assert [(c.name, c.datatype) for c in f.fields()] == [('labels', 'hstore')] \ No newline at end of file