in drools-compiler/src/main/java/org/drools/compiler/rule/builder/QueryElementBuilder.java [79:231]
public RuleConditionElement build( RuleBuildContext context,
BaseDescr descr,
QueryImpl query) {
PatternDescr patternDescr = (PatternDescr) descr;
Declaration[] params = query.getParameters();
List<BaseDescr> args = (List<BaseDescr>) patternDescr.getDescrs();
List<Declaration> requiredDeclarations = new ArrayList<>();
ObjectType argsObjectType = ClassObjectType.ObjectArray_ObjectType;
ReadAccessor arrayReader = new SelfReferenceClassFieldReader( Object[].class );
Pattern pattern = new Pattern( context.getNextPatternId(),
0, // tupleIndex is 0 by default
0, // patternIndex is 0 by default
argsObjectType,
null );
if ( !StringUtils.isEmpty( patternDescr.getIdentifier() ) ) {
if ( query.isAbductive() ) {
Declaration declr = context.getDeclarationResolver().getDeclaration( patternDescr.getIdentifier() );
if ( declr != null && ! patternDescr.isUnification() ) {
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Duplicate declaration " + patternDescr.getIdentifier() +", unable to bind abducted value" ) );
}
} else {
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Query binding is not supported by non-abductive queries : " + patternDescr.getIdentifier() ) );
}
}
boolean addAbductiveReturnArgument = query.isAbductive()
&& ! StringUtils.isEmpty( patternDescr.getIdentifier() )
&& args.size() < params.length;
if ( addAbductiveReturnArgument ) {
ExprConstraintDescr extraDescr = new ExprConstraintDescr( patternDescr.getIdentifier() );
extraDescr.setPosition( patternDescr.getConstraint().getDescrs().size() );
extraDescr.setType( ExprConstraintDescr.Type.POSITIONAL );
args.add( extraDescr );
}
QueryArgument[] arguments = new QueryArgument[params.length];
// Deal with the constraints, both positional and bindings
for ( BaseDescr base : args ) {
String expression = null;
boolean isPositional = false;
boolean isBinding = false;
BindingDescr bind = null;
ConstraintConnectiveDescr result = null;
if ( base instanceof BindingDescr ) {
bind = (BindingDescr) base;
expression = bind.getVariable() + ( bind.isUnification() ? " := " : " : " ) + bind.getExpression();
isBinding = true;
} else {
if ( base instanceof ExprConstraintDescr ) {
ExprConstraintDescr ecd = (ExprConstraintDescr) base;
expression = ecd.getExpression();
isPositional = ecd.getType() == ExprConstraintDescr.Type.POSITIONAL;
} else {
expression = base.getText();
}
result = parseExpression( context,
patternDescr,
expression );
if ( result == null ) {
// error, can't parse expression.
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Unable to parse constraint: \n" + expression ) );
continue;
}
isBinding = result.getDescrs().size() == 1 && result.getDescrs().get( 0 ) instanceof BindingDescr;
if ( isBinding ) {
bind = (BindingDescr) result.getDescrs().get( 0 );
}
}
if ( ( !isPositional ) && ( !isBinding ) ) {
// error, can't have non binding slots.
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Query's must use positional or bindings, not field constraints:\n" + expression ) );
} else if ( isPositional && isBinding ) {
// error, can't have positional binding slots.
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Query's can't use positional bindings:\n" + expression ) );
} else if ( isPositional ) {
processPositional( context,
query,
params,
arguments,
requiredDeclarations,
arrayReader,
pattern,
base,
expression,
result );
} else {
// it is binding
processBinding( context,
descr,
params,
arguments,
requiredDeclarations,
arrayReader,
pattern,
bind );
}
}
List<Integer> varIndexList = new ArrayList<>();
for (int i = 0; i < arguments.length; i++) {
if (!(arguments[i] instanceof QueryArgument.Declr)) {
if (arguments[i] instanceof QueryArgument.Var) {
varIndexList.add(i);
}
continue;
}
Class actual = ((QueryArgument.Declr) arguments[i]).getArgumentClass();
Declaration formalArgument = query.getParameters()[i];
Class formal = formalArgument.getDeclarationClass();
// with queries invoking each other, we won't know until runtime whether a declaration is input, output or else
// input argument require a broader type, while output types require a narrower type, so we check for both.
if ( ! ClassUtils.isTypeCompatibleWithArgumentType( actual, formal ) && ! ClassUtils.isTypeCompatibleWithArgumentType( formal, actual ) ) {
context.addError( new DescrBuildError( context.getParentDescr(),
descr,
null,
"Query is being invoked with known argument of type " + actual +
" at position " + i + ", but the expected query argument is of type " + formal ) );
}
}
return new QueryElement( pattern,
query.getName(),
arguments,
toIntArray( varIndexList ),
requiredDeclarations.toArray( new Declaration[requiredDeclarations.size()] ),
!patternDescr.isQuery(),
query.isAbductive() );
}