| // 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); |
| } |
| } |