PHOENIX-4605 Support running multiple transaction providers
[phoenix.git] / phoenix-core / src / main / java / org / apache / phoenix / schema / PTableImpl.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.phoenix.schema;
19
20 import static org.apache.phoenix.hbase.index.util.KeyValueBuilder.addQuietly;
21 import static org.apache.phoenix.hbase.index.util.KeyValueBuilder.deleteQuietly;
22 import static org.apache.phoenix.schema.SaltingUtil.SALTING_COLUMN;
23
24 import java.io.IOException;
25 import java.sql.DriverManager;
26 import java.sql.SQLException;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Map.Entry;
35
36 import javax.annotation.Nonnull;
37
38 import org.apache.hadoop.hbase.Cell;
39 import org.apache.hadoop.hbase.HConstants;
40 import org.apache.hadoop.hbase.client.Delete;
41 import org.apache.hadoop.hbase.client.Durability;
42 import org.apache.hadoop.hbase.client.Increment;
43 import org.apache.hadoop.hbase.client.Mutation;
44 import org.apache.hadoop.hbase.client.Put;
45 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
46 import org.apache.hadoop.hbase.util.ByteStringer;
47 import org.apache.hadoop.hbase.util.Bytes;
48 import org.apache.hadoop.hbase.util.Pair;
49 import org.apache.phoenix.compile.ExpressionCompiler;
50 import org.apache.phoenix.compile.StatementContext;
51 import org.apache.phoenix.coprocessor.generated.PTableProtos;
52 import org.apache.phoenix.exception.DataExceedsCapacityException;
53 import org.apache.phoenix.expression.Expression;
54 import org.apache.phoenix.expression.LiteralExpression;
55 import org.apache.phoenix.expression.SingleCellConstructorExpression;
56 import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
57 import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
58 import org.apache.phoenix.index.IndexMaintainer;
59 import org.apache.phoenix.jdbc.PhoenixConnection;
60 import org.apache.phoenix.jdbc.PhoenixStatement;
61 import org.apache.phoenix.parse.ParseNode;
62 import org.apache.phoenix.parse.SQLParser;
63 import org.apache.phoenix.protobuf.ProtobufUtil;
64 import org.apache.phoenix.query.QueryConstants;
65 import org.apache.phoenix.schema.RowKeySchema.RowKeySchemaBuilder;
66 import org.apache.phoenix.schema.types.PBinary;
67 import org.apache.phoenix.schema.types.PChar;
68 import org.apache.phoenix.schema.types.PDataType;
69 import org.apache.phoenix.schema.types.PDouble;
70 import org.apache.phoenix.schema.types.PFloat;
71 import org.apache.phoenix.schema.types.PVarchar;
72 import org.apache.phoenix.transaction.TransactionFactory;
73 import org.apache.phoenix.util.ByteUtil;
74 import org.apache.phoenix.util.EncodedColumnsUtil;
75 import org.apache.phoenix.util.PhoenixRuntime;
76 import org.apache.phoenix.util.SchemaUtil;
77 import org.apache.phoenix.util.SizedUtil;
78 import org.apache.phoenix.util.TrustedByteArrayOutputStream;
79
80 import com.google.common.base.Objects;
81 import com.google.common.base.Preconditions;
82 import com.google.common.collect.ArrayListMultimap;
83 import com.google.common.collect.ImmutableList;
84 import com.google.common.collect.ImmutableMap;
85 import com.google.common.collect.ImmutableSortedMap;
86 import com.google.common.collect.ListMultimap;
87 import com.google.common.collect.Lists;
88 import com.google.common.collect.Maps;
89
90
91 /**
92 *
93 * Base class for PTable implementors. Provides abstraction for
94 * storing data in a single column (ColumnLayout.SINGLE) or in
95 * multiple columns (ColumnLayout.MULTI).
96 *
97 * @since 0.1
98 */
99 public class PTableImpl implements PTable {
100 private static final Integer NO_SALTING = -1;
101
102 private PTableKey key;
103 private PName name;
104 private PName schemaName = PName.EMPTY_NAME;
105 private PName tableName = PName.EMPTY_NAME;
106 private PName tenantId;
107 private PTableType type;
108 private PIndexState state;
109 private long sequenceNumber;
110 private long timeStamp;
111 private long indexDisableTimestamp;
112 // Have MultiMap for String->PColumn (may need family qualifier)
113 private List<PColumn> pkColumns;
114 private List<PColumn> allColumns;
115 private List<PColumnFamily> families;
116 private Map<byte[], PColumnFamily> familyByBytes;
117 private Map<String, PColumnFamily> familyByString;
118 private ListMultimap<String, PColumn> columnsByName;
119 private Map<KVColumnFamilyQualifier, PColumn> kvColumnsByQualifiers;
120 private PName pkName;
121 private Integer bucketNum;
122 private RowKeySchema rowKeySchema;
123 // Indexes associated with this table.
124 private List<PTable> indexes;
125 // Data table name that the index is created on.
126 private PName parentName;
127 private PName parentSchemaName;
128 private PName parentTableName;
129 private List<PName> physicalNames;
130 private boolean isImmutableRows;
131 private IndexMaintainer indexMaintainer;
132 private ImmutableBytesWritable indexMaintainersPtr;
133 private PName defaultFamilyName;
134 private String viewStatement;
135 private boolean disableWAL;
136 private boolean multiTenant;
137 private boolean storeNulls;
138 private TransactionFactory.Provider transactionProvider;
139 private ViewType viewType;
140 private Short viewIndexId;
141 private int estimatedSize;
142 private IndexType indexType;
143 private int baseColumnCount;
144 private boolean rowKeyOrderOptimizable; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
145 private boolean hasColumnsRequiringUpgrade; // TODO: remove when required that tables have been upgrade for PHOENIX-2067
146 private int rowTimestampColPos;
147 private long updateCacheFrequency;
148 private boolean isNamespaceMapped;
149 private String autoPartitionSeqName;
150 private boolean isAppendOnlySchema;
151 private ImmutableStorageScheme immutableStorageScheme;
152 private QualifierEncodingScheme qualifierEncodingScheme;
153 private EncodedCQCounter encodedCQCounter;
154 private Boolean useStatsForParallelization;
155
156 public PTableImpl() {
157 this.indexes = Collections.emptyList();
158 this.physicalNames = Collections.emptyList();
159 this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
160 }
161
162 // Constructor used at table creation time
163 public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped) {
164 Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
165 this.tenantId = tenantId;
166 this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName, tableName));
167 this.key = new PTableKey(tenantId, name.getString());
168 this.schemaName = PNameFactory.newName(schemaName);
169 this.tableName = PNameFactory.newName(tableName);
170 this.type = PTableType.VIEW;
171 this.viewType = ViewType.MAPPED;
172 this.timeStamp = timestamp;
173 this.pkColumns = this.allColumns = Collections.emptyList();
174 this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
175 this.indexes = Collections.emptyList();
176 this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size());
177 this.familyByString = Maps.newHashMapWithExpectedSize(families.size());
178 for (PColumnFamily family : families) {
179 familyByBytes.put(family.getName().getBytes(), family);
180 familyByString.put(family.getName().getString(), family);
181 }
182 this.families = families;
183 this.physicalNames = Collections.emptyList();
184 this.isNamespaceMapped = isNamespaceMapped;
185 }
186
187 public PTableImpl(PName tenantId, String schemaName, String tableName, long timestamp, List<PColumnFamily> families, boolean isNamespaceMapped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme encodingScheme, Boolean useStatsForParallelization) { // For base table of mapped VIEW
188 Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
189 this.tenantId = tenantId;
190 this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName, tableName));
191 this.key = new PTableKey(tenantId, name.getString());
192 this.schemaName = PNameFactory.newName(schemaName);
193 this.tableName = PNameFactory.newName(tableName);
194 this.type = PTableType.VIEW;
195 this.viewType = ViewType.MAPPED;
196 this.timeStamp = timestamp;
197 this.pkColumns = this.allColumns = Collections.emptyList();
198 this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
199 this.indexes = Collections.emptyList();
200 this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size());
201 this.familyByString = Maps.newHashMapWithExpectedSize(families.size());
202 for (PColumnFamily family : families) {
203 familyByBytes.put(family.getName().getBytes(), family);
204 familyByString.put(family.getName().getString(), family);
205 }
206 this.families = families;
207 this.physicalNames = Collections.emptyList();
208 this.isNamespaceMapped = isNamespaceMapped;
209 this.immutableStorageScheme = storageScheme;
210 this.qualifierEncodingScheme = encodingScheme;
211 this.useStatsForParallelization = useStatsForParallelization;
212 }
213
214 // For indexes stored in shared physical tables
215 public PTableImpl(PName tenantId, PName schemaName, PName tableName, long timestamp, List<PColumnFamily> families,
216 List<PColumn> columns, List<PName> physicalNames, Short viewIndexId, boolean multiTenant, boolean isNamespaceMpped, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme,
217 EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization) throws SQLException {
218 this.pkColumns = this.allColumns = Collections.emptyList();
219 this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
220 this.indexes = Collections.emptyList();
221 this.familyByBytes = Maps.newHashMapWithExpectedSize(families.size());
222 this.familyByString = Maps.newHashMapWithExpectedSize(families.size());
223 for (PColumnFamily family : families) {
224 familyByBytes.put(family.getName().getBytes(), family);
225 familyByString.put(family.getName().getString(), family);
226 }
227 this.families = families;
228 init(tenantId, this.schemaName, this.tableName, PTableType.INDEX, state, timeStamp, sequenceNumber, pkName, bucketNum, columns,
229 this.schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
230 null, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
231 transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMpped, null, false, storageScheme, qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization);
232 }
233
234 public PTableImpl(long timeStamp) { // For delete marker
235 this(timeStamp, false);
236 }
237
238 public PTableImpl(long timeStamp, boolean isIndex) { // For index delete marker
239 if (isIndex) {
240 this.type = PTableType.INDEX;
241 this.state = PIndexState.INACTIVE;
242 } else {
243 this.type = PTableType.TABLE;
244 }
245 this.timeStamp = timeStamp;
246 this.pkColumns = this.allColumns = Collections.emptyList();
247 this.families = Collections.emptyList();
248 this.familyByBytes = Collections.emptyMap();
249 this.familyByString = Collections.emptyMap();
250 this.rowKeySchema = RowKeySchema.EMPTY_SCHEMA;
251 this.indexes = Collections.emptyList();
252 this.physicalNames = Collections.emptyList();;
253 }
254
255 // When cloning table, ignore the salt column as it will be added back in the constructor
256 public static List<PColumn> getColumnsToClone(PTable table) {
257 return table.getBucketNum() == null ? table.getColumns() : table.getColumns().subList(1, table.getColumns().size());
258 }
259
260 public static PTableImpl makePTable(PTable table, long timeStamp, List<PTable> indexes) throws SQLException {
261 return makePTable(table, timeStamp, indexes, table.getParentSchemaName(), table.getViewStatement());
262 }
263
264 public static PTable makePTable(PTable index, PName indexName, String viewStatement, long updateCacheFrequency, PName tenantId) throws SQLException {
265 return Objects.equal(viewStatement, index.getViewStatement()) ? index : makePTable(index, indexName, index.getTimeStamp(), Lists.newArrayList(index.getPhysicalName()), index.getIndexes(), viewStatement, updateCacheFrequency, tenantId);
266 }
267
268 public static PTableImpl makePTable(PTable table, PName tableName, long timeStamp, List<PName> physicalNames, List<PTable> indexes, String viewStatement, long updateCacheFrequency, PName tenantId) throws SQLException {
269 return new PTableImpl(
270 tenantId, table.getSchemaName(), tableName, table.getType(), table.getIndexState(), timeStamp,
271 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table), table.getParentSchemaName(), table.getParentTableName(),
272 indexes, table.isImmutableRows(), physicalNames, table.getDefaultFamilyName(), viewStatement,
273 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
274 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), updateCacheFrequency,
275 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
276 }
277
278 public static PTableImpl makePTable(PTable table, long timeStamp, List<PTable> indexes, PName parentSchemaName, String viewStatement) throws SQLException {
279 return new PTableImpl(
280 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
281 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table), parentSchemaName, table.getParentTableName(),
282 indexes, table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), viewStatement,
283 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
284 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(),
285 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
286 }
287
288 public static PTableImpl makePTable(PTable table, Collection<PColumn> columns) throws SQLException {
289 return new PTableImpl(
290 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
291 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
292 table.getIndexes(), table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
293 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
294 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(),
295 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
296 }
297
298 public static PTableImpl makePTable(PTable table, PTableType type, Collection<PColumn> columns) throws SQLException {
299 return new PTableImpl(
300 table.getTenantId(), table.getSchemaName(), table.getTableName(), type, table.getIndexState(), table.getTimeStamp(),
301 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
302 table.getIndexes(), table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
303 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
304 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(),
305 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
306 }
307
308 public static PTableImpl makePTable(PTable table, Collection<PColumn> columns, PName defaultFamily) throws SQLException {
309 return new PTableImpl(
310 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
311 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
312 table.getIndexes(), table.isImmutableRows(), table.getPhysicalNames(), defaultFamily, table.getViewStatement(),
313 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
314 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(),
315 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
316 }
317
318 public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<PColumn> columns) throws SQLException {
319 return new PTableImpl(
320 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
321 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
322 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(), table.isWALDisabled(),
323 table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
324 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(),
325 table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
326 }
327
328 public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<PColumn> columns, boolean isImmutableRows) throws SQLException {
329 return new PTableImpl(
330 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
331 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
332 table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
333 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(),
334 table.getIndexType(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(),
335 table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
336 }
337
338 public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, Collection<PColumn> columns, boolean isImmutableRows, boolean isWalDisabled,
339 boolean isMultitenant, boolean storeNulls, TransactionFactory.Provider transactionProvider, long updateCacheFrequency, boolean isNamespaceMapped) throws SQLException {
340 return new PTableImpl(
341 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), timeStamp,
342 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
343 table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
344 isWalDisabled, isMultitenant, storeNulls, table.getViewType(), table.getViewIndexId(), table.getIndexType(),
345 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), transactionProvider, updateCacheFrequency, table.getIndexDisableTimestamp(),
346 isNamespaceMapped, table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
347 }
348
349 public static PTableImpl makePTable(PTable table, PIndexState state) throws SQLException {
350 return new PTableImpl(
351 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), state, table.getTimeStamp(),
352 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
353 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
354 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
355 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
356 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(),
357 table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
358 }
359
360 public static PTableImpl makePTable(PTable table, boolean rowKeyOrderOptimizable) throws SQLException {
361 return new PTableImpl(
362 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
363 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
364 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
365 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
366 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
367 table.getBaseColumnCount(), rowKeyOrderOptimizable, table.getTransactionProvider(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(),
368 table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
369 }
370
371 public static PTableImpl makePTable(PTable table) throws SQLException {
372 return new PTableImpl(
373 table.getTenantId(), table.getSchemaName(), table.getTableName(), table.getType(), table.getIndexState(), table.getTimeStamp(),
374 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table),
375 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
376 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
377 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
378 table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.getTransactionProvider(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(),
379 table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema(), table.getImmutableStorageScheme(), table.getEncodingScheme(), table.getEncodedCQCounter(), table.useStatsForParallelization());
380 }
381
382 public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
383 PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum,
384 Collection<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes,
385 boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
386 boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
387 IndexType indexType, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency,
388 long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization) throws SQLException {
389 return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, dataSchemaName,
390 dataTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
391 viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
392 indexType, QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT, rowKeyOrderOptimizable, transactionProvider,
393 updateCacheFrequency,indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization);
394 }
395
396 public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
397 PIndexState state, long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum,
398 Collection<PColumn> columns, PName dataSchemaName, PName dataTableName, List<PTable> indexes,
399 boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
400 boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
401 IndexType indexType, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency,
402 int baseColumnCount, long indexDisableTimestamp, boolean isNamespaceMapped,
403 String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme,
404 QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization)
405 throws SQLException {
406 return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName,
407 bucketNum, columns, dataSchemaName, dataTableName, indexes, isImmutableRows, physicalNames,
408 defaultFamilyName, viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
409 indexType, baseColumnCount, rowKeyOrderOptimizable, transactionProvider, updateCacheFrequency,
410 indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization);
411 }
412
413 private PTableImpl(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state,
414 long timeStamp, long sequenceNumber, PName pkName, Integer bucketNum, Collection<PColumn> columns,
415 PName parentSchemaName, PName parentTableName, List<PTable> indexes, boolean isImmutableRows,
416 List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL, boolean multiTenant,
417 boolean storeNulls, ViewType viewType, Short viewIndexId, IndexType indexType,
418 int baseColumnCount, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency,
419 long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme,
420 QualifierEncodingScheme qualifierEncodingScheme, EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization) throws SQLException {
421 init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns,
422 parentSchemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
423 viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
424 transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema, storageScheme,
425 qualifierEncodingScheme, encodedCQCounter, useStatsForParallelization);
426 }
427
428 @Override
429 public long getUpdateCacheFrequency() {
430 return updateCacheFrequency;
431 }
432
433 @Override
434 public boolean isMultiTenant() {
435 return multiTenant;
436 }
437
438 @Override
439 public boolean getStoreNulls() {
440 return storeNulls;
441 }
442
443 @Override
444 public ViewType getViewType() {
445 return viewType;
446 }
447
448
449 @Override
450 public int getEstimatedSize() {
451 return estimatedSize;
452 }
453
454 private void init(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state, long timeStamp, long sequenceNumber,
455 PName pkName, Integer bucketNum, Collection<PColumn> columns, PName parentSchemaName, PName parentTableName,
456 List<PTable> indexes, boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL,
457 boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
458 IndexType indexType , int baseColumnCount, boolean rowKeyOrderOptimizable, TransactionFactory.Provider transactionProvider, long updateCacheFrequency, long indexDisableTimestamp,
459 boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema, ImmutableStorageScheme storageScheme, QualifierEncodingScheme qualifierEncodingScheme,
460 EncodedCQCounter encodedCQCounter, Boolean useStatsForParallelization) throws SQLException {
461 Preconditions.checkNotNull(schemaName);
462 Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
463 int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE + 4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE +
464 PNameFactory.getEstimatedSize(tenantId) +
465 PNameFactory.getEstimatedSize(schemaName) +
466 PNameFactory.getEstimatedSize(tableName) +
467 PNameFactory.getEstimatedSize(pkName) +
468 PNameFactory.getEstimatedSize(parentTableName) +
469 PNameFactory.getEstimatedSize(defaultFamilyName);
470 this.tenantId = tenantId;
471 this.schemaName = schemaName;
472 this.tableName = tableName;
473 this.name = PNameFactory.newName(SchemaUtil.getTableName(schemaName.getString(), tableName.getString()));
474 this.key = new PTableKey(tenantId, name.getString());
475 this.type = type;
476 this.state = state;
477 this.timeStamp = timeStamp;
478 this.indexDisableTimestamp = indexDisableTimestamp;
479 this.sequenceNumber = sequenceNumber;
480 this.pkName = pkName;
481 this.isImmutableRows = isImmutableRows;
482 this.defaultFamilyName = defaultFamilyName;
483 this.viewStatement = viewExpression;
484 this.disableWAL = disableWAL;
485 this.multiTenant = multiTenant;
486 this.storeNulls = storeNulls;
487 this.viewType = viewType;
488 this.viewIndexId = viewIndexId;
489 this.indexType = indexType;
490 this.transactionProvider = transactionProvider;
491 this.rowKeyOrderOptimizable = rowKeyOrderOptimizable;
492 this.updateCacheFrequency = updateCacheFrequency;
493 this.isNamespaceMapped = isNamespaceMapped;
494 this.autoPartitionSeqName = autoPartitionSeqName;
495 this.isAppendOnlySchema = isAppendOnlySchema;
496 // null check for backward compatibility and sanity. If any of the two below is null, then it means the table is a non-encoded table.
497 this.immutableStorageScheme = storageScheme == null ? ImmutableStorageScheme.ONE_CELL_PER_COLUMN : storageScheme;
498 this.qualifierEncodingScheme = qualifierEncodingScheme == null ? QualifierEncodingScheme.NON_ENCODED_QUALIFIERS : qualifierEncodingScheme;
499 List<PColumn> pkColumns;
500 PColumn[] allColumns;
501
502 this.columnsByName = ArrayListMultimap.create(columns.size(), 1);
503 this.kvColumnsByQualifiers = Maps.newHashMapWithExpectedSize(columns.size());
504 int numPKColumns = 0;
505 if (bucketNum != null) {
506 // Add salt column to allColumns and pkColumns, but don't add to
507 // columnsByName, since it should not be addressable via name.
508 allColumns = new PColumn[columns.size()+1];
509 allColumns[SALTING_COLUMN.getPosition()] = SALTING_COLUMN;
510 pkColumns = Lists.newArrayListWithExpectedSize(columns.size()+1);
511 ++numPKColumns;
512 } else {
513 allColumns = new PColumn[columns.size()];
514 pkColumns = Lists.newArrayListWithExpectedSize(columns.size());
515 }
516 for (PColumn column : columns) {
517 allColumns[column.getPosition()] = column;
518 PName familyName = column.getFamilyName();
519 if (familyName == null) {
520 ++numPKColumns;
521 }
522 String columnName = column.getName().getString();
523 if (columnsByName.put(columnName, column)) {
524 int count = 0;
525 for (PColumn dupColumn : columnsByName.get(columnName)) {
526 if (Objects.equal(familyName, dupColumn.getFamilyName())) {
527 count++;
528 if (count > 1) {
529 throw new ColumnAlreadyExistsException(schemaName.getString(), name.getString(), columnName);
530 }
531 }
532 }
533 }
534 byte[] cq = column.getColumnQualifierBytes();
535 String cf = column.getFamilyName() != null ? column.getFamilyName().getString() : null;
536 if (cf != null && cq != null) {
537 KVColumnFamilyQualifier info = new KVColumnFamilyQualifier(cf, cq);
538 if (kvColumnsByQualifiers.get(info) != null) {
539 throw new ColumnAlreadyExistsException(schemaName.getString(),
540 name.getString(), columnName);
541 }
542 kvColumnsByQualifiers.put(info, column);
543 }
544 }
545 estimatedSize += SizedUtil.sizeOfMap(allColumns.length, SizedUtil.POINTER_SIZE, SizedUtil.sizeOfArrayList(1)); // for multi-map
546
547 this.bucketNum = bucketNum;
548 this.allColumns = ImmutableList.copyOf(allColumns);
549 estimatedSize += SizedUtil.sizeOfMap(numPKColumns) + SizedUtil.sizeOfMap(allColumns.length);
550
551 RowKeySchemaBuilder builder = new RowKeySchemaBuilder(numPKColumns);
552 // Two pass so that column order in column families matches overall column order
553 // and to ensure that column family order is constant
554 int maxExpectedSize = allColumns.length - numPKColumns;
555 // Maintain iteration order so that column families are ordered as they are listed
556 Map<PName, List<PColumn>> familyMap = Maps.newLinkedHashMap();
557 PColumn rowTimestampCol = null;
558 for (PColumn column : allColumns) {
559 PName familyName = column.getFamilyName();
560 if (familyName == null) {
561 hasColumnsRequiringUpgrade |=
562 ( column.getSortOrder() == SortOrder.DESC
563 && (!column.getDataType().isFixedWidth()
564 || column.getDataType() == PChar.INSTANCE
565 || column.getDataType() == PFloat.INSTANCE
566 || column.getDataType() == PDouble.INSTANCE
567 || column.getDataType() == PBinary.INSTANCE) )
568 || (column.getSortOrder() == SortOrder.ASC && column.getDataType() == PBinary.INSTANCE && column.getMaxLength() != null && column.getMaxLength() > 1);
569 pkColumns.add(column);
570 if (column.isRowTimestamp()) {
571 rowTimestampCol = column;
572 }
573 }
574 if (familyName == null) {
575 estimatedSize += column.getEstimatedSize(); // PK columns
576 builder.addField(column, column.isNullable(), column.getSortOrder());
577 } else {
578 List<PColumn> columnsInFamily = familyMap.get(familyName);
579 if (columnsInFamily == null) {
580 columnsInFamily = Lists.newArrayListWithExpectedSize(maxExpectedSize);
581 familyMap.put(familyName, columnsInFamily);
582 }
583 columnsInFamily.add(column);
584 }
585 }
586 this.pkColumns = ImmutableList.copyOf(pkColumns);
587 if (rowTimestampCol != null) {
588 this.rowTimestampColPos = this.pkColumns.indexOf(rowTimestampCol);
589 } else {
590 this.rowTimestampColPos = -1;
591 }
592
593 builder.rowKeyOrderOptimizable(this.rowKeyOrderOptimizable()); // after hasDescVarLengthColumns is calculated
594 this.rowKeySchema = builder.build();
595 estimatedSize += rowKeySchema.getEstimatedSize();
596 Iterator<Map.Entry<PName,List<PColumn>>> iterator = familyMap.entrySet().iterator();
597 PColumnFamily[] families = new PColumnFamily[familyMap.size()];
598 ImmutableMap.Builder<String, PColumnFamily> familyByString = ImmutableMap.builder();
599 ImmutableSortedMap.Builder<byte[], PColumnFamily> familyByBytes = ImmutableSortedMap
600 .orderedBy(Bytes.BYTES_COMPARATOR);
601 for (int i = 0; i < families.length; i++) {
602 Map.Entry<PName,List<PColumn>> entry = iterator.next();
603 PColumnFamily family = new PColumnFamilyImpl(entry.getKey(), entry.getValue());
604 families[i] = family;
605 familyByString.put(family.getName().getString(), family);
606 familyByBytes.put(family.getName().getBytes(), family);
607 estimatedSize += family.getEstimatedSize();
608 }
609 this.families = ImmutableList.copyOf(families);
610 this.familyByBytes = familyByBytes.build();
611 this.familyByString = familyByString.build();
612 estimatedSize += SizedUtil.sizeOfArrayList(families.length);
613 estimatedSize += SizedUtil.sizeOfMap(families.length) * 2;
614 this.indexes = indexes == null ? Collections.<PTable>emptyList() : indexes;
615 for (PTable index : this.indexes) {
616 estimatedSize += index.getEstimatedSize();
617 }
618
619 this.parentSchemaName = parentSchemaName;
620 this.parentTableName = parentTableName;
621 this.parentName = parentTableName == null ? null : PNameFactory.newName(SchemaUtil.getTableName(
622 parentSchemaName!=null ? parentSchemaName.getString() : null, parentTableName.getString()));
623 estimatedSize += PNameFactory.getEstimatedSize(this.parentName);
624
625 this.physicalNames = physicalNames == null ? ImmutableList.<PName>of() : ImmutableList.copyOf(physicalNames);
626 for (PName name : this.physicalNames) {
627 estimatedSize += name.getEstimatedSize();
628 }
629 this.estimatedSize = estimatedSize;
630 this.baseColumnCount = baseColumnCount;
631 this.encodedCQCounter = encodedCQCounter;
632 this.useStatsForParallelization = useStatsForParallelization;
633 }
634
635 @Override
636 public boolean isImmutableRows() {
637 return isImmutableRows;
638 }
639
640 @Override
641 public String toString() {
642 return name.getString();
643 }
644
645 @Override
646 public List<PColumn> getPKColumns() {
647 return pkColumns;
648 }
649
650 @Override
651 public final PName getName() {
652 return name;
653 }
654
655 @Override
656 public final PName getSchemaName() {
657 return schemaName;
658 }
659
660 @Override
661 public final PName getTableName() {
662 return tableName;
663 }
664
665 @Override
666 public final PTableType getType() {
667 return type;
668 }
669
670 @Override
671 public final List<PColumnFamily> getColumnFamilies() {
672 return families;
673 }
674
675 @Override
676 public int newKey(ImmutableBytesWritable key, byte[][] values) {
677 List<PColumn> columns = getPKColumns();
678 int nValues = values.length;
679 while (nValues > 0 && (values[nValues-1] == null || values[nValues-1].length == 0)) {
680 nValues--;
681 }
682 for (PColumn column : columns) {
683 if (column.getExpressionStr() != null) {
684 nValues++;
685 }
686 }
687 int i = 0;
688 TrustedByteArrayOutputStream os = new TrustedByteArrayOutputStream(SchemaUtil.estimateKeyLength(this));
689 try {
690 Integer bucketNum = this.getBucketNum();
691 if (bucketNum != null) {
692 // Write place holder for salt byte
693 i++;
694 os.write(QueryConstants.SEPARATOR_BYTE_ARRAY);
695 }
696 int nColumns = columns.size();
697 PDataType type = null;
698 SortOrder sortOrder = null;
699 boolean wasNull = false;
700
701 while (i < nValues && i < nColumns) {
702 // Separate variable length column values in key with zero byte
703 if (type != null && !type.isFixedWidth()) {
704 os.write(SchemaUtil.getSeparatorByte(rowKeyOrderOptimizable(), wasNull, sortOrder));
705 }
706 PColumn column = columns.get(i);
707 sortOrder = column.getSortOrder();
708 type = column.getDataType();
709 // This will throw if the value is null and the type doesn't allow null
710 byte[] byteValue = values[i++];
711 if (byteValue == null) {
712 if (column.getExpressionStr() != null) {
713 try {
714 String url = PhoenixRuntime.JDBC_PROTOCOL
715 + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR
716 + PhoenixRuntime.CONNECTIONLESS;
717 PhoenixConnection conn = DriverManager.getConnection(url)
718 .unwrap(PhoenixConnection.class);
719 StatementContext context =
720 new StatementContext(new PhoenixStatement(conn));
721
722 ExpressionCompiler compiler = new ExpressionCompiler(context);
723 ParseNode defaultParseNode =
724 new SQLParser(column.getExpressionStr()).parseExpression();
725 Expression defaultExpression = defaultParseNode.accept(compiler);
726 defaultExpression.evaluate(null, key);
727 column.getDataType().coerceBytes(key, null,
728 defaultExpression.getDataType(),
729 defaultExpression.getMaxLength(), defaultExpression.getScale(),
730 defaultExpression.getSortOrder(),
731 column.getMaxLength(), column.getScale(),
732 column.getSortOrder());
733 byteValue = ByteUtil.copyKeyBytesIfNecessary(key);
734 } catch (SQLException e) { // should not be possible
735 throw new ConstraintViolationException(name.getString() + "."
736 + column.getName().getString()
737 + " failed to compile default value expression of "
738 + column.getExpressionStr());
739 }
740 }
741 else {
742 byteValue = ByteUtil.EMPTY_BYTE_ARRAY;
743 }
744 }
745 wasNull = byteValue.length == 0;
746 // An empty byte array return value means null. Do this,
747 // since a type may have muliple representations of null.
748 // For example, VARCHAR treats both null and an empty string
749 // as null. This way we don't need to leak that part of the
750 // implementation outside of PDataType by checking the value
751 // here.
752 if (byteValue.length == 0 && !column.isNullable()) {
753 throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() + " may not be null");
754 }
755 Integer maxLength = column.getMaxLength();
756 Integer scale = column.getScale();
757 key.set(byteValue);
758 if (!type.isSizeCompatible(key, null, type, sortOrder, null, null, maxLength, scale)) {
759 throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() + " may not exceed " + maxLength + " (" + SchemaUtil.toString(type, byteValue) + ")");
760 }
761 key.set(byteValue);
762 type.pad(key, maxLength, sortOrder);
763 byteValue = ByteUtil.copyKeyBytesIfNecessary(key);
764 os.write(byteValue, 0, byteValue.length);
765 }
766 // Need trailing byte for DESC columns
767 if (type != null && !type.isFixedWidth() && SchemaUtil.getSeparatorByte(rowKeyOrderOptimizable(), wasNull, sortOrder) == QueryConstants.DESC_SEPARATOR_BYTE) {
768 os.write(QueryConstants.DESC_SEPARATOR_BYTE);
769 }
770 // If some non null pk values aren't set, then throw
771 if (i < nColumns) {
772 PColumn column = columns.get(i);
773 if (column.getDataType().isFixedWidth() || !column.isNullable()) {
774 throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() + " may not be null");
775 }
776 }
777 if (nValues == 0) {
778 throw new ConstraintViolationException("Primary key may not be null ("+ name.getString() + ")");
779 }
780 byte[] buf = os.getBuffer();
781 int size = os.size();
782 if (bucketNum != null) {
783 buf[0] = SaltingUtil.getSaltingByte(buf, 1, size-1, bucketNum);
784 }
785 key.set(buf,0,size);
786 return i;
787 } finally {
788 try {
789 os.close();
790 } catch (IOException e) {
791 throw new RuntimeException(e); // Impossible
792 }
793 }
794 }
795
796 private PRow newRow(KeyValueBuilder builder, long ts, ImmutableBytesWritable key, int i, boolean hasOnDupKey, byte[]... values) {
797 PRow row = new PRowImpl(builder, key, ts, getBucketNum(), hasOnDupKey);
798 if (i < values.length) {
799 for (PColumnFamily family : getColumnFamilies()) {
800 for (PColumn column : family.getColumns()) {
801 row.setValue(column, values[i++]);
802 if (i == values.length)
803 return row;
804 }
805 }
806 }
807 return row;
808 }
809
810 @Override
811 public PRow newRow(KeyValueBuilder builder, long ts, ImmutableBytesWritable key,
812 boolean hasOnDupKey, byte[]... values) {
813 return newRow(builder, ts, key, 0, hasOnDupKey, values);
814 }
815
816 @Override
817 public PRow newRow(KeyValueBuilder builder, ImmutableBytesWritable key, boolean hasOnDupKey, byte[]... values) {
818 return newRow(builder, HConstants.LATEST_TIMESTAMP, key, hasOnDupKey, values);
819 }
820
821 @Override
822 public PColumn getColumnForColumnName(String name) throws ColumnNotFoundException, AmbiguousColumnException {
823 List<PColumn> columns = columnsByName.get(name);
824 int size = columns.size();
825 if (size == 0) {
826 String schemaNameStr = schemaName==null?null:schemaName.getString();
827 String tableNameStr = tableName==null?null:tableName.getString();
828 throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, name);
829
830 }
831 if (size > 1) {
832 for (PColumn column : columns) {
833 if (column.getFamilyName() == null || QueryConstants.DEFAULT_COLUMN_FAMILY.equals(column.getFamilyName().getString())) {
834 // Allow ambiguity with PK column or column in the default column family,
835 // since a PK column cannot be prefixed and a user would not know how to
836 // prefix a column in the default column family.
837 return column;
838 }
839 }
840 throw new AmbiguousColumnException(name);
841 }
842 return columns.get(0);
843 }
844
845 @Override
846 public PColumn getColumnForColumnQualifier(byte[] cf, byte[] cq) throws ColumnNotFoundException, AmbiguousColumnException {
847 Preconditions.checkNotNull(cq);
848 if (!EncodedColumnsUtil.usesEncodedColumnNames(this) || cf == null) {
849 String columnName = (String)PVarchar.INSTANCE.toObject(cq);
850 return getColumnForColumnName(columnName);
851 } else {
852 String family = (String)PVarchar.INSTANCE.toObject(cf);
853 PColumn col = kvColumnsByQualifiers.get(new KVColumnFamilyQualifier(family, cq));
854 if (col == null) {
855 String schemaNameStr = schemaName==null?null:schemaName.getString();
856 String tableNameStr = tableName==null?null:tableName.getString();
857 throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null,
858 "No column found for column qualifier " + qualifierEncodingScheme.decode(cq));
859 }
860 return col;
861 }
862 }
863
864 /**
865 *
866 * PRow implementation for ColumnLayout.MULTI mode which stores column
867 * values across multiple hbase columns.
868 *
869 *
870 * @since 0.1
871 */
872 private class PRowImpl implements PRow {
873 private final byte[] key;
874 private final ImmutableBytesWritable keyPtr;
875 // default to the generic builder, and only override when we know on the client
876 private final KeyValueBuilder kvBuilder;
877
878 private Mutation setValues;
879 private Delete unsetValues;
880 private Mutation deleteRow;
881 private final long ts;
882 private final boolean hasOnDupKey;
883 // map from column name to value
884 private Map<PColumn, byte[]> columnToValueMap;
885
886 public PRowImpl(KeyValueBuilder kvBuilder, ImmutableBytesWritable key, long ts, Integer bucketNum, boolean hasOnDupKey) {
887 this.kvBuilder = kvBuilder;
888 this.ts = ts;
889 this.hasOnDupKey = hasOnDupKey;
890 if (bucketNum != null) {
891 this.key = SaltingUtil.getSaltedKey(key, bucketNum);
892 this.keyPtr = new ImmutableBytesPtr(this.key);
893 } else {
894 this.keyPtr = new ImmutableBytesPtr(key);
895 this.key = ByteUtil.copyKeyBytesIfNecessary(key);
896 }
897 this.columnToValueMap = Maps.newHashMapWithExpectedSize(1);
898 newMutations();
899 }
900
901 private void newMutations() {
902 Mutation put = this.hasOnDupKey ? new Increment(this.key) : new Put(this.key);
903 Delete delete = new Delete(this.key);
904 if (isWALDisabled()) {
905 put.setDurability(Durability.SKIP_WAL);
906 delete.setDurability(Durability.SKIP_WAL);
907 }
908 this.setValues = put;
909 this.unsetValues = delete;
910 }
911
912 @Override
913 public List<Mutation> toRowMutations() {
914 List<Mutation> mutations = new ArrayList<Mutation>(3);
915 if (deleteRow != null) {
916 // Include only deleteRow mutation if present because it takes precedence over all others
917 mutations.add(deleteRow);
918 } else {
919 // store all columns for a given column family in a single cell instead of one column per cell in order to improve write performance
920 if (immutableStorageScheme != null && immutableStorageScheme != ImmutableStorageScheme.ONE_CELL_PER_COLUMN) {
921 Put put = new Put(this.key);
922 if (isWALDisabled()) {
923 put.setDurability(Durability.SKIP_WAL);
924 }
925 // the setValues Put contains one cell per column, we need to convert it to a Put that contains a cell with all columns for a given column family
926 for (PColumnFamily family : families) {
927 byte[] columnFamily = family.getName().getBytes();
928 Collection<PColumn> columns = family.getColumns();
929 int maxEncodedColumnQualifier = Integer.MIN_VALUE;
930 for (PColumn column : columns) {
931 int qualifier = qualifierEncodingScheme.decode(column.getColumnQualifierBytes());
932 maxEncodedColumnQualifier = Math.max(maxEncodedColumnQualifier, qualifier);
933 }
934 Expression[] colValues = EncodedColumnsUtil.createColumnExpressionArray(maxEncodedColumnQualifier);
935 for (PColumn column : columns) {
936 if (columnToValueMap.containsKey(column)) {
937 int colIndex = qualifierEncodingScheme.decode(column.getColumnQualifierBytes())-QueryConstants.ENCODED_CQ_COUNTER_INITIAL_VALUE+1;
938 colValues[colIndex] = new LiteralExpression(columnToValueMap.get(column));
939 }
940 }
941
942 List<Expression> children = Arrays.asList(colValues);
943 // we use SingleCellConstructorExpression to serialize all the columns into a single byte[]
944 SingleCellConstructorExpression singleCellConstructorExpression = new SingleCellConstructorExpression(immutableStorageScheme, children);
945 ImmutableBytesWritable ptr = new ImmutableBytesWritable();
946 singleCellConstructorExpression.evaluate(null, ptr);
947 ImmutableBytesPtr colFamilyPtr = new ImmutableBytesPtr(columnFamily);
948 addQuietly(put, kvBuilder, kvBuilder.buildPut(keyPtr,
949 colFamilyPtr, QueryConstants.SINGLE_KEYVALUE_COLUMN_QUALIFIER_BYTES_PTR, ts, ptr));
950 }
951 setValues = put;
952 }
953 // Because we cannot enforce a not null constraint on a KV column (since we don't know if the row exists when
954 // we upsert it), so instead add a KV that is always empty. This allows us to imitate SQL semantics given the
955 // way HBase works.
956 Pair<byte[], byte[]> emptyKvInfo = EncodedColumnsUtil.getEmptyKeyValueInfo(PTableImpl.this);
957 addQuietly(setValues, kvBuilder, kvBuilder.buildPut(keyPtr,
958 SchemaUtil.getEmptyColumnFamilyPtr(PTableImpl.this),
959 new ImmutableBytesPtr(emptyKvInfo.getFirst()), ts,
960 new ImmutableBytesPtr(emptyKvInfo.getSecond())));
961 mutations.add(setValues);
962 if (!unsetValues.isEmpty()) {
963 mutations.add(unsetValues);
964 }
965 }
966 return mutations;
967 }
968
969 private void removeIfPresent(Mutation m, byte[] family, byte[] qualifier) {
970 Map<byte[],List<Cell>> familyMap = m.getFamilyCellMap();
971 List<Cell> kvs = familyMap.get(family);
972 if (kvs != null) {
973 Iterator<Cell> iterator = kvs.iterator();
974 while (iterator.hasNext()) {
975 Cell kv = iterator.next();
976 if (Bytes.compareTo(kv.getQualifierArray(), kv.getQualifierOffset(), kv.getQualifierLength(),
977 qualifier, 0, qualifier.length) == 0) {
978 iterator.remove();
979 break;
980 }
981 }
982 }
983 }
984
985 @Override
986 public void setValue(PColumn column, byte[] byteValue) {
987 deleteRow = null;
988 byte[] family = column.getFamilyName().getBytes();
989 byte[] qualifier = column.getColumnQualifierBytes();
990 ImmutableBytesPtr qualifierPtr = new ImmutableBytesPtr(qualifier);
991 PDataType<?> type = column.getDataType();
992 // Check null, since some types have no byte representation for null
993 if (byteValue == null) {
994 byteValue = ByteUtil.EMPTY_BYTE_ARRAY;
995 }
996 boolean isNull = type.isNull(byteValue);
997 if (isNull && !column.isNullable()) {
998 throw new ConstraintViolationException(name.getString() + "." + column.getName().getString() +
999 " may not be null");
1000 } else if (isNull && PTableImpl.this.isImmutableRows() && column.getExpressionStr() == null) {
1001 // Store nulls for immutable tables otherwise default value would be used
1002 removeIfPresent(setValues, family, qualifier);
1003 removeIfPresent(unsetValues, family, qualifier);
1004 } else if (isNull && !getStoreNulls() && !this.hasOnDupKey && column.getExpressionStr() == null) {
1005 // Cannot use column delete marker when row has ON DUPLICATE KEY clause
1006 // because we cannot change a Delete mutation to a Put mutation in the
1007 // case of updates occurring due to the execution of the clause.
1008 removeIfPresent(setValues, family, qualifier);
1009 deleteQuietly(unsetValues, kvBuilder, kvBuilder.buildDeleteColumns(keyPtr, column
1010 .getFamilyName().getBytesPtr(), qualifierPtr, ts));
1011 } else {
1012 ImmutableBytesWritable ptr = new ImmutableBytesWritable(byteValue);
1013 Integer maxLength = column.getMaxLength();
1014 Integer scale = column.getScale();
1015 SortOrder sortOrder = column.getSortOrder();
1016 if (!type.isSizeCompatible(ptr, null, type, sortOrder, null, null, maxLength, scale)) {
1017 throw new DataExceedsCapacityException(name.getString() + "." + column.getName().getString() +
1018 " may not exceed " + maxLength + " (" + SchemaUtil.toString(type, byteValue) + ")");
1019 }
1020 ptr.set(byteValue);
1021 type.pad(ptr, maxLength, sortOrder);
1022 removeIfPresent(unsetValues, family, qualifier);
1023 // store all columns for a given column family in a single cell instead of one column per cell in order to improve write performance
1024 // we don't need to do anything with unsetValues as it is only used when storeNulls is false, storeNulls is always true when storeColsInSingleCell is true
1025 if (immutableStorageScheme == ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS) {
1026 columnToValueMap.put(column, ptr.get());
1027 }
1028 else {
1029 removeIfPresent(unsetValues, family, qualifier);
1030 addQuietly(setValues, kvBuilder, kvBuilder.buildPut(keyPtr,
1031 column.getFamilyName().getBytesPtr(), qualifierPtr,
1032 ts, ptr));
1033 }
1034 }
1035 }
1036
1037 @SuppressWarnings("deprecation")
1038 @Override
1039 public void delete() {
1040 newMutations();
1041 Delete delete = new Delete(key);
1042 if (families.isEmpty()) {
1043 delete.deleteFamily(SchemaUtil.getEmptyColumnFamily(PTableImpl.this), ts);
1044 } else {
1045 for (PColumnFamily colFamily : families) {
1046 delete.deleteFamily(colFamily.getName().getBytes(), ts);
1047 }
1048 }
1049
1050 deleteRow = delete;
1051
1052 if (isWALDisabled()) {
1053 deleteRow.setDurability(Durability.SKIP_WAL);
1054 }
1055 }
1056 }
1057
1058 @Override
1059 public PColumnFamily getColumnFamily(String familyName) throws ColumnFamilyNotFoundException {
1060 PColumnFamily family = familyByString.get(familyName);
1061 if (family == null) {
1062 String schemaNameStr = schemaName==null?null:schemaName.getString();
1063 String tableNameStr = tableName==null?null:tableName.getString();
1064 throw new ColumnFamilyNotFoundException(schemaNameStr, tableNameStr, familyName);
1065 }
1066 return family;
1067 }
1068
1069 @Override
1070 public PColumnFamily getColumnFamily(byte[] familyBytes) throws ColumnFamilyNotFoundException {
1071 PColumnFamily family = familyByBytes.get(familyBytes);
1072 if (family == null) {
1073 String familyName = Bytes.toString(familyBytes);
1074 String schemaNameStr = schemaName==null?null:schemaName.getString();
1075 String tableNameStr = tableName==null?null:tableName.getString();
1076 throw new ColumnFamilyNotFoundException(schemaNameStr, tableNameStr, familyName);
1077 }
1078 return family;
1079 }
1080
1081 @Override
1082 public List<PColumn> getColumns() {
1083 return allColumns;
1084 }
1085
1086 @Override
1087 public long getSequenceNumber() {
1088 return sequenceNumber;
1089 }
1090
1091 @Override
1092 public long getTimeStamp() {
1093 return timeStamp;
1094 }
1095
1096 @Override
1097 public long getIndexDisableTimestamp() {
1098 return indexDisableTimestamp;
1099 }
1100
1101 @Override
1102 public PColumn getPKColumn(String name) throws ColumnNotFoundException {
1103 List<PColumn> columns = columnsByName.get(name);
1104 int size = columns.size();
1105 if (size == 0) {
1106 String schemaNameStr = schemaName==null?null:schemaName.getString();
1107 String tableNameStr = tableName==null?null:tableName.getString();
1108 throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, name);
1109 }
1110 if (size > 1) {
1111 do {
1112 PColumn column = columns.get(--size);
1113 if (column.getFamilyName() == null) {
1114 return column;
1115 }
1116 } while (size > 0);
1117 String schemaNameStr = schemaName==null?null:schemaName.getString();
1118 String tableNameStr = tableName==null?null:tableName.getString();
1119 throw new ColumnNotFoundException(schemaNameStr, tableNameStr, null, name);
1120 }
1121 return columns.get(0);
1122 }
1123
1124 @Override
1125 public PName getPKName() {
1126 return pkName;
1127 }
1128
1129 @Override
1130 public RowKeySchema getRowKeySchema() {
1131 return rowKeySchema;
1132 }
1133
1134 @Override
1135 public Integer getBucketNum() {
1136 return bucketNum;
1137 }
1138
1139 @Override
1140 public List<PTable> getIndexes() {
1141 return indexes;
1142 }
1143
1144 @Override
1145 public PIndexState getIndexState() {
1146 return state;
1147 }
1148
1149 @Override
1150 public PName getParentTableName() {
1151 // a view on a table will not have a parent name but will have a physical table name (which is the parent)
1152 return (type!=PTableType.VIEW || parentName!=null) ? parentTableName :
1153 PNameFactory.newName(SchemaUtil.getTableNameFromFullName(getPhysicalName().getBytes()));
1154 }
1155
1156 @Override
1157 public PName getParentName() {
1158 // a view on a table will not have a parent name but will have a physical table name (which is the parent)
1159 return (type!=PTableType.VIEW || parentName!=null) ? parentName : getPhysicalName();
1160 }
1161
1162 @Override
1163 public synchronized IndexMaintainer getIndexMaintainer(PTable dataTable, PhoenixConnection connection) {
1164 if (indexMaintainer == null) {
1165 indexMaintainer = IndexMaintainer.create(dataTable, this, connection);
1166 }
1167 return indexMaintainer;
1168 }
1169
1170 @Override
1171 public synchronized boolean getIndexMaintainers(ImmutableBytesWritable ptr, PhoenixConnection connection) {
1172 if (indexMaintainersPtr == null || indexMaintainersPtr.getLength()==0) {
1173 indexMaintainersPtr = new ImmutableBytesWritable();
1174 if (indexes.isEmpty()) {
1175 indexMaintainersPtr.set(ByteUtil.EMPTY_BYTE_ARRAY);
1176 } else {
1177 IndexMaintainer.serialize(this, indexMaintainersPtr, connection);
1178 }
1179 }
1180 ptr.set(indexMaintainersPtr.get(), indexMaintainersPtr.getOffset(), indexMaintainersPtr.getLength());
1181 return indexMaintainersPtr.getLength() > 0;
1182 }
1183
1184 @Override
1185 public PName getPhysicalName() {
1186 if (physicalNames.isEmpty()) {
1187 return SchemaUtil.getPhysicalHBaseTableName(schemaName, tableName, isNamespaceMapped);
1188 } else {
1189 return PNameFactory.newName(physicalNames.get(0).getBytes());
1190 }
1191 }
1192
1193 @Override
1194 public List<PName> getPhysicalNames() {
1195 return physicalNames;
1196 }
1197
1198 @Override
1199 public PName getDefaultFamilyName() {
1200 return defaultFamilyName;
1201 }
1202
1203 @Override
1204 public String getViewStatement() {
1205 return viewStatement;
1206 }
1207
1208 @Override
1209 public boolean isWALDisabled() {
1210 return disableWAL;
1211 }
1212
1213 @Override
1214 public Short getViewIndexId() {
1215 return viewIndexId;
1216 }
1217
1218 @Override
1219 public PName getTenantId() {
1220 return tenantId;
1221 }
1222
1223 @Override
1224 public IndexType getIndexType() {
1225 return indexType;
1226 }
1227
1228 /**
1229 * Construct a PTable instance from ProtoBuffered PTable instance
1230 * @param table
1231 */
1232 public static PTable createFromProto(PTableProtos.PTable table) {
1233 PName tenantId = null;
1234 if(table.hasTenantId()){
1235 tenantId = PNameFactory.newName(table.getTenantId().toByteArray());
1236 }
1237 PName schemaName = PNameFactory.newName(table.getSchemaNameBytes().toByteArray());
1238 PName tableName = PNameFactory.newName(table.getTableNameBytes().toByteArray());
1239 PTableType tableType = PTableType.values()[table.getTableType().ordinal()];
1240 PIndexState indexState = null;
1241 if (table.hasIndexState()) {
1242 indexState = PIndexState.fromSerializedValue(table.getIndexState());
1243 }
1244 Short viewIndexId = null;
1245 if(table.hasViewIndexId()){
1246 viewIndexId = (short)table.getViewIndexId();
1247 }
1248 IndexType indexType = IndexType.getDefault();
1249 if(table.hasIndexType()){
1250 indexType = IndexType.fromSerializedValue(table.getIndexType().toByteArray()[0]);
1251 }
1252 long sequenceNumber = table.getSequenceNumber();
1253 long timeStamp = table.getTimeStamp();
1254 long indexDisableTimestamp = table.getIndexDisableTimestamp();
1255 PName pkName = null;
1256 if (table.hasPkNameBytes()) {
1257 pkName = PNameFactory.newName(table.getPkNameBytes().toByteArray());
1258 }
1259 int bucketNum = table.getBucketNum();
1260 List<PColumn> columns = Lists.newArrayListWithExpectedSize(table.getColumnsCount());
1261 for (PTableProtos.PColumn curPColumnProto : table.getColumnsList()) {
1262 columns.add(PColumnImpl.createFromProto(curPColumnProto));
1263 }
1264 List<PTable> indexes = Lists.newArrayListWithExpectedSize(table.getIndexesCount());
1265 for (PTableProtos.PTable curPTableProto : table.getIndexesList()) {
1266 indexes.add(createFromProto(curPTableProto));
1267 }
1268
1269 boolean isImmutableRows = table.getIsImmutableRows();
1270 PName parentSchemaName = null;
1271 PName parentTableName = null;
1272 if (table.hasParentNameBytes()) {
1273 parentSchemaName = PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName((table.getParentNameBytes().toByteArray())));
1274 parentTableName = PNameFactory.newName(SchemaUtil.getTableNameFromFullName(table.getParentNameBytes().toByteArray()));
1275 }
1276 PName defaultFamilyName = null;
1277 if (table.hasDefaultFamilyName()) {
1278 defaultFamilyName = PNameFactory.newName(table.getDefaultFamilyName().toByteArray());
1279 }
1280 boolean disableWAL = table.getDisableWAL();
1281 boolean multiTenant = table.getMultiTenant();
1282 boolean storeNulls = table.getStoreNulls();
1283 TransactionFactory.Provider transactionProvider = null;
1284 if (table.hasTransactionProvider()) {
1285 transactionProvider = TransactionFactory.Provider.fromCode(table.getTransactionProvider());
1286 } else if (table.hasTransactional()) {
1287 // For backward compatibility prior to transactionProvider field
1288 transactionProvider = TransactionFactory.Provider.TEPHRA;
1289 }
1290 ViewType viewType = null;
1291 String viewStatement = null;
1292 List<PName> physicalNames = Collections.emptyList();
1293 if (tableType == PTableType.VIEW) {
1294 viewType = ViewType.fromSerializedValue(table.getViewType().toByteArray()[0]);
1295 }
1296 if(table.hasViewStatement()){
1297 viewStatement = (String) PVarchar.INSTANCE.toObject(table.getViewStatement().toByteArray());
1298 }
1299 if (tableType == PTableType.VIEW || viewIndexId != null) {
1300 physicalNames = Lists.newArrayListWithExpectedSize(table.getPhysicalNamesCount());
1301 for(int i = 0; i < table.getPhysicalNamesCount(); i++) {
1302 physicalNames.add(PNameFactory.newName(table.getPhysicalNames(i).toByteArray()));
1303 }
1304 }
1305 int baseColumnCount = -1;
1306 if (table.hasBaseColumnCount()) {
1307 baseColumnCount = table.getBaseColumnCount();
1308 }
1309
1310 boolean rowKeyOrderOptimizable = false;
1311 if (table.hasRowKeyOrderOptimizable()) {
1312 rowKeyOrderOptimizable = table.getRowKeyOrderOptimizable();
1313 }
1314 long updateCacheFrequency = 0;
1315 if (table.hasUpdateCacheFrequency()) {
1316 updateCacheFrequency = table.getUpdateCacheFrequency();
1317 }
1318 boolean isNamespaceMapped=false;
1319 if (table.hasIsNamespaceMapped()) {
1320 isNamespaceMapped = table.getIsNamespaceMapped();
1321 }
1322 String autoParititonSeqName = null;
1323 if (table.hasAutoParititonSeqName()) {
1324 autoParititonSeqName = table.getAutoParititonSeqName();
1325 }
1326 boolean isAppendOnlySchema = false;
1327 if (table.hasIsAppendOnlySchema()) {
1328 isAppendOnlySchema = table.getIsAppendOnlySchema();
1329 }
1330 // For backward compatibility. Clients older than 4.10 will always have non-encoded immutable tables.
1331 ImmutableStorageScheme storageScheme = ImmutableStorageScheme.ONE_CELL_PER_COLUMN;
1332 if (table.hasStorageScheme()) {
1333 storageScheme = ImmutableStorageScheme.fromSerializedValue(table.getStorageScheme().toByteArray()[0]);
1334 }
1335 // For backward compatibility. Clients older than 4.10 will always have non-encoded qualifiers.
1336 QualifierEncodingScheme qualifierEncodingScheme = QualifierEncodingScheme.NON_ENCODED_QUALIFIERS;
1337 if (table.hasEncodingScheme()) {
1338 qualifierEncodingScheme = QualifierEncodingScheme.fromSerializedValue(table.getEncodingScheme().toByteArray()[0]);
1339 }
1340 EncodedCQCounter encodedColumnQualifierCounter = null;
1341 if ((!EncodedColumnsUtil.usesEncodedColumnNames(qualifierEncodingScheme) || tableType == PTableType.VIEW)) {
1342 encodedColumnQualifierCounter = PTable.EncodedCQCounter.NULL_COUNTER;
1343 }
1344 else {
1345 encodedColumnQualifierCounter = new EncodedCQCounter();
1346 if (table.getEncodedCQCountersList() != null) {
1347 for (org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter cqCounterFromProto : table.getEncodedCQCountersList()) {
1348 encodedColumnQualifierCounter.setValue(cqCounterFromProto.getColFamily(), cqCounterFromProto.getCounter());
1349 }
1350 }
1351 }
1352 Boolean useStatsForParallelization = null;
1353 if (table.hasUseStatsForParallelization()) {
1354 useStatsForParallelization = table.getUseStatsForParallelization();
1355 }
1356 try {
1357 PTableImpl result = new PTableImpl();
1358 result.init(tenantId, schemaName, tableName, tableType, indexState, timeStamp, sequenceNumber, pkName,
1359 (bucketNum == NO_SALTING) ? null : bucketNum, columns, parentSchemaName, parentTableName, indexes,
1360 isImmutableRows, physicalNames, defaultFamilyName, viewStatement, disableWAL,
1361 multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
1362 transactionProvider, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoParititonSeqName,
1363 isAppendOnlySchema, storageScheme, qualifierEncodingScheme, encodedColumnQualifierCounter, useStatsForParallelization);
1364 return result;
1365 } catch (SQLException e) {
1366 throw new RuntimeException(e); // Impossible
1367 }
1368 }
1369
1370 public static PTableProtos.PTable toProto(PTable table) {
1371 PTableProtos.PTable.Builder builder = PTableProtos.PTable.newBuilder();
1372 if(table.getTenantId() != null){
1373 builder.setTenantId(ByteStringer.wrap(table.getTenantId().getBytes()));
1374 }
1375 builder.setSchemaNameBytes(ByteStringer.wrap(table.getSchemaName().getBytes()));
1376 builder.setTableNameBytes(ByteStringer.wrap(table.getTableName().getBytes()));
1377 builder.setTableType(ProtobufUtil.toPTableTypeProto(table.getType()));
1378 if (table.getType() == PTableType.INDEX) {
1379 if(table.getIndexState() != null) {
1380 builder.setIndexState(table.getIndexState().getSerializedValue());
1381 }
1382 if(table.getViewIndexId() != null) {
1383 builder.setViewIndexId(table.getViewIndexId());
1384 }
1385 if(table.getIndexType() != null) {
1386 builder.setIndexType(ByteStringer.wrap(new byte[]{table.getIndexType().getSerializedValue()}));
1387 }
1388 }
1389 builder.setSequenceNumber(table.getSequenceNumber());
1390 builder.setTimeStamp(table.getTimeStamp());
1391 PName tmp = table.getPKName();
1392 if (tmp != null) {
1393 builder.setPkNameBytes(ByteStringer.wrap(tmp.getBytes()));
1394 }
1395 Integer bucketNum = table.getBucketNum();
1396 int offset = 0;
1397 if(bucketNum == null){
1398 builder.setBucketNum(NO_SALTING);
1399 } else {
1400 offset = 1;
1401 builder.setBucketNum(bucketNum);
1402 }
1403 List<PColumn> columns = table.getColumns();
1404 int columnSize = columns.size();
1405 for (int i = offset; i < columnSize; i++) {
1406 PColumn column = columns.get(i);
1407 builder.addColumns(PColumnImpl.toProto(column));
1408 }
1409
1410 List<PTable> indexes = table.getIndexes();
1411 for (PTable curIndex : indexes) {
1412 builder.addIndexes(toProto(curIndex));
1413 }
1414 builder.setIsImmutableRows(table.isImmutableRows());
1415 // TODO remove this field in 5.0 release
1416 if (table.getParentName() != null) {
1417 builder.setDataTableNameBytes(ByteStringer.wrap(table.getParentTableName().getBytes()));
1418 }
1419 if (table.getParentName() !=null) {
1420 builder.setParentNameBytes(ByteStringer.wrap(table.getParentName().getBytes()));
1421 }
1422 if (table.getDefaultFamilyName()!= null) {
1423 builder.setDefaultFamilyName(ByteStringer.wrap(table.getDefaultFamilyName().getBytes()));
1424 }
1425 builder.setDisableWAL(table.isWALDisabled());
1426 builder.setMultiTenant(table.isMultiTenant());
1427 builder.setStoreNulls(table.getStoreNulls());
1428 if (table.getTransactionProvider() != null) {
1429 builder.setTransactionProvider(table.getTransactionProvider().getCode());
1430 }
1431 if(table.getType() == PTableType.VIEW){
1432 builder.setViewType(ByteStringer.wrap(new byte[]{table.getViewType().getSerializedValue()}));
1433 }
1434 if(table.getViewStatement()!=null){
1435 builder.setViewStatement(ByteStringer.wrap(PVarchar.INSTANCE.toBytes(table.getViewStatement())));
1436 }
1437 if(table.getType() == PTableType.VIEW || table.getViewIndexId() != null){
1438 for (int i = 0; i < table.getPhysicalNames().size(); i++) {
1439 builder.addPhysicalNames(ByteStringer.wrap(table.getPhysicalNames().get(i).getBytes()));
1440 }
1441 }
1442 builder.setBaseColumnCount(table.getBaseColumnCount());
1443 builder.setRowKeyOrderOptimizable(table.rowKeyOrderOptimizable());
1444 builder.setUpdateCacheFrequency(table.getUpdateCacheFrequency());
1445 builder.setIndexDisableTimestamp(table.getIndexDisableTimestamp());
1446 builder.setIsNamespaceMapped(table.isNamespaceMapped());
1447 if (table.getAutoPartitionSeqName() != null) {
1448 builder.setAutoParititonSeqName(table.getAutoPartitionSeqName());
1449 }
1450 builder.setIsAppendOnlySchema(table.isAppendOnlySchema());
1451 if (table.getImmutableStorageScheme() != null) {
1452 builder.setStorageScheme(ByteStringer.wrap(new byte[]{table.getImmutableStorageScheme().getSerializedMetadataValue()}));
1453 }
1454 if (table.getEncodedCQCounter() != null) {
1455 Map<String, Integer> values = table.getEncodedCQCounter().values();
1456 for (Entry<String, Integer> cqCounter : values.entrySet()) {
1457 org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter.Builder cqBuilder = org.apache.phoenix.coprocessor.generated.PTableProtos.EncodedCQCounter.newBuilder();
1458 cqBuilder.setColFamily(cqCounter.getKey());
1459 cqBuilder.setCounter(cqCounter.getValue());
1460 builder.addEncodedCQCounters(cqBuilder.build());
1461 }
1462 }
1463 if (table.getEncodingScheme() != null) {
1464 builder.setEncodingScheme(ByteStringer.wrap(new byte[]{table.getEncodingScheme().getSerializedMetadataValue()}));
1465 }
1466 if (table.useStatsForParallelization() != null) {
1467 builder.setUseStatsForParallelization(table.useStatsForParallelization());
1468 }
1469 return builder.build();
1470 }
1471
1472 @Override
1473 public PTableKey getKey() {
1474 return key;
1475 }
1476
1477 @Override
1478 public PName getParentSchemaName() {
1479 // a view on a table will not have a parent name but will have a physical table name (which is the parent)
1480 return (type!=PTableType.VIEW || parentName!=null) ? parentSchemaName :
1481 PNameFactory.newName(SchemaUtil.getSchemaNameFromFullName(getPhysicalName().getBytes()));
1482 }
1483
1484 @Override
1485 public TransactionFactory.Provider getTransactionProvider() {
1486 return transactionProvider;
1487 }
1488
1489 @Override
1490 public final boolean isTransactional() {
1491 return transactionProvider != null;
1492 }
1493
1494 @Override
1495 public int getBaseColumnCount() {
1496 return baseColumnCount;
1497 }
1498
1499 @Override
1500 public boolean rowKeyOrderOptimizable() {
1501 return rowKeyOrderOptimizable || !hasColumnsRequiringUpgrade;
1502 }
1503
1504 @Override
1505 public int getRowTimestampColPos() {
1506 return rowTimestampColPos;
1507 }
1508
1509 @Override
1510 public boolean isNamespaceMapped() {
1511 return isNamespaceMapped;
1512 }
1513
1514 @Override
1515 public String getAutoPartitionSeqName() {
1516 return autoPartitionSeqName;
1517 }
1518
1519 @Override
1520 public boolean isAppendOnlySchema() {
1521 return isAppendOnlySchema;
1522 }
1523
1524 @Override
1525 public int hashCode() {
1526 final int prime = 31;
1527 int result = 1;
1528 result = prime * result + ((key == null) ? 0 : key.hashCode());
1529 return result;
1530 }
1531
1532 @Override
1533 public boolean equals(Object obj) {
1534 if (this == obj) return true;
1535 if (obj == null) return false;
1536 if (! (obj instanceof PTable)) return false;
1537 PTable other = (PTable) obj;
1538 if (key == null) {
1539 if (other.getKey() != null) return false;
1540 } else if (!key.equals(other.getKey())) return false;
1541 return true;
1542 }
1543
1544 @Override
1545 public ImmutableStorageScheme getImmutableStorageScheme() {
1546 return immutableStorageScheme;
1547 }
1548
1549 @Override
1550 public EncodedCQCounter getEncodedCQCounter() {
1551 return encodedCQCounter;
1552 }
1553
1554 @Override
1555 public QualifierEncodingScheme getEncodingScheme() {
1556 return qualifierEncodingScheme;
1557 }
1558
1559 @Override
1560 public Boolean useStatsForParallelization() {
1561 return useStatsForParallelization;
1562 }
1563
1564 private static final class KVColumnFamilyQualifier {
1565 @Nonnull
1566 private final String colFamilyName;
1567 @Nonnull
1568 private final byte[] colQualifier;
1569
1570 public KVColumnFamilyQualifier(String colFamilyName, byte[] colQualifier) {
1571 Preconditions.checkArgument(colFamilyName != null && colQualifier != null,
1572 "None of the arguments, column family name or column qualifier can be null");
1573 this.colFamilyName = colFamilyName;
1574 this.colQualifier = colQualifier;
1575 }
1576
1577 @Override
1578 public int hashCode() {
1579 final int prime = 31;
1580 int result = 1;
1581 result = prime * result + colFamilyName.hashCode();
1582 result = prime * result + Arrays.hashCode(colQualifier);
1583 return result;
1584 }
1585
1586 @Override
1587 public boolean equals(Object obj) {
1588 if (this == obj) return true;
1589 if (obj == null) return false;
1590 if (getClass() != obj.getClass()) return false;
1591 KVColumnFamilyQualifier other = (KVColumnFamilyQualifier) obj;
1592 if (!colFamilyName.equals(other.colFamilyName)) return false;
1593 if (!Arrays.equals(colQualifier, other.colQualifier)) return false;
1594 return true;
1595 }
1596
1597 }
1598 }