MCPcopy Create free account
hub / github.com/dolthub/doltgresql / WithChildren

Method WithChildren

server/expression/in_tuple.go:179–247  ·  view source on GitHub ↗

WithChildren implements the sql.Expression interface.

(ctx *sql.Context, children ...sql.Expression)

Source from the content-addressed store, hash-verified

177
178// WithChildren implements the sql.Expression interface.
179func (it *InTuple) WithChildren(ctx *sql.Context, children ...sql.Expression) (sql.Expression, error) {
180 if len(children) != 2 {
181 return nil, sql.ErrInvalidChildrenNumber.New(it, len(children), 2)
182 }
183 rightTuple, ok := children[1].(expression.Tuple)
184 if !ok {
185 return nil, errors.Errorf("%T: expected right child to be `%T` but has type `%T`", it, expression.Tuple{}, children[1])
186 }
187 if len(rightTuple) == 0 {
188 return nil, errors.Errorf("IN must contain at least 1 expression")
189 }
190 // We'll only resolve the comparison functions once we have all Doltgres types.
191 // We may see GMS types during some analyzer steps, so we should wait until those are done.
192 if leftType, ok := children[0].Type(ctx).(*pgtypes.DoltgresType); ok {
193 // Rather than finding and resolving a comparison function every time we call Eval, we resolve them once and
194 // reuse the functions. We also want to avoid re-assigning the parameters of the comparison functions since that
195 // will also cause the functions to resolve again. To do this, we store expressions within our struct that the
196 // functions reference, so we can freely switch the values within the literals without changing anything
197 // regarding the comparison functions. This is usually unsafe, but since we're verifying the types returned by
198 // the parameters, and assigning the values to our own literals, we do not have to worry. This offers a
199 // significant speedup as function resolution is very expensive, so we want to do it as few times as possible
200 // (preferably once).
201 staticLiteral := expression.NewLiteral(nil, leftType)
202 arrayLiterals := make([]*expression.Literal, len(rightTuple))
203 // Each expression may be a different type (which is valid), so we need a comparison function for each expression.
204 compFuncs := make([]framework.Function, len(rightTuple))
205 allValidChildren := true
206 for i, rightExpr := range rightTuple {
207 rightType, ok := rightExpr.Type(ctx).(*pgtypes.DoltgresType)
208 if !ok {
209 allValidChildren = false
210 break
211 }
212 arrayLiterals[i] = expression.NewLiteral(nil, rightType)
213 compFunc := framework.GetBinaryFunction(framework.Operator_BinaryEqual).Compile(ctx, "internal_in_comparison", staticLiteral, arrayLiterals[i])
214 if compFunc == nil {
215 return nil, errors.Errorf("operator does not exist: %s = %s", leftType.String(), rightType.String())
216 }
217 cid := compFunc.Type(ctx).(*pgtypes.DoltgresType).ID
218 if cid != pgtypes.Bool.ID {
219 // Prepared statement binding values will need explicit casting to appropriate type
220 ec := NewAssignmentCast(arrayLiterals[i], pgtypes.Unknown, staticLiteral.Type(ctx).(*pgtypes.DoltgresType))
221 compFunc = framework.GetBinaryFunction(framework.Operator_BinaryEqual).Compile(ctx, "internal_in_comparison", staticLiteral, ec)
222 if compFunc == nil || compFunc.StashedError() != nil {
223 return nil, errors.Errorf("operator does not exist: %s = %s", leftType.String(), rightType.String())
224 }
225 cid = compFunc.Type(ctx).(*pgtypes.DoltgresType).ID
226 if cid != pgtypes.Bool.ID {
227 // This should never happen, but this is just to be safe
228 return nil, errors.Errorf("%T: found equality comparison that does not return a bool", it)
229 }
230 }
231 compFuncs[i] = compFunc
232 }
233 if allValidChildren {
234 return &InTuple{
235 leftExpr: children[0],
236 rightExpr: rightTuple,

Callers 1

WithResolvedChildrenMethod · 0.95

Calls 7

GetBinaryFunctionFunction · 0.92
NewAssignmentCastFunction · 0.85
CompileMethod · 0.80
StashedErrorMethod · 0.80
ErrorfMethod · 0.65
TypeMethod · 0.65
StringMethod · 0.65

Tested by

no test coverage detected