Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,6 @@ CROSS JOIN LATERAL unnest(
WHERE {routineWhere}
AND ns.nspname NOT IN ('pg_catalog', 'information_schema'){schemaWhere}
AND NOT EXISTS (SELECT 1 FROM pg_depend dep WHERE dep.objid = proc.oid AND dep.deptype IN ('e', 'x'))
AND param.parameter_name IS NOT NULL
AND param.parameter_mode <> 't'
ORDER BY proc.oid, param.ordinal_position
""";
Expand All @@ -231,7 +230,12 @@ AND param.parameter_mode <> 't'
continue;

var ordinal = (int)reader.GetInt64(positionOrdinal);
var parameterName = reader.GetString(nameOrdinal);
var parameterName = reader.GetStringNull(nameOrdinal);

// PostgreSQL leaves unnamed arguments as NULL or an empty string in proargnames; name them positionally
if (string.IsNullOrEmpty(parameterName))
parameterName = $"${ordinal}";

var direction = MapParameterDirection(reader.GetString(directionOrdinal));
var typeName = reader.GetString(typeNameOrdinal);
var formattedTypeName = AdjustFormattedTypeName(reader.GetString(formattedTypeOrdinal));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
-- unnamed input combined with a named OUT parameter => proargnames = {'', 'result'}
CREATE OR REPLACE FUNCTION public."UnnamedInputWithOutput"(
integer,
OUT "Result" text
)
LANGUAGE sql
AS $$
SELECT 'x'::text;
$$;

-- unnamed input on a RETURNS TABLE function => proargnames = {''}
CREATE OR REPLACE FUNCTION public."UnnamedInputReturnsTable"(
integer
)
RETURNS TABLE ("Id" integer)
LANGUAGE sql
AS $$
SELECT 1;
$$;

-- no named parameters at all => proargnames IS NULL
CREATE OR REPLACE FUNCTION public."UnnamedInputScalar"(
integer
)
RETURNS integer
LANGUAGE sql
AS $$
SELECT $1;
$$;
47 changes: 47 additions & 0 deletions test/SchemaSaurus.PostgreSql.Tests/UnnamedParameterTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using SchemaSaurus.Metadata;
using SchemaSaurus.PostgreSql.Tests.Fixtures;

namespace SchemaSaurus.PostgreSql.Tests;

public class UnnamedParameterTests(DatabaseFixture databaseFixture)
: SchemaReaderTestBase(databaseFixture)
{
[Fact]
public async Task WhenFunctionHasUnnamedInputWithNamedOutputThenParametersArePositionallyNamed()
{
var model = await GetDatabaseModelAsync();
var func = model.ScalarFunctions.First(f => f.QualifiedName.Name == "UnnamedInputWithOutput");

func.Parameters.Should().HaveCount(2);

var input = func.Parameters.Single(p => p.Ordinal == 1);
input.Name.Should().Be("$1");
input.Direction.Should().Be(ParameterDirection.Input);
input.SystemType.Should().Be(typeof(int));

var output = func.Parameters.Single(p => p.Ordinal == 2);
output.Name.Should().Be("Result");
output.Direction.Should().Be(ParameterDirection.Output);
}

[Fact]
public async Task WhenTableValuedFunctionHasUnnamedInputThenParameterIsPositionallyNamed()
{
var model = await GetDatabaseModelAsync();
var func = model.TableValuedFunctions.First(f => f.QualifiedName.Name == "UnnamedInputReturnsTable");

func.Parameters.Should().HaveCount(1);
func.Parameters[0].Name.Should().Be("$1");
func.Parameters[0].Ordinal.Should().Be(1);
}

[Fact]
public async Task WhenFunctionHasNoNamedParametersThenParameterIsPositionallyNamed()
{
var model = await GetDatabaseModelAsync();
var func = model.ScalarFunctions.First(f => f.QualifiedName.Name == "UnnamedInputScalar");

func.Parameters.Should().HaveCount(1);
func.Parameters[0].Name.Should().Be("$1");
}
}