foreignKeyComparableTypes returns whether the two given types are able to be used as parent/child columns in a foreign key.
(ctx *sql.Context, castColl *casts.Collection, from sql.Type, to sql.Type)
| 51 | // foreignKeyComparableTypes returns whether the two given types are able to be used as parent/child columns in a |
| 52 | // foreign key. |
| 53 | func foreignKeyComparableTypes(ctx *sql.Context, castColl *casts.Collection, from sql.Type, to sql.Type) bool { |
| 54 | dtFrom, ok := from.(*types.DoltgresType) |
| 55 | if !ok { |
| 56 | return false // should never be possible |
| 57 | } |
| 58 | |
| 59 | dtTo, ok := to.(*types.DoltgresType) |
| 60 | if !ok { |
| 61 | return false // should never be possible |
| 62 | } |
| 63 | |
| 64 | if dtFrom.Equals(dtTo) { |
| 65 | return true |
| 66 | } |
| 67 | |
| 68 | fromLiteral := expression.NewLiteral(dtFrom.Zero(), from) |
| 69 | toLiteral := expression.NewLiteral(dtTo.Zero(), to) |
| 70 | |
| 71 | // a foreign key between two different types is valid if there is an equality operator on the two types |
| 72 | // TODO: there are some subtleties in postgres not captured by this logic, e.g. a foreign key from double -> int |
| 73 | // is valid, but the reverse is not. This works fine, but is more permissive than postgres is. |
| 74 | eq := framework.GetBinaryFunction(framework.Operator_BinaryEqual).Compile(ctx, "=", fromLiteral, toLiteral) |
| 75 | if eq == nil || eq.StashedError() != nil { |
| 76 | return false |
| 77 | } |
| 78 | |
| 79 | // Additionally, we need to be able to convert freely between the two types in both directions, since we do this |
| 80 | // during the process of enforcing the constraints |
| 81 | forwardConversion, fErr := castColl.GetAssignmentCast(ctx, dtFrom, dtTo) |
| 82 | reverseConversion, rErr := castColl.GetAssignmentCast(ctx, dtTo, dtFrom) |
| 83 | |
| 84 | return fErr == nil && rErr == nil && forwardConversion.ID.IsValid() && reverseConversion.ID.IsValid() |
| 85 | } |
no test coverage detected