Skip to content
Open
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
8 changes: 1 addition & 7 deletions server/plpgsql/interpreter_logic.go
Original file line number Diff line number Diff line change
Expand Up @@ -297,15 +297,9 @@ func convertRowsToRecords(schema sql.Schema, rows []sql.Row) [][]pgtypes.RecordV
for _, row := range rows {
record := make([]pgtypes.RecordValue, len(row))
for i, field := range row {
t := schema[i].Type
doltgresType, ok := t.(*pgtypes.DoltgresType)
if !ok {
panic("expected Doltgres type")
}

record[i] = pgtypes.RecordValue{
Value: field,
Type: doltgresType,
Type: schema[i].Type,
}
}
records = append(records, record)
Expand Down
31 changes: 18 additions & 13 deletions server/types/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,25 @@ func RecordToString(ctx *sql.Context, fields []RecordValue) (any, error) {
continue
}

doltgresType, ok := value.Type.(*DoltgresType)
if !ok {
return nil, fmt.Errorf(`expected *DoltgresType but found: %T`, value.Type)
}

str, err := doltgresType.IoOutput(ctx, value.Value)
if err != nil {
return "", err
}
if doltgresType.ID == Bool.ID {
str = string(str[0])
switch t := value.Type.(type) {
case *DoltgresType:
str, err := t.IoOutput(ctx, value.Value)
if err != nil {
return "", err
}
if t.ID == Bool.ID {
str = string(str[0])
}
sb.WriteString(quoteString(str))
case sql.Type:
val, err := t.SQL(ctx, []byte{}, value.Value)
if err != nil {
return nil, err
}
sb.WriteString(quoteString(val.ToString()))
default:
return nil, fmt.Errorf("unable to convert record to string; unsupported type: %T", t)
}

sb.WriteString(quoteString(str))
}
sb.WriteRune(')')

Expand Down
100 changes: 100 additions & 0 deletions testing/go/create_function_plpgsql_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,56 @@ $$ LANGUAGE plpgsql;`},
},
},
},
{
Name: "RETURNS TABLE - with real query ",
SetUpScript: []string{
`CREATE TABLE customers (
id INT PRIMARY KEY,
name TEXT
);`,
`CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT,
amount INT
);`,
`INSERT INTO customers VALUES (1, 'John'), (2, 'Jane');`,
`INSERT INTO orders VALUES (1, 1, 100), (2, 2, 10);`,
`CREATE OR REPLACE FUNCTION func2(n INT) RETURNS TABLE (c_id INT, c_name TEXT, c_total_spent INT)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT c.id,
c.name,
SUM(o.amount) AS total_spent
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name
HAVING SUM(o.amount) >= n
;
END;
$$;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func2(1);",
Expected: []sql.Row{
{"(1,John,100)"},
{"(2,Jane,10)"},
},
},
{
Query: "SELECT func2(11);",
Expected: []sql.Row{
{"(1,John,100)"},
},
},
{
Query: "SELECT func2(111);",
Expected: []sql.Row{},
},
},
},
{
Name: "RETURNS SETOF",
SetUpScript: []string{
Expand Down Expand Up @@ -654,6 +704,56 @@ $$ LANGUAGE plpgsql;`},
},
},
},
{
Name: "RETURNS TABLE with join query",
SetUpScript: []string{
`CREATE TABLE customers (
id INT PRIMARY KEY,
name TEXT
);`,
`CREATE TABLE orders (
id SERIAL PRIMARY KEY,
customer_id INT,
amount INT
);`,
`INSERT INTO customers VALUES (1, 'John'), (2, 'Jane');`,
`INSERT INTO orders VALUES (1, 1, 100), (2, 2, 10);`,
`CREATE OR REPLACE FUNCTION func2(n INT) RETURNS TABLE (c_id INT, c_name TEXT, c_total_spent INT)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT c.id,
c.name,
SUM(o.amount) AS total_spent
FROM customers c
JOIN orders o ON o.customer_id = c.id
GROUP BY c.id, c.name
HAVING SUM(o.amount) >= n
;
END;
$$;`,
},
Assertions: []ScriptTestAssertion{
{
Query: "SELECT func2(1);",
Expected: []sql.Row{
{"(1,John,100)"},
{"(2,Jane,10)"},
},
},
{
Query: "SELECT func2(11);",
Expected: []sql.Row{
{"(1,John,100)"},
},
},
{
Query: "SELECT func2(111);",
Expected: []sql.Row{},
},
},
},
{
Name: "RETURNS SETOF with composite param",
SetUpScript: []string{
Expand Down