com.squid.core.sql.AnalyzerMapping Maven / Gradle / Ivy
/*******************************************************************************
* Copyright © Squid Solutions, 2016
*
* This file is part of Open Bouquet software.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation (version 3 of the License).
*
* There is a special FOSS exception to the terms and conditions of the
* licenses as they are applied to this program. See LICENSE.txt in
* the directory of this program distribution.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Squid Solutions also offers commercial licenses with additional warranties,
* professional functionalities or services. If you purchase a commercial
* license, then it supersedes and replaces any other agreement between
* you and Squid Solutions (above licenses and LICENSE.txt included).
* See http://www.squidsolutions.com/EnterpriseBouquet/
*******************************************************************************/
package com.squid.core.sql;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import com.squid.core.database.model.Column;
import com.squid.core.database.model.KeyPair;
import com.squid.core.domain.operators.IntrinsicOperators;
import com.squid.core.domain.operators.Operators;
import com.squid.core.expression.Compose;
import com.squid.core.expression.ExpressionAST;
import com.squid.core.expression.Operator;
import com.squid.core.expression.reference.ColumnReference;
import com.squid.core.expression.reference.ForeignKeyReference;
import com.squid.core.sql.model.Scope;
/**
* this is the part of the analyzer responsible for mapping equi-joins
* @author sergefantino
*
*/
public class AnalyzerMapping {
public class Mapping {
public Scope scope;
public Column column;
public Mapping(Scope scope, Column column) {
super();
this.scope = scope;
this.column = column;
}
}
private HashMap> equiMap = new HashMap>();
public List getMapping(Column subject) {
return equiMap.get(subject);
}
public void analyzeRelation(Scope joinScope, ExpressionAST relation) {
List keys = factorRelation(relation);
for (KeyPair kp : keys) {
addMapping(kp.getExported(), new Mapping(joinScope, kp.getPrimary()));
addMapping(kp.getPrimary(), new Mapping(joinScope, kp.getExported()));
}
}
protected void addMapping(Column source, Mapping mapping) {
if (equiMap.containsKey(source)) {
List contents = equiMap.get(source);
contents.add(mapping);
} else {
List contents = new LinkedList();
contents.add(mapping);
equiMap.put(source, contents);
}
}
public List factorRelation(ExpressionAST relation) {
// it must be an operator or a FK
if (relation instanceof Operator) {
// it can be either a single == or a list
Operator op = (Operator)relation;
return factorRelationRaw(op);
} else if (relation instanceof ForeignKeyReference) {
ForeignKeyReference ref = (ForeignKeyReference)relation;
// easy going
return ref.getForeignKey().getKeys();
} else {
// no good
return Collections.emptyList();
}
}
private List factorRelationRaw(Operator op) {
if (op.getOperatorDefinition().getId()==IntrinsicOperators.IDENTITY) {
// ok, just ignore
return factorRelation(op.getArguments().get(0));
} else if (op.getOperatorDefinition()==Operators.EQUAL) {
// ok, simple case
KeyPair kp = factorEqui(op);
if (kp!=null) {
return Collections.singletonList(kp);
} else {
return Collections.emptyList();
}
} else if (op.getOperatorDefinition()==Operators.AND) {
// ok, hope it's not embedded ?
LinkedList result = new LinkedList();
for (ExpressionAST arg : op.getArguments()) {
List factor = factorRelation(arg);
if (factor.isEmpty()) {
//return factor;// shortcut
// ignore in case of some constant ?
} else {
result.addAll(factor);
}
}
// looks good
return result;
} else {
// not good
return Collections.emptyList();
}
}
private KeyPair factorEqui(Operator op) {
// must have 2 arguments
if (op.getArguments().size()!=2) {
return null;
}
ExpressionAST first = op.getArguments().get(0);
ExpressionAST second = op.getArguments().get(1);
// factor columns
Column c1 = factorColumn(first);
Column c2 = factorColumn(second);
if (c1!=null && c2!=null) {
// sounds good
return new KeyPair(c1, c2, -1);
} else {
return null;
}
}
private Column factorColumn(ExpressionAST first) {
// ok, it is something like table.column... easy, isn't it?
if (first instanceof Compose) {
Compose compose = (Compose)first;
if (compose.getBody().size()==2) {
ExpressionAST head = compose.getHead();// just interested in the head - if it is a column then [0] must be a table
if (head instanceof ColumnReference) {
return ((ColumnReference)head).getColumn();
}
}
}
// else
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy