1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.hbql.mapping;
22
23 import org.apache.expreval.expr.ExpressionTree;
24 import org.apache.hadoop.hbase.hbql.client.HBqlException;
25 import org.apache.hadoop.hbase.hbql.client.HMapping;
26 import org.apache.hadoop.hbase.hbql.client.HRecord;
27 import org.apache.hadoop.hbase.hbql.filter.RecordFilter;
28 import org.apache.hadoop.hbase.hbql.impl.HConnectionImpl;
29 import org.apache.hadoop.hbase.hbql.impl.HRecordImpl;
30 import org.apache.hadoop.hbase.hbql.io.IO;
31 import org.apache.hadoop.hbase.hbql.parser.ParserUtil;
32 import org.apache.hadoop.hbase.hbql.statement.args.KeyInfo;
33 import org.apache.hadoop.hbase.hbql.util.Lists;
34 import org.apache.hadoop.hbase.hbql.util.Maps;
35
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Set;
39
40 public class TableMapping extends Mapping implements HMapping {
41
42 private static final long serialVersionUID = 3L;
43
44 private transient HConnectionImpl connection;
45 private boolean tempMapping;
46 private boolean systemMapping;
47 private KeyInfo keyInfo = null;
48
49 private final Map<String, HRecordAttrib> columnAttribByFamilyQualifiedNameMap = Maps.newHashMap();
50 private final Map<String, HRecordAttrib> versionAttribMap = Maps.newHashMap();
51 private final Map<String, List<HRecordAttrib>> columnAttribListByFamilyNameMap = Maps.newHashMap();
52
53 private final Map<String, HRecordAttrib> unMappedAttribsMap = Maps.newHashMap();
54
55
56 public TableMapping() {
57 }
58
59 public TableMapping(final HConnectionImpl conn,
60 final boolean tempMapping,
61 final boolean systemMapping,
62 final String mappingName,
63 final String tableName,
64 final KeyInfo keyInfo,
65 final List<FamilyMapping> familyMappingList) throws HBqlException {
66
67 super(mappingName, tableName);
68
69 this.connection = conn;
70 this.tempMapping = tempMapping;
71 this.systemMapping = systemMapping;
72 this.keyInfo = keyInfo;
73
74
75 if (keyInfo != null)
76 processColumnDefintion(ColumnDefinition.newKeyColumn(keyInfo));
77
78 if (familyMappingList != null) {
79 for (final FamilyMapping familyMapping : familyMappingList) {
80
81 if (familyMapping.getColumnDefinitionList() != null)
82 for (final ColumnDefinition columnDefinition : familyMapping.getColumnDefinitionList())
83 processColumnDefintion(columnDefinition);
84
85
86 if (familyMapping.includeUnmapped()) {
87 final String familyName = familyMapping.getFamilyName();
88 final ColumnDefinition columnDefinition = ColumnDefinition.newUnMappedColumn(familyName);
89 final HRecordAttrib attrib = new HRecordAttrib(columnDefinition);
90 this.addUnMappedAttrib(attrib);
91 }
92 }
93 }
94 }
95
96 private HConnectionImpl getConnection() {
97 return this.connection;
98 }
99
100 public KeyInfo getKeyInfo() {
101 return this.keyInfo;
102 }
103
104 public void validateKeyInfo(final String indexName) throws HBqlException {
105 if (!this.getKeyInfo().isWidthSpecified())
106 throw new HBqlException("Cannot use index " + indexName + " without a width value for KEY "
107 + this.getKeyInfo().getKeyName() + " in mapping " + this.getMappingName());
108 }
109
110 public HRecord newHRecord() throws HBqlException {
111 final MappingContext mappingContext = new MappingContext(this);
112 mappingContext.setResultAccessor(new HRecordResultAccessor(mappingContext));
113 return new HRecordImpl(mappingContext);
114 }
115
116 public HRecord newHRecord(final Map<String, Object> initMap) throws HBqlException {
117 final HRecord newrec = this.newHRecord();
118
119 for (final String name : initMap.keySet())
120 newrec.setCurrentValue(name, initMap.get(name));
121
122 return newrec;
123 }
124
125 private void processColumnDefintion(final ColumnDefinition columnDefinition) throws HBqlException {
126
127 final HRecordAttrib attrib = new HRecordAttrib(columnDefinition);
128
129 this.addAttribToVariableNameMap(attrib, attrib.getNamesForColumn());
130 this.addAttribToFamilyQualifiedNameMap(attrib);
131 this.addVersionAttrib(attrib);
132 this.addAttribToFamilyNameColumnListMap(attrib);
133
134 if (attrib.isAKeyAttrib()) {
135 if (this.getKeyAttrib() != null)
136 throw new HBqlException("Mapping " + this + " has multiple instance variables marked as keys");
137 this.setKeyAttrib(attrib);
138 }
139 }
140
141 public byte[] getTableNameAsBytes() throws HBqlException {
142 return IO.getSerialization().getStringAsBytes(this.getTableName());
143 }
144
145
146 protected Map<String, HRecordAttrib> getAttribByFamilyQualifiedNameMap() {
147 return this.columnAttribByFamilyQualifiedNameMap;
148 }
149
150 public ColumnAttrib getAttribFromFamilyQualifiedName(final String familyName, final String columnName) {
151 return this.getAttribFromFamilyQualifiedName(familyName + ":" + columnName);
152 }
153
154 public ColumnAttrib getAttribFromFamilyQualifiedName(final String familyQualifiedName) {
155 return this.getAttribByFamilyQualifiedNameMap().get(familyQualifiedName);
156 }
157
158 protected void addAttribToFamilyQualifiedNameMap(final HRecordAttrib attrib) throws HBqlException {
159
160 final String name = attrib.getFamilyQualifiedName();
161 if (this.getAttribByFamilyQualifiedNameMap().containsKey(name))
162 throw new HBqlException(name + " already declared");
163 this.getAttribByFamilyQualifiedNameMap().put(name, attrib);
164 }
165
166
167 private Map<String, HRecordAttrib> getUnMappedAttribsMap() {
168 return this.unMappedAttribsMap;
169 }
170
171 public ColumnAttrib getUnMappedAttrib(final String familyName) {
172 return this.getUnMappedAttribsMap().get(familyName);
173 }
174
175 private boolean includeUnMappedForFamiily(final String familyName) {
176 return this.getUnMappedAttribsMap().containsKey(familyName);
177 }
178
179 private void addUnMappedAttrib(final HRecordAttrib attrib) throws HBqlException {
180
181 final String familyName = attrib.getFamilyName();
182 if (this.getUnMappedAttribsMap().containsKey(familyName))
183 throw new HBqlException(familyName + " already declared");
184
185 this.getUnMappedAttribsMap().put(familyName, attrib);
186
187 final String aliasName = attrib.getAliasName();
188 if (aliasName == null || aliasName.length() == 0 || aliasName.equals(familyName))
189 return;
190
191 if (this.getUnMappedAttribsMap().containsKey(aliasName))
192 throw new HBqlException(aliasName + " already declared");
193
194 this.getUnMappedAttribsMap().put(aliasName, attrib);
195 }
196
197
198 private Map<String, HRecordAttrib> getVersionAttribMap() {
199 return this.versionAttribMap;
200 }
201
202 public ColumnAttrib getVersionAttrib(final String name) {
203 return this.getVersionAttribMap().get(name);
204 }
205
206 protected void addVersionAttrib(final HRecordAttrib attrib) throws HBqlException {
207
208 if (!attrib.isAVersionValue())
209 return;
210
211 final String familyQualifiedName = attrib.getFamilyQualifiedName();
212 if (this.getVersionAttribMap().containsKey(familyQualifiedName))
213 throw new HBqlException(familyQualifiedName + " already declared");
214
215 this.getVersionAttribMap().put(familyQualifiedName, attrib);
216 }
217
218
219 private Map<String, List<HRecordAttrib>> getColumnAttribListByFamilyNameMap() {
220 return this.columnAttribListByFamilyNameMap;
221 }
222
223 public Set<String> getFamilySet() {
224 return this.getColumnAttribListByFamilyNameMap().keySet();
225 }
226
227 public boolean containsFamily(final String familyName) {
228 return this.getFamilySet().contains(familyName);
229 }
230
231 public List<HRecordAttrib> getColumnAttribListByFamilyName(final String familyName) {
232 return this.getColumnAttribListByFamilyNameMap().get(familyName);
233 }
234
235 public boolean containsFamilyNameInFamilyNameMap(final String familyName) {
236 return this.getColumnAttribListByFamilyNameMap().containsKey(familyName);
237 }
238
239 public void addAttribToFamilyNameColumnListMap(final String familyName,
240 final List<HRecordAttrib> attribList) throws HBqlException {
241 if (this.containsFamilyNameInFamilyNameMap(familyName))
242 throw new HBqlException(familyName + " already declared");
243 this.getColumnAttribListByFamilyNameMap().put(familyName, attribList);
244 }
245
246 public void addAttribToFamilyNameColumnListMap(HRecordAttrib attrib) throws HBqlException {
247
248 if (attrib.isAKeyAttrib())
249 return;
250
251 final String familyName = attrib.getFamilyName();
252
253 if (familyName == null || familyName.length() == 0)
254 return;
255
256 final List<HRecordAttrib> attribList;
257 if (!this.containsFamilyNameInFamilyNameMap(familyName)) {
258 attribList = Lists.newArrayList();
259 this.addAttribToFamilyNameColumnListMap(familyName, attribList);
260 }
261 else {
262 attribList = this.getColumnAttribListByFamilyName(familyName);
263 }
264 attribList.add(attrib);
265 }
266
267 public synchronized Set<String> getMappingFamilyNames() throws HBqlException {
268
269
270 return (this.getConnection() == null)
271 ? this.getFamilySet()
272 : this.getConnection().getFamilyNames(this.getTableName());
273 }
274
275 public RecordFilter newRecordFilter(final String query) throws HBqlException {
276 final MappingContext mappingContext = new MappingContext(this);
277 mappingContext.setResultAccessor(new HRecordResultAccessor(mappingContext));
278 final ExpressionTree expressionTree = ParserUtil.parseWhereExpression(query, mappingContext);
279 return RecordFilter.newRecordFilter(expressionTree);
280 }
281
282 public boolean isTempMapping() {
283 return this.tempMapping;
284 }
285
286 public boolean isSystemMapping() {
287 return this.systemMapping;
288 }
289
290 public void dropMapping() throws HBqlException {
291 this.getConnection().dropMapping(this.getMappingName());
292 }
293
294 public void validate(final String mappingName) throws HBqlException {
295 for (final ColumnAttrib attrib : this.getColumnAttribSet()) {
296 if (attrib.getFieldType() == null)
297 throw new HBqlException(mappingName + " attribute "
298 + attrib.getFamilyQualifiedName() + " has unknown type.");
299 }
300 }
301
302 public String asString() throws HBqlException {
303
304 final StringBuilder sbuf = new StringBuilder();
305
306 sbuf.append("CREATE ")
307 .append(this.isTempMapping() ? "TEMP " : "")
308 .append("MAPPING ")
309 .append(this.getMappingName());
310
311 if (!(this.getMappingName().equals(this.getTableName())))
312 sbuf.append(" FOR TABLE ").append(this.getTableName());
313
314 sbuf.append(" (\n ")
315 .append(this.getKeyAttrib().getColumnName())
316 .append(" KEY");
317
318 for (final String familyName : this.getColumnAttribListByFamilyNameMap().keySet()) {
319
320 sbuf.append(",\n ").append(familyName);
321
322 if (this.includeUnMappedForFamiily(familyName))
323 sbuf.append(" INCLUDE UNMAPPED");
324
325 sbuf.append(" (");
326
327 boolean first = true;
328 for (final HRecordAttrib column : this.getColumnAttribListByFamilyNameMap().get(familyName)) {
329 if (!first)
330 sbuf.append(",");
331 else
332 first = false;
333
334 sbuf.append("\n ").append(column.asString());
335 }
336
337 sbuf.append("\n )");
338 }
339
340 if (this.getColumnAttribListByFamilyNameMap().size() > 0)
341 sbuf.append("\n");
342
343 sbuf.append(")");
344
345 return sbuf.toString();
346 }
347 }