1515package ast
1616
1717import (
18+ "context"
1819 "fmt"
1920 "strings"
2021
2122 "github.com/cockroachdb/errors"
2223 vitess "github.com/dolthub/vitess/go/vt/sqlparser"
2324
25+ "github.com/dolthub/doltgresql/core/id"
2426 "github.com/dolthub/doltgresql/postgres/parser/parser"
2527 "github.com/dolthub/doltgresql/postgres/parser/sem/tree"
2628 "github.com/dolthub/doltgresql/postgres/parser/types"
@@ -38,27 +40,41 @@ func nodeCreateFunction(ctx *Context, node *tree.CreateFunction) (vitess.Stateme
3840 }
3941 // Grab the general information that we'll need to create the function
4042 tableName := node .Name .ToTableName ()
41- retType := pgtypes .Void
42- if len (node .RetType ) == 1 {
43+ var retType * pgtypes.DoltgresType
44+ if len (node .RetType ) == 0 {
45+ retType = pgtypes .Void
46+ } else if ! node .ReturnsTable { // Return types may specify "trigger", but this doesn't apply elsewhere
4347 switch typ := node .RetType [0 ].Type .(type ) {
4448 case * types.T :
4549 retType = pgtypes .NewUnresolvedDoltgresType ("" , strings .ToLower (typ .Name ()))
46- default :
47- sqlString := strings .ToLower (typ .SQLString ())
48- if sqlString == "trigger" {
50+ case * tree.UnresolvedObjectName :
51+ if typ .NumParts == 1 && typ .SQLString () == "trigger" {
4952 retType = pgtypes .Trigger
5053 } else {
51- retType = pgtypes .NewUnresolvedDoltgresType ("" , sqlString )
54+ _ , retType , err = nodeResolvableTypeReference (ctx , typ )
55+ if err != nil {
56+ return nil , err
57+ }
5258 }
59+ default :
60+ return nil , fmt .Errorf ("unsupported ResolvableTypeReference type: %T" , typ )
5361 }
62+ } else {
63+ retType = createAnonymousCompositeType (node .RetType )
5464 }
65+
5566 paramNames := make ([]string , len (node .Args ))
5667 paramTypes := make ([]* pgtypes.DoltgresType , len (node .Args ))
5768 for i , arg := range node .Args {
5869 paramNames [i ] = arg .Name .String ()
5970 switch argType := arg .Type .(type ) {
6071 case * types.T :
6172 paramTypes [i ] = pgtypes .NewUnresolvedDoltgresType ("" , strings .ToLower (argType .Name ()))
73+ case * tree.UnresolvedObjectName :
74+ _ , paramTypes [i ], err = nodeResolvableTypeReference (ctx , argType )
75+ if err != nil {
76+ return nil , err
77+ }
6278 default :
6379 paramTypes [i ] = pgtypes .NewUnresolvedDoltgresType ("" , strings .ToLower (argType .SQLString ()))
6480 }
@@ -121,11 +137,38 @@ func nodeCreateFunction(ctx *Context, node *tree.CreateFunction) (vitess.Stateme
121137 parsedBody ,
122138 sqlDef ,
123139 sqlDefParsed ,
124- node .SetOf ,
140+ node .ReturnsSetOf ,
125141 ),
126142 }, nil
127143}
128144
145+ // createAnonymousCompositeType creates a new DoltgresType for the anonymous composite return
146+ // type for a function, as represented by the |fieldTypes| that were specified in the function
147+ // definition.
148+ func createAnonymousCompositeType (fieldTypes []tree.SimpleColumnDef ) * pgtypes.DoltgresType {
149+ attrs := make ([]pgtypes.CompositeAttribute , len (fieldTypes ))
150+ for i , fieldType := range fieldTypes {
151+ attrs [i ] = pgtypes .NewCompositeAttribute (nil , id .Null , fieldType .Name .String (),
152+ id .NewType ("" , fieldType .Type .SQLString ()), int16 (i ), "" )
153+ }
154+
155+ typeIdString := "table("
156+ for i , attr := range attrs {
157+ if i > 0 {
158+ typeIdString += ","
159+ }
160+ typeIdString += attr .Name
161+ typeIdString += ":"
162+ typeIdString += attr .TypeID .TypeName ()
163+ }
164+ typeIdString += ")"
165+
166+ // NOTE: there is no schema needed, since these types are anonymous and can't be directly referenced
167+ typeId := id .NewType ("" , typeIdString )
168+
169+ return pgtypes .NewCompositeType (context .Background (), id .Null , id .NullType , typeId , attrs )
170+ }
171+
129172// handleLanguageSQL handles parsing SQL definition strings in both CREATE FUNCTION and CREATE PROCEDURE.
130173func handleLanguageSQL (definition string , paramNames []string , paramTypes []* pgtypes.DoltgresType ) (string , vitess.Statement , error ) {
131174 stmt , err := parser .ParseOne (definition )
0 commit comments