]> review.fuel-infra Code Review - packages/trusty/mysql-wsrep-5.6.git/blob
f03067c3bb6972f77ce0d604aa2eef8d57055250
[packages/trusty/mysql-wsrep-5.6.git] /
1 /*
2    Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
16 */
17
18 package com.mysql.clusterj.core.metadata;
19
20 import com.mysql.clusterj.core.query.CandidateIndexImpl;
21 import com.mysql.clusterj.core.spi.DomainTypeHandler;
22 import com.mysql.clusterj.core.store.Dictionary;
23 import com.mysql.clusterj.core.store.Index;
24 import com.mysql.clusterj.core.util.I18NHelper;
25 import com.mysql.clusterj.core.util.Logger;
26 import com.mysql.clusterj.core.util.LoggerFactoryService;
27
28 import java.util.Arrays;
29
30 /** IndexHandlerImpl represents indices defined in the cluster.
31  * One instance of this class represents either an ordered index or a unique
32  * hash index. So a unique index that results in creating two indices will
33  * be represented by two instances of IndexHandlerImpl.
34  * The Dictionary access to unique indexes requires the suffix "$unique"
35  * to be appended to the name, but the NdbTransaction access requires that
36  * the suffix not be used. This class is responsible for mediating the
37  * difference.
38  * <p>
39  * The simple case is one index => one field => one column. 
40  * <p>
41  * For ClusterJ and JPA, indexes can also support multiple columns, with each column 
42  * mapped to one field. This pattern is used for compound primary keys. In this case,
43  * there is one instance of IndexHandlerImpl for each index, and the columnNames
44  * and fields have the same cardinality.
45  * This is one index => multiple (one field => one column)
46  * <p>
47  * For JPA, indexes can also support one field mapped to multiple columns, which is
48  * the pattern used for compound foreign keys to represent relationships.
49  * In this case, there is a single instance of IndexHandlerImpl for each index. The 
50  * columnNames lists the columns covered by the index, and there is one field. The
51  * field manages an instance of the object id class for the relationship.
52  * This is one index => one field => multiple columns.
53  * <p>
54  *
55  */
56 public class IndexHandlerImpl {
57
58     /** My message translator */
59     static final I18NHelper local = I18NHelper.getInstance(IndexHandlerImpl.class);
60
61     /** My logger */
62     static final Logger logger = LoggerFactoryService.getFactory().getInstance(IndexHandlerImpl.class);
63
64     /** The unique suffix. */
65     static final String UNIQUE_SUFFIX = "$unique";
66
67     /** My class */
68     protected String className;
69
70     /** My table */
71     protected String tableName;
72
73     /** The indexName of the index. */
74     private String indexName;
75
76     /** The store Index of this index. */
77     protected Index storeIndex;
78
79     /** This is a unique index? */
80     protected boolean unique = true;
81
82     /** The fields (corresponding to the columnNames) in the index. */
83     protected AbstractDomainFieldHandlerImpl[] fields;
84
85     /** The columnNames in the index. */
86     protected final String[] columnNames;
87
88     /** This index is usable (all fields are mapped) */
89     private boolean usable = true;
90
91     /** The reason the index is not usable */
92     private String reason = null;
93
94     /** Construct an IndexHandlerImpl from an index name and column names.
95      * This constructor is used when the column handlers are not yet known.
96      * @param domainTypeHandler the domain type handler
97      * @param dictionary the dictionary for validation
98      * @param storeIndex the store index
99      * @param columnNames the column names for the index
100      */
101     public IndexHandlerImpl(DomainTypeHandler<?> domainTypeHandler,
102             Dictionary dictionary, Index storeIndex, String[] columnNames) {
103         this.className = domainTypeHandler.getName();
104         this.storeIndex = storeIndex;
105         this.indexName = storeIndex.getName();
106         this.tableName = domainTypeHandler.getTableName();
107         this.columnNames = columnNames;
108         int numberOfColumns = columnNames.length;
109         // the fields are not yet known; will be filled later 
110         this.fields = new AbstractDomainFieldHandlerImpl[numberOfColumns];
111         this.unique = storeIndex.isUnique();
112         if (logger.isDebugEnabled()) logger.debug(toString());
113     }
114
115     /** Construct an IndexHandlerImpl from an index declared on a field.
116      * There may be more than one column in the index; the columns are taken from the
117      * columns mapped by the field.
118      * @param domainTypeHandler the domain type handler
119      * @param dictionary the Dictionary
120      * @param indexName the index name
121      * @param fmd the DomainFieldHandlerImpl that corresponds to the column
122      */
123     public IndexHandlerImpl(DomainTypeHandler<?> domainTypeHandler,
124             Dictionary dictionary, String indexName, AbstractDomainFieldHandlerImpl fmd) {
125         this.className = domainTypeHandler.getName();
126         this.indexName = indexName;
127         this.tableName = domainTypeHandler.getTableName();
128         this.storeIndex = getIndex(dictionary, tableName, indexName);
129         this.unique = isUnique(storeIndex);
130         this.columnNames = fmd.getColumnNames();
131         this.fields = new AbstractDomainFieldHandlerImpl[]{fmd};
132         if (logger.isDebugEnabled()) logger.debug(toString());
133     }
134
135     /** Create a CandidateIndexImpl from this IndexHandlerImpl.
136      * The CandidateIndexImpl is used to decide on the strategy for a query.
137      *
138      */
139     public CandidateIndexImpl toCandidateIndexImpl() {
140         if (!usable) {
141             return CandidateIndexImpl.getIndexForNullWhereClause();
142         } else {
143             return new CandidateIndexImpl(
144                     className, storeIndex, unique, fields);
145         }
146     }
147
148     @Override
149     public String toString() {
150         StringBuffer buffer = new StringBuffer();
151         buffer.append("IndexHandler for class ");
152         buffer.append(className);
153         buffer.append(" index: ");
154         buffer.append(indexName);
155         buffer.append(" unique: ");
156         buffer.append(unique);
157         buffer.append(" columns: ");
158         buffer.append(Arrays.toString(columnNames));
159         return buffer.toString();
160     }
161
162     /** Set the DomainFieldHandlerImpl once it's known.
163      *
164      * @param i the index into the fields array
165      * @param fmd the DomainFieldHandlerImpl for the corresponding column
166      */
167     public void setDomainFieldHandlerFor(int i, AbstractDomainFieldHandlerImpl fmd) {
168         fields[i] = fmd;
169         fmd.validateIndexType(indexName, unique);
170     }
171
172     /** Accessor for columnNames. */
173     public String[] getColumnNames() {
174         return columnNames;
175     }
176
177     /** Validate that all columnNames have fields.
178      * 
179      */
180     public void assertAllColumnsHaveFields() {
181         for (int i = 0; i < columnNames.length; ++i) {
182             AbstractDomainFieldHandlerImpl fmd = fields[i];
183             if (fmd == null || !(columnNames[i].equals(fmd.getColumnName()))) {
184                 usable = false;
185                 reason = local.message(
186                         "ERR_Index_Mismatch", className, indexName, columnNames[i]);
187             }
188         }
189     }
190
191     protected boolean isUnique(Index storeIndex) {
192         return storeIndex.isUnique();
193     }
194
195     public boolean isUsable() {
196         return usable;
197     }
198
199     public String getReason() {
200         return reason;
201     }
202
203     protected Index getIndex(Dictionary dictionary,
204             String tableName, String indexName) {
205         return dictionary.getIndex(indexName, tableName, indexName);
206     }
207
208     public String getIndexName() {
209         return indexName;
210     }
211
212 }