blob: b7f8a93b2c843b87fd04d0fde672d43961dd2320 [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package com.cloud.utils.db;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.cloud.utils.Pair;
import com.cloud.utils.db.SearchBase.Condition;
import com.cloud.utils.db.SearchBase.Select;
/**
* big joins or high performance searches, it is much better to
*/
public class SearchCriteria<K> {
public enum Op {
GT(" > ? ", 1), GTEQ(" >= ? ", 1), LT(" < ? ", 1), LTEQ(" <= ? ", 1), EQ(" = ? ", 1), NEQ(" != ? ", 1), BETWEEN(" BETWEEN ? AND ? ", 2), NBETWEEN(
" NOT BETWEEN ? AND ? ",
2), IN(" IN () ", -1), NOTIN(" NOT IN () ", -1), LIKE(" LIKE ? ", 1), NLIKE(" NOT LIKE ? ", 1), NIN(" NOT IN () ", -1), NULL(" IS NULL ", 0), NNULL(
" IS NOT NULL ",
0), SC(" () ", 1), TEXT(" () ", 1), RP("", 0), AND(" AND ", 0), OR(" OR ", 0), NOT(" NOT ", 0);
private final String op;
int params;
Op(String op, int params) {
this.op = op;
this.params = params;
}
@Override
public String toString() {
return op;
}
public int getParams() {
return params;
}
}
public enum Func {
NATIVE("@", 1), MAX("MAX(@)", 1), MIN("MIN(@)", 1), FIRST("FIRST(@)", 1), LAST("LAST(@)", 1), SUM("SUM(@)", 1), COUNT("COUNT(@)", 1), DISTINCT("DISTINCT(@)", 1);
private String func;
private int count;
Func(String func, int params) {
this.func = func;
this.count = params;
}
@Override
public String toString() {
return func;
}
public int getCount() {
return count;
}
}
public enum SelectType {
Fields, Entity, Single, Result
}
private final Map<String, Attribute> _attrs;
private final ArrayList<Condition> _conditions;
private ArrayList<Condition> _additionals = null;
private HashMap<String, Object[]> _params = new HashMap<String, Object[]>();
private int _counter;
private HashMap<String, JoinBuilder<SearchCriteria<?>>> _joins;
private final ArrayList<Select> _selects;
private final GroupBy<? extends SearchBase<?, ?, K>, ?, K> _groupBy;
private final List<Object> _groupByValues;
private final Class<K> _resultType;
private final SelectType _selectType;
protected SearchCriteria(SearchBase<?, ?, K> sb) {
this._attrs = sb._attrs;
this._conditions = sb._conditions;
this._additionals = new ArrayList<Condition>();
this._counter = 0;
this._joins = null;
if (sb._joins != null) {
_joins = new HashMap<String, JoinBuilder<SearchCriteria<?>>>(sb._joins.size());
for (Map.Entry<String, JoinBuilder<SearchBase<?, ?, ?>>> entry : sb._joins.entrySet()) {
JoinBuilder<SearchBase<?, ?, ?>> value = entry.getValue();
_joins.put(entry.getKey(),
new JoinBuilder<SearchCriteria<?>>(value.getT().create(), value.getFirstAttribute(), value.getSecondAttribute(), value.getType()));
}
}
_selects = sb._selects;
_groupBy = sb._groupBy;
if (_groupBy != null) {
_groupByValues = new ArrayList<Object>();
} else {
_groupByValues = null;
}
_resultType = sb._resultType;
_selectType = sb._selectType;
}
protected void setParameters(HashMap<String, Object[]> parameters) {
_params = parameters;
}
public SelectType getSelectType() {
return _selectType;
}
public void getSelect(StringBuilder str, int insertAt) {
if (_selects == null || _selects.size() == 0) {
return;
}
for (Select select : _selects) {
String func = select.func.toString() + ",";
if (select.attr == null) {
func = func.replace("@", "*");
} else {
func = func.replace("@", select.attr.table + "." + select.attr.columnName);
}
str.insert(insertAt, func);
insertAt += func.length();
if (select.field == null) {
break;
}
}
str.delete(insertAt - 1, insertAt);
}
public List<Field> getSelectFields() {
List<Field> fields = new ArrayList<Field>(_selects.size());
for (Select select : _selects) {
fields.add(select.field);
}
return fields;
}
public void setParameters(String conditionName, Object... params) {
assert _conditions.contains(new Condition(conditionName)) || _additionals.contains(new Condition(conditionName)) : "Couldn't find " + conditionName;
_params.put(conditionName, params);
}
public boolean isSelectAll() {
return _selects == null || _selects.size() == 0;
}
protected JoinBuilder<SearchCriteria<?>> findJoin(Map<String, JoinBuilder<SearchCriteria<?>>> jbmap, String joinName) {
JoinBuilder<SearchCriteria<?>> jb = jbmap.get(joinName);
if (jb != null) {
return jb;
}
for (JoinBuilder<SearchCriteria<?>> j2 : jbmap.values()) {
SearchCriteria<?> sc = j2.getT();
if (sc._joins != null)
jb = findJoin(sc._joins, joinName);
if (jb != null) {
return jb;
}
}
assert (false) : "Unable to find a join by the name " + joinName;
return null;
}
public void setJoinParameters(String joinName, String conditionName, Object... params) {
JoinBuilder<SearchCriteria<?>> join = findJoin(_joins, joinName);
assert (join != null) : "Incorrect join name specified: " + joinName;
join.getT().setParameters(conditionName, params);
}
public SearchCriteria<?> getJoin(String joinName) {
return _joins.get(joinName).getT();
}
public Pair<GroupBy<?, ?, ?>, List<Object>> getGroupBy() {
return _groupBy == null ? null : new Pair<GroupBy<?, ?, ?>, List<Object>>(_groupBy, _groupByValues);
}
public void setGroupByValues(Object... values) {
for (Object value : values) {
_groupByValues.add(value);
}
}
public Class<K> getResultType() {
return _resultType;
}
@Deprecated
public void addAnd(String field, Op op, Object... values) {
String name = Integer.toString(_counter++);
addCondition(name, " AND ", field, op);
setParameters(name, values);
}
@Deprecated
public void addAnd(Attribute attr, Op op, Object... values) {
String name = Integer.toString(_counter++);
addCondition(name, " AND ", attr, op);
setParameters(name, values);
}
@Deprecated
public void addOr(String field, Op op, Object... values) {
String name = Integer.toString(_counter++);
addCondition(name, " OR ", field, op);
setParameters(name, values);
}
protected void addCondition(String conditionName, String cond, String fieldName, Op op) {
Attribute attr = _attrs.get(fieldName);
assert attr != null : "Unable to find field: " + fieldName;
addCondition(conditionName, cond, attr, op);
}
protected void addCondition(String conditionName, String cond, Attribute attr, Op op) {
Condition condition = new Condition(conditionName, /*(_conditions.size() + _additionals.size()) == 0 ? "" : */cond, attr, op);
_additionals.add(condition);
}
public String getWhereClause() {
StringBuilder sql = new StringBuilder();
int i = 0;
for (Condition condition : _conditions) {
if (condition.isPreset()) {
_params.put(condition.name, condition.presets);
}
Object[] params = _params.get(condition.name);
if ((condition.op == null || condition.op.params == 0) || (params != null)) {
condition.toSql(sql, params, i++);
}
}
for (Condition condition : _additionals) {
if (condition.isPreset()) {
_params.put(condition.name, condition.presets);
}
Object[] params = _params.get(condition.name);
if ((condition.op.params == 0) || (params != null)) {
condition.toSql(sql, params, i++);
}
}
return sql.toString();
}
public List<Pair<Attribute, Object>> getValues() {
ArrayList<Pair<Attribute, Object>> params = new ArrayList<Pair<Attribute, Object>>(_params.size());
for (Condition condition : _conditions) {
Object[] objs = _params.get(condition.name);
if (condition.op != null && condition.op.params != 0 && objs != null) {
getParams(params, condition, objs);
}
}
for (Condition condition : _additionals) {
Object[] objs = _params.get(condition.name);
if ((condition.op.params == 0) || (objs != null)) {
getParams(params, condition, objs);
}
}
return params;
}
public Collection<JoinBuilder<SearchCriteria<?>>> getJoins() {
return _joins != null ? _joins.values() : null;
}
private void getParams(ArrayList<Pair<Attribute, Object>> params, Condition condition, Object[] objs) {
if (condition.op == Op.SC) {
assert (objs != null && objs.length > 0) : " Where's your search criteria object? " + condition.name;
params.addAll(((SearchCriteria<?>)objs[0]).getValues());
return;
}
if (objs != null && objs.length > 0) {
for (Object obj : objs) {
if ((condition.op != Op.EQ && condition.op != Op.NEQ) || (obj != null)) {
params.add(new Pair<Attribute, Object>(condition.attr, obj));
}
}
}
}
public Pair<String, ArrayList<Object>> toSql() {
StringBuilder sql = new StringBuilder();
return new Pair<String, ArrayList<Object>>(sql.toString(), null);
}
}