You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/10/18 03:40:53 UTC
[1/4] PHOENIX-1297 Adding utility methods to get primary key
information from the optimized query plan (Samarth Jain)
Repository: phoenix
Updated Branches:
refs/heads/3.0 b95498c55 -> ef062ad25
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java b/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
index 9b0ebff..766917c 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
@@ -18,6 +18,7 @@
package org.apache.phoenix.schema;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -70,6 +71,48 @@ public class ValueBitSetTest {
}
@Test
+ public void testMinNullableIndex() {
+ final int minNullableIndex = 4; // first 4 fields are not nullable.
+ int numFields = 6;
+ KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(minNullableIndex);
+ for (int i = 0; i < numFields; i++) {
+ final int fieldIndex = i;
+ builder.addField(new PDatum() {
+ @Override
+ public boolean isNullable() {
+ // not nullable till index reaches minNullableIndex
+ return fieldIndex < minNullableIndex;
+ }
+
+ @Override
+ public SortOrder getSortOrder() {
+ return SortOrder.getDefault();
+ }
+
+ @Override
+ public Integer getScale() {
+ return null;
+ }
+
+ @Override
+ public Integer getMaxLength() {
+ return null;
+ }
+
+ @Override
+ public PDataType getDataType() {
+ return PDataType.values()[fieldIndex % PDataType.values().length];
+ }
+ });
+ }
+ KeyValueSchema kvSchema = builder.build();
+ assertFalse(kvSchema.getFields().get(0).isNullable());
+ assertFalse(kvSchema.getFields().get(minNullableIndex - 1).isNullable());
+ assertTrue(kvSchema.getFields().get(minNullableIndex).isNullable());
+ assertTrue(kvSchema.getFields().get(minNullableIndex + 1).isNullable());
+ }
+
+ @Test
public void testNullCount() {
int nFields = 32;
int nRepeating = 5;
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
new file mode 100644
index 0000000..7ddb235
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ *distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you maynot use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicablelaw or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.util.Arrays;
+
+import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class PhoenixEncodeDecodeTest extends BaseConnectionlessQueryTest {
+
+ @Test
+ public void testDecodeValues1() throws Exception {
+ testDecodeValues(false, false);
+ }
+
+ @Test
+ public void testDecodeValues2() throws Exception {
+ testDecodeValues(true, false);
+ }
+
+ @Test
+ public void testDecodeValues3() throws Exception {
+ testDecodeValues(true, true);
+ }
+
+ @Test
+ public void testDecodeValues4() throws Exception {
+ testDecodeValues(false, true);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void testDecodeValues(boolean nullFixedWidth, boolean nullVariableWidth) throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl());
+ conn.createStatement().execute(
+ "CREATE TABLE T(pk1 CHAR(15) not null, pk2 VARCHAR not null, CF1.v1 DATE, CF2.v2 VARCHAR, CF2.v1 VARCHAR " +
+ "CONSTRAINT pk PRIMARY KEY (pk1, pk2)) ");
+
+ Date d = nullFixedWidth ? null : new Date(100);
+ String s = nullVariableWidth ? null : "foo";
+ Object[] values = new Object[] {"def", "eid", d, s, s};
+ byte[] bytes = PhoenixRuntime.encodeValues(conn, "T", values, Lists.newArrayList(new Pair<String, String>(null, "pk1"), new Pair<String, String>(null, "pk2"), new Pair<String, String>("cf1", "v1"), new Pair<String, String>("cf2", "v2"), new Pair<String, String>("cf2", "v1")));
+ Object[] decodedValues = PhoenixRuntime.decodeValues(conn, "T", bytes, Lists.newArrayList(new Pair<String, String>(null, "pk1"), new Pair<String, String>(null, "pk2"), new Pair<String, String>("cf1", "v1"), new Pair<String, String>("cf2", "v2"), new Pair<String, String>("cf2", "v1")));
+ assertEquals(Lists.newArrayList("def", "eid", d, s, s), Arrays.asList(decodedValues));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
index 0e3da98..25da3aa 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
@@ -22,8 +22,20 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.compile.QueryPlan;
import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.schema.PDataType;
import org.junit.Test;
import com.google.common.collect.ImmutableList;
@@ -81,4 +93,67 @@ public class PhoenixRuntimeTest extends BaseConnectionlessQueryTest {
assertTrue(execCmd.isStrict());
assertEquals("!", execCmd.getArrayElementSeparator());
}
+
+ @Test
+ public void testGetPkColsDataTypes() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+ int i = 0;
+ PDataType[] pTypes = PDataType.values();
+ int size = pTypes.length;
+ StringBuilder sb = null;
+ try {
+ for (i = 0 ; i < size; i++) {
+ PDataType pType = pTypes[i];
+ String sqlTypeName = pType.getSqlTypeName();
+ if (sqlTypeName.equalsIgnoreCase("VARBINARY ARRAY")) {
+ // we don't support VARBINARY ARRAYS yet
+ // JIRA - https://issues.apache.org/jira/browse/PHOENIX-1329
+ continue;
+ }
+ if (pType.isArrayType() && PDataType.arrayBaseType(pType).isFixedWidth() && PDataType.arrayBaseType(pType).getByteSize() == null) {
+ // Need to treat array type whose base type is of fixed width whose byte size is not known as a special case.
+ // Cannot just use the sql type name returned by PDataType.getSqlTypeName().
+ String baseTypeName = PDataType.arrayBaseType(pType).getSqlTypeName();
+ sqlTypeName = baseTypeName + "(15)" + " " + PDataType.ARRAY_TYPE_SUFFIX;
+ } else if (pType.isFixedWidth() && pType.getByteSize() == null) {
+ sqlTypeName = sqlTypeName + "(15)";
+ }
+ String columnName = "col" + i;
+ String tableName = "t" + i;
+
+ sb = new StringBuilder(100);
+
+ // create a table by using the type name as returned by PDataType
+ sb.append("CREATE TABLE " + tableName + " (");
+ sb.append(columnName + " " + sqlTypeName + " NOT NULL PRIMARY KEY, V1 VARCHAR)");
+ conn.createStatement().execute(sb.toString());
+
+ // generate the optimized query plan by going through the pk of the table.
+ PreparedStatement stmt = conn.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnName + " = ?");
+ Integer maxLength = pType.isFixedWidth() && pType.getByteSize() == null ? 15 : null;
+ stmt.setObject(1, pType.getSampleValue(maxLength));
+ QueryPlan plan = PhoenixRuntime.getOptimizedQueryPlan(stmt);
+
+ // now go through the utility method, get column name and type name and
+ // try creating another table with the returned info. Use the query plan generated above.
+ // If table can be created with the returned sql type name, then great!
+ // It would mean "Roundtrip" of column data type name works.
+ List<Pair<String, String>> pkCols = new ArrayList<Pair<String, String>>();
+ List<String> dataTypes = new ArrayList<String>();
+ PhoenixRuntime.getPkColsDataTypesForSql(pkCols, dataTypes, plan, conn, true);
+
+ tableName = "newt" + i;
+ columnName = "newCol" + i;
+ String roundTripSqlTypeName = dataTypes.get(0);
+
+ // create a table by using the type name as returned by the utility method
+ sb = new StringBuilder(100);
+ sb.append("CREATE TABLE " + tableName + " (");
+ sb.append(columnName + " " + roundTripSqlTypeName + " NOT NULL PRIMARY KEY)");
+ conn.createStatement().execute(sb.toString());
+ }
+ } catch (Exception e) {
+ fail("Failed sql: " + sb.toString() + ExceptionUtils.getStackTrace(e));
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
----------------------------------------------------------------------
diff --git a/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java b/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
index 6538d89..0e21ed1 100644
--- a/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
+++ b/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
@@ -616,7 +616,10 @@ public class PhoenixHBaseLoaderIT {
@AfterClass
public static void tearDownAfterClass() throws Exception {
- conn.close();
- hbaseTestUtil.shutdownMiniCluster();
+ try {
+ conn.close();
+ } finally {
+ hbaseTestUtil.shutdownMiniCluster();
+ }
}
}
\ No newline at end of file
[3/4] git commit: PHOENIX-1365 Make sequence salt buckets configurable
Posted by ja...@apache.org.
PHOENIX-1365 Make sequence salt buckets configurable
Conflicts:
phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/cf07a5dd
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/cf07a5dd
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/cf07a5dd
Branch: refs/heads/3.0
Commit: cf07a5dd5981e0b6dbb5d1b562bd47fee32f97dc
Parents: 878570d
Author: James Taylor <jt...@salesforce.com>
Authored: Fri Oct 17 13:35:17 2014 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Fri Oct 17 18:44:13 2014 -0700
----------------------------------------------------------------------
.../phoenix/query/ConnectionQueryServicesImpl.java | 3 +--
.../java/org/apache/phoenix/schema/MetaDataClient.java | 11 +++++------
.../phoenix/schema/NewerTableAlreadyExistsException.java | 9 +++++++++
.../java/org/apache/phoenix/util/PhoenixRuntime.java | 3 +--
4 files changed, 16 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/cf07a5dd/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index f1d12fc..688cf42 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -1343,8 +1343,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
} catch (NewerTableAlreadyExistsException e) {
// Ignore, as this will happen if the SYSTEM.SEQUENCE already exists at this fixed timestamp.
// A TableAlreadyExistsException is not thrown, since the table only exists *after* this fixed timestamp.
- PTable sequenceTable = ConnectionQueryServicesImpl.this.latestMetaData.getTable(new PTableKey(null, PhoenixDatabaseMetaData.SEQUENCE_FULLNAME));
- Integer sequenceSaltBuckets = sequenceTable.getBucketNum();
+ Integer sequenceSaltBuckets = e.getTable().getBucketNum();
nSequenceSaltBuckets = sequenceSaltBuckets == null ? 0 : sequenceSaltBuckets;
} catch (TableAlreadyExistsException e) {
// This will occur if we have an older SYSTEM.SEQUENCE, so we need to update it to include
http://git-wip-us.apache.org/repos/asf/phoenix/blob/cf07a5dd/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
index e950903..712ef5c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
@@ -1348,7 +1348,9 @@ public class MetaDataClient {
case PARENT_TABLE_NOT_FOUND:
throw new TableNotFoundException(schemaName, parent.getName().getString());
case NEWER_TABLE_FOUND:
- throw new NewerTableAlreadyExistsException(schemaName, tableName);
+ // Add table to ConnectionQueryServices so it's cached, but don't add
+ // it to this connection as we can't see it.
+ throw new NewerTableAlreadyExistsException(schemaName, tableName, result.getTable());
case UNALLOWED_TABLE_MUTATION:
throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_TABLE)
.setSchemaName(schemaName).setTableName(tableName).build().buildException();
@@ -1468,7 +1470,7 @@ public class MetaDataClient {
}
break;
case NEWER_TABLE_FOUND:
- throw new NewerTableAlreadyExistsException(schemaName, tableName);
+ throw new NewerTableAlreadyExistsException(schemaName, tableName, result.getTable());
case UNALLOWED_TABLE_MUTATION:
throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_TABLE)
.setSchemaName(schemaName).setTableName(tableName).build().buildException();
@@ -1579,10 +1581,7 @@ public class MetaDataClient {
}
throw new ConcurrentTableMutationException(schemaName, tableName);
case NEWER_TABLE_FOUND:
- if (result.getTable() != null) {
- connection.addTable(result.getTable());
- }
- throw new NewerTableAlreadyExistsException(schemaName, tableName);
+ throw new NewerTableAlreadyExistsException(schemaName, tableName, result.getTable());
case NO_PK_COLUMNS:
throw new SQLExceptionInfo.Builder(SQLExceptionCode.PRIMARY_KEY_MISSING)
.setSchemaName(schemaName).setTableName(tableName).build().buildException();
http://git-wip-us.apache.org/repos/asf/phoenix/blob/cf07a5dd/phoenix-core/src/main/java/org/apache/phoenix/schema/NewerTableAlreadyExistsException.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/NewerTableAlreadyExistsException.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/NewerTableAlreadyExistsException.java
index c5afcec..5404485 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/NewerTableAlreadyExistsException.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/NewerTableAlreadyExistsException.java
@@ -19,9 +19,18 @@ package org.apache.phoenix.schema;
public class NewerTableAlreadyExistsException extends TableAlreadyExistsException {
private static final long serialVersionUID = 1L;
+ private final PTable table;
public NewerTableAlreadyExistsException(String schemaName, String tableName) {
+ this(schemaName, tableName, null);
+ }
+
+ public NewerTableAlreadyExistsException(String schemaName, String tableName, PTable table) {
super(schemaName, tableName);
+ this.table = table;
}
+ public PTable getTable() {
+ return table;
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/cf07a5dd/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
index 36c3ede..3d19692 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
@@ -61,6 +61,7 @@ import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.AmbiguousColumnException;
import org.apache.phoenix.schema.ColumnNotFoundException;
import org.apache.phoenix.schema.KeyValueSchema;
+import org.apache.phoenix.schema.KeyValueSchema.KeyValueSchemaBuilder;
import org.apache.phoenix.schema.MetaDataClient;
import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.PColumnFamily;
@@ -70,10 +71,8 @@ import org.apache.phoenix.schema.PTableKey;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.RowKeySchema;
import org.apache.phoenix.schema.TableNotFoundException;
-import org.apache.phoenix.schema.KeyValueSchema.KeyValueSchemaBuilder;
import org.apache.phoenix.schema.ValueBitSet;
-import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
[2/4] git commit: PHOENIX-1297 Adding utility methods to get primary
key information from the optimized query plan (Samarth Jain)
Posted by ja...@apache.org.
PHOENIX-1297 Adding utility methods to get primary key information from the optimized query plan (Samarth Jain)
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/878570d0
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/878570d0
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/878570d0
Branch: refs/heads/3.0
Commit: 878570d077f98b4c381c19ec44c444e7b4d75fbc
Parents: b95498c
Author: James Taylor <jt...@salesforce.com>
Authored: Fri Oct 17 18:37:50 2014 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Fri Oct 17 18:37:50 2014 -0700
----------------------------------------------------------------------
.../org/apache/phoenix/end2end/ArrayIT.java | 8 +-
.../phoenix/end2end/PhoenixEncodeDecodeIT.java | 215 ---------------
.../org/apache/phoenix/end2end/QueryMoreIT.java | 141 ++++++----
.../org/apache/phoenix/end2end/StddevIT.java | 40 +--
.../apache/phoenix/schema/KeyValueSchema.java | 5 +-
.../org/apache/phoenix/schema/PDataType.java | 108 ++++----
.../java/org/apache/phoenix/util/IndexUtil.java | 20 ++
.../org/apache/phoenix/util/PhoenixRuntime.java | 274 +++++++++++++++++++
.../org/apache/phoenix/util/SchemaUtil.java | 27 ++
.../phoenix/compile/QueryOptimizerTest.java | 264 ++++++++++++++++++
.../apache/phoenix/schema/ValueBitSetTest.java | 43 +++
.../phoenix/util/PhoenixEncodeDecodeTest.java | 72 +++++
.../apache/phoenix/util/PhoenixRuntimeTest.java | 77 +++++-
.../phoenix/pig/PhoenixHBaseLoaderIT.java | 7 +-
14 files changed, 935 insertions(+), 366 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
index d2dbda6..f44a517 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ArrayIT.java
@@ -43,7 +43,6 @@ import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.StringUtil;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -1220,13 +1219,8 @@ public class ArrayIT extends BaseClientManagedTimeIT {
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
assertTrue(rs.next());
- Double[] doubleArr = new Double[1];
- doubleArr[0] = 36.763;
- Array array = conn.createArrayOf("DOUBLE", doubleArr);
PhoenixArray resultArray = (PhoenixArray) rs.getArray(1);
- assertEquals(resultArray, array);
- Assert.fail("Should have failed");
- } catch (Exception e) {
+ assertNull(resultArray);
} finally {
conn.close();
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/it/java/org/apache/phoenix/end2end/PhoenixEncodeDecodeIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PhoenixEncodeDecodeIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/PhoenixEncodeDecodeIT.java
deleted file mode 100644
index bdb0745..0000000
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/PhoenixEncodeDecodeIT.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- *distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you maynot use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicablelaw or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.phoenix.end2end;
-
-import static org.junit.Assert.assertEquals;
-
-import java.sql.Connection;
-import java.sql.Date;
-import java.sql.DriverManager;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.util.Arrays;
-import java.util.Properties;
-
-import org.apache.phoenix.util.PhoenixRuntime;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-@Category(HBaseManagedTimeTest.class)
-public class PhoenixEncodeDecodeIT extends BaseHBaseManagedTimeIT {
-
- private static String tenantId = "ABC";
-
- @Test
- public void testEncodeDecode() throws Exception {
- Connection conn = DriverManager.getConnection(getUrl());
- conn.createStatement().execute(
- "CREATE TABLE t(org_id CHAR(3) not null, p_id CHAR(3) not null, date DATE not null, e_id CHAR(3) not null, old_value VARCHAR, new_value VARCHAR " +
- "CONSTRAINT pk PRIMARY KEY (org_id, p_id, date, e_id))");
- PreparedStatement stmt = conn.prepareStatement("UPSERT INTO t VALUES (?, ?, ?, ?, ?)");
- Date date = new Date(System.currentTimeMillis());
- stmt.setString(1, "abc");
- stmt.setString(2, "def");
- stmt.setDate(3, date);
- stmt.setString(4, "eid");
- stmt.setString(5, "old");
- stmt.executeUpdate();
- conn.commit();
-
- stmt = conn.prepareStatement("SELECT org_id, p_id, date, e_id FROM T");
-
- Object[] retrievedValues = new Object[4];
- ResultSet rs = stmt.executeQuery();
- rs.next();
- retrievedValues[0] = rs.getString(1);
- retrievedValues[1] = rs.getString(2);
- retrievedValues[2] = rs.getDate(3);
- retrievedValues[3] = rs.getString(4);
-
- byte[] value = PhoenixRuntime.encodePK(conn, "T", retrievedValues);
- Object[] decodedValues = PhoenixRuntime.decodePK(conn, "T", value);
-
- assertEquals(Arrays.asList(decodedValues), Arrays.asList(retrievedValues));
- }
-
- @Test
- public void testEncodeDecodeSalted() throws Exception {
- Connection conn = DriverManager.getConnection(getUrl());
- conn.createStatement().execute(
- "CREATE TABLE t(org_id CHAR(3) not null, p_id CHAR(3) not null, date DATE not null, e_id CHAR(3) not null, old_value VARCHAR, new_value VARCHAR " +
- "CONSTRAINT pk PRIMARY KEY (org_id, p_id, date, e_id)) SALT_BUCKETS = 2");
- PreparedStatement stmt = conn.prepareStatement("UPSERT INTO t VALUES (?, ?, ?, ?, ?)");
- Date date = new Date(System.currentTimeMillis());
- stmt.setString(1, "abc");
- stmt.setString(2, "def");
- stmt.setDate(3, date);
- stmt.setString(4, "eid");
- stmt.setString(5, "old");
- stmt.executeUpdate();
- conn.commit();
-
- stmt = conn.prepareStatement("SELECT org_id, p_id, date, e_id FROM T");
-
- Object[] retrievedValues = new Object[4];
- ResultSet rs = stmt.executeQuery();
- rs.next();
- retrievedValues[0] = rs.getString(1);
- retrievedValues[1] = rs.getString(2);
- retrievedValues[2] = rs.getDate(3);
- retrievedValues[3] = rs.getString(4);
-
- byte[] value = PhoenixRuntime.encodePK(conn, "T", retrievedValues);
- Object[] decodedValues = PhoenixRuntime.decodePK(conn, "T", value);
-
- assertEquals(Arrays.asList(decodedValues), Arrays.asList(retrievedValues));
- }
-
- @Test
- public void testEncodeDecodeMultiTenant() throws Exception {
- Connection globalConn = DriverManager.getConnection(getUrl());
- try {
- globalConn.createStatement().execute(
- "CREATE TABLE T(tenant_id CHAR(3) not null, p_id CHAR(3) not null, date DATE not null, e_id CHAR(3) not null, old_value VARCHAR, new_value VARCHAR " +
- "CONSTRAINT pk PRIMARY KEY (tenant_id, p_id, date, e_id)) MULTI_TENANT = true");
- } finally {
- globalConn.close();
- }
-
- Connection tenantConn = getTenantSpecificConnection();
-
- //create tenant-specific view.
- tenantConn.createStatement().execute("CREATE VIEW TENANT_TABLE AS SELECT * FROM T");
-
- PreparedStatement stmt = tenantConn.prepareStatement("UPSERT INTO TENANT_TABLE (p_id, date, e_id) VALUES (?, ?, ?)");
- Date date = new Date(System.currentTimeMillis());
- stmt.setString(1, "def");
- stmt.setDate(2, date);
- stmt.setString(3, "eid");
- stmt.executeUpdate();
- tenantConn.commit();
-
- stmt = tenantConn.prepareStatement("SELECT p_id, date, e_id FROM TENANT_TABLE");
-
- Object[] retrievedValues = new Object[3];
- ResultSet rs = stmt.executeQuery();
- rs.next();
- retrievedValues[0] = rs.getString(1);
- retrievedValues[1] = rs.getDate(2);
- retrievedValues[2] = rs.getString(3);
-
- byte[] value = PhoenixRuntime.encodePK(tenantConn, "TENANT_TABLE", retrievedValues);
- Object[] decodedValues = PhoenixRuntime.decodePK(tenantConn, "TENANT_TABLE", value);
-
- assertEquals(Arrays.asList(decodedValues), Arrays.asList(retrievedValues));
- }
-
- @Test
- public void testEncodeDecodeSaltedMultiTenant() throws Exception {
- Connection globalConn = DriverManager.getConnection(getUrl());
- try {
- globalConn.createStatement().execute(
- "CREATE TABLE T(tenant_id CHAR(3) not null, p_id CHAR(3) not null, date DATE not null, e_id CHAR(3) not null, old_value VARCHAR, new_value VARCHAR " +
- "CONSTRAINT pk PRIMARY KEY (tenant_id, p_id, date, e_id)) MULTI_TENANT = true, SALT_BUCKETS = 2");
- } finally {
- globalConn.close();
- }
-
- Connection tenantConn = getTenantSpecificConnection();
-
- //create tenant-specific view.
- tenantConn.createStatement().execute("CREATE VIEW TENANT_TABLE AS SELECT * FROM T");
-
- PreparedStatement stmt = tenantConn.prepareStatement("UPSERT INTO TENANT_TABLE (p_id, date, e_id) VALUES (?, ?, ?)");
- Date date = new Date(System.currentTimeMillis());
- stmt.setString(1, "def");
- stmt.setDate(2, date);
- stmt.setString(3, "eid");
- stmt.executeUpdate();
- tenantConn.commit();
-
- stmt = tenantConn.prepareStatement("SELECT p_id, date, e_id FROM TENANT_TABLE");
-
- Object[] retrievedValues = new Object[3];
- ResultSet rs = stmt.executeQuery();
- rs.next();
- retrievedValues[0] = rs.getString(1);
- retrievedValues[1] = rs.getDate(2);
- retrievedValues[2] = rs.getString(3);
-
- byte[] value = PhoenixRuntime.encodePK(tenantConn, "TENANT_TABLE", retrievedValues);
- Object[] decodedValues = PhoenixRuntime.decodePK(tenantConn, "TENANT_TABLE", value);
-
- assertEquals(Arrays.asList(decodedValues), Arrays.asList(retrievedValues));
- }
-
- @Test
- public void testEncodeDecodePaddingPks() throws Exception {
- Connection conn = DriverManager.getConnection(getUrl());
- conn.createStatement().execute(
- "CREATE TABLE T(pk1 CHAR(15) not null, pk2 CHAR(15) not null, v1 DATE " +
- "CONSTRAINT pk PRIMARY KEY (pk1, pk2))");
-
- PreparedStatement stmt = conn.prepareStatement("UPSERT INTO T (pk1, pk2, v1) VALUES (?, ?, ?)");
- stmt.setString(1, "def");
- stmt.setString(2, "eid");
- stmt.setDate(3, new Date(100));
- stmt.executeUpdate();
- conn.commit();
-
- stmt = conn.prepareStatement("SELECT pk1, pk2 FROM T");
-
- Object[] retrievedValues = new Object[2];
- ResultSet rs = stmt.executeQuery();
- rs.next();
- retrievedValues[0] = rs.getString(1);
- retrievedValues[1] = rs.getString(2);
-
- byte[] value = PhoenixRuntime.encodePK(conn, "T", retrievedValues);
- Object[] decodedValues = PhoenixRuntime.decodePK(conn, "T", value);
-
- assertEquals(Arrays.asList(decodedValues), Arrays.asList(retrievedValues));
- }
-
- private static Connection getTenantSpecificConnection() throws Exception {
- Properties props = new Properties();
- props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId);
- return DriverManager.getConnection(getUrl(), props);
- }
-
-}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryMoreIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryMoreIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryMoreIT.java
index 5173b0e..e82abbb 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryMoreIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryMoreIT.java
@@ -31,6 +31,7 @@ import java.util.Map;
import java.util.Properties;
import org.apache.hadoop.hbase.util.Base64;
+import org.apache.hadoop.hbase.util.Pair;
import org.apache.phoenix.util.PhoenixRuntime;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@@ -40,40 +41,41 @@ import com.google.common.collect.Lists;
@Category(HBaseManagedTimeTest.class)
public class QueryMoreIT extends BaseHBaseManagedTimeIT {
- //Data table - multi-tenant = true, salted = true
+ private String dataTableName;
+ //queryAgainstTenantSpecificView = true, dataTableSalted = true
@Test
public void testQueryMore1() throws Exception {
testQueryMore(true, true);
}
- //Data table - multi-tenant = false, salted = true
+ //queryAgainstTenantSpecificView = false, dataTableSalted = true
@Test
public void testQueryMore2() throws Exception {
testQueryMore(false, true);
}
- //Data table - multi-tenant = false, salted = false
+ //queryAgainstTenantSpecificView = false, dataTableSalted = false
@Test
public void testQueryMore3() throws Exception {
testQueryMore(false, false);
}
- //Data table - multi-tenant = true, salted = false
+ //queryAgainstTenantSpecificView = true, dataTableSalted = false
@Test
public void testQueryMore4() throws Exception {
testQueryMore(true, false);
}
- private void testQueryMore(boolean dataTableMultiTenant, boolean dataTableSalted) throws Exception {
+ private void testQueryMore(boolean queryAgainstTenantSpecificView, boolean dataTableSalted) throws Exception {
String[] tenantIds = new String[] {"00Dxxxxxtenant1", "00Dxxxxxtenant2", "00Dxxxxxtenant3"};
int numRowsPerTenant = 10;
String cursorTableName = "CURSOR_TABLE";
- String dataTableName = "BASE_HISTORY_TABLE" + (dataTableMultiTenant ? "_MULTI" : "") + (dataTableSalted ? "_SALTED" : "");
+ this.dataTableName = "BASE_HISTORY_TABLE" + (dataTableSalted ? "_SALTED" : "");
String cursorTableDDL = "CREATE TABLE IF NOT EXISTS " +
cursorTableName + " (\n" +
"TENANT_ID VARCHAR(15) NOT NULL\n," +
"QUERY_ID VARCHAR(15) NOT NULL,\n" +
- "CURSOR_ORDER BIGINT NOT NULL\n" +
+ "CURSOR_ORDER BIGINT NOT NULL \n" +
"CONSTRAINT CURSOR_TABLE_PK PRIMARY KEY (TENANT_ID, QUERY_ID, CURSOR_ORDER)) "+
"SALT_BUCKETS = 4, TTL=86400";
String baseDataTableDDL = "CREATE TABLE IF NOT EXISTS " +
@@ -86,7 +88,7 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
"OLDVAL_STRING VARCHAR,\n" +
"NEWVAL_STRING VARCHAR\n" +
"CONSTRAINT PK PRIMARY KEY(TENANT_ID, PARENT_ID, CREATED_DATE DESC, ENTITY_HISTORY_ID)) " +
- "VERSIONS = 1, MULTI_TENANT = true, SALT_BUCKETS = 4";
+ "VERSIONS = 1, MULTI_TENANT = true" + (dataTableSalted ? ", SALT_BUCKETS = 4" : "");
//create cursor and data tables.
Connection conn = DriverManager.getConnection(getUrl());
@@ -94,14 +96,36 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
conn.createStatement().execute(baseDataTableDDL);
conn.close();
- //upsert rows in the data table.
+ //upsert rows in the data table for all the tenantIds
Map<String, List<String>> historyIdsPerTenant = createHistoryTableRows(dataTableName, tenantIds, numRowsPerTenant);
+ // assert query more for tenantId -> tenantIds[0]
String tenantId = tenantIds[0];
String cursorQueryId = "00TcursrqueryId";
- String tenantViewName = dataTableMultiTenant ? ("HISTORY_TABLE" + "_" + tenantId) : null;
- assertEquals(numRowsPerTenant, upsertSelectRecordsInCursorTableForTenant(dataTableName, dataTableMultiTenant, tenantId, tenantViewName, cursorQueryId));
+ String tableOrViewName = queryAgainstTenantSpecificView ? ("\"HISTORY_TABLE" + "_" + tenantId + "\"") : dataTableName;
+ assertEquals(numRowsPerTenant, upsertSelectRecordsInCursorTableForTenant(tableOrViewName, queryAgainstTenantSpecificView, tenantId, cursorQueryId));
+
+ /*// assert that the data inserted in cursor table matches the data in the data table for tenantId.
+ String selectDataTable = "SELECT TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID FROM BASE_HISTORY_TABLE WHERE TENANT_ID = ? ";
+ String selectCursorTable = "SELECT TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID FROM CURSOR_TABLE (PARENT_ID CHAR(15), CREATED_DATE DATE, ENTITY_HISTORY_ID CHAR(15)) WHERE TENANT_ID = ? ";
+
+ PreparedStatement stmtData = DriverManager.getConnection(getUrl()).prepareStatement(selectDataTable);
+ stmtData.setString(1, tenantId);
+ ResultSet rsData = stmtData.executeQuery();
+
+ PreparedStatement stmtCursor = DriverManager.getConnection(getUrl()).prepareStatement(selectCursorTable);
+ stmtCursor.setString(1, tenantId);
+ ResultSet rsCursor = stmtCursor.executeQuery();
+
+ while(rsData.next() && rsCursor.next()) {
+ assertEquals(rsData.getString("TENANT_ID"), rsCursor.getString("TENANT_ID"));
+ assertEquals(rsData.getString("PARENT_ID"), rsCursor.getString("PARENT_ID"));
+ assertEquals(rsData.getDate("CREATED_DATE"), rsCursor.getDate("CREATED_DATE"));
+ assertEquals(rsData.getString("ENTITY_HISTORY_ID"), rsCursor.getString("ENTITY_HISTORY_ID"));
+ }
+
+ */
Connection conn2 = DriverManager.getConnection(getUrl());
ResultSet rs = conn2.createStatement().executeQuery("SELECT count(*) from " + cursorTableName);
rs.next();
@@ -110,20 +134,28 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
int startOrder = 0;
int endOrder = 5;
- int numRecordsThatShouldBeRetrieved = 5;
+ int numRecordsThatShouldBeRetrieved = numRowsPerTenant/2; // we will test for two rounds of query more.
- //get first batch of cursor ids out of the cursor table.
- String[] cursorIds = getRecordsOutofCursorTable(dataTableName, tenantId, cursorQueryId, startOrder, endOrder, numRecordsThatShouldBeRetrieved);
+ // get first batch of cursor ids out of the cursor table.
+ String[] cursorIds = getRecordsOutofCursorTable(tableOrViewName, queryAgainstTenantSpecificView, tenantId, cursorQueryId, startOrder, endOrder);
assertEquals(numRecordsThatShouldBeRetrieved, cursorIds.length);
-
- //now query against the tenant view and fetch first batch of records.
- List<String> historyIds = doQueryMore(dataTableName, dataTableMultiTenant, tenantId, tenantViewName, cursorIds);
+ // now query and fetch first batch of records.
+ List<String> historyIds = doQueryMore(queryAgainstTenantSpecificView, tenantId, tableOrViewName, cursorIds);
+ // assert that history ids match for this tenant
assertEquals(historyIdsPerTenant.get(tenantId).subList(startOrder, endOrder), historyIds);
- cursorIds = getRecordsOutofCursorTable(dataTableName, tenantId, cursorQueryId, startOrder + 5, endOrder + 5, numRecordsThatShouldBeRetrieved);
+ // get the next batch of cursor ids out of the cursor table.
+ cursorIds = getRecordsOutofCursorTable(tableOrViewName, queryAgainstTenantSpecificView, tenantId, cursorQueryId, startOrder + numRecordsThatShouldBeRetrieved, endOrder + numRecordsThatShouldBeRetrieved);
assertEquals(numRecordsThatShouldBeRetrieved, cursorIds.length);
- historyIds = doQueryMore(dataTableName, dataTableMultiTenant, tenantId, tenantViewName, cursorIds);
- assertEquals(historyIdsPerTenant.get(tenantId).subList(startOrder + 5, endOrder+ 5), historyIds);
+ // now query and fetch the next batch of records.
+ historyIds = doQueryMore(queryAgainstTenantSpecificView, tenantId, tableOrViewName, cursorIds);
+ // assert that the history ids match for this tenant
+ assertEquals(historyIdsPerTenant.get(tenantId).subList(startOrder + numRecordsThatShouldBeRetrieved, endOrder+ numRecordsThatShouldBeRetrieved), historyIds);
+
+ // get the next batch of cursor ids out of the cursor table.
+ cursorIds = getRecordsOutofCursorTable(tableOrViewName, queryAgainstTenantSpecificView, tenantId, cursorQueryId, startOrder + 2 * numRecordsThatShouldBeRetrieved, endOrder + 2 * numRecordsThatShouldBeRetrieved);
+ // assert that there are no more cursorids left for this tenant.
+ assertEquals(0, cursorIds.length);
}
private Map<String, List<String>> createHistoryTableRows(String dataTableName, String[] tenantIds, int numRowsPerTenant) throws Exception {
@@ -133,7 +165,7 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
try {
PreparedStatement stmt = conn.prepareStatement(upsertDML);
for (int j = 0; j < tenantIds.length; j++) {
- List<String> parentIds = new ArrayList<String>();
+ List<String> historyIds = new ArrayList<String>();
for (int i = 0; i < numRowsPerTenant; i++) {
stmt.setString(1, tenantIds[j]);
String parentId = "parentId" + i;
@@ -145,9 +177,9 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
stmt.setString(6, "oldval");
stmt.setString(7, "newval");
stmt.executeUpdate();
- parentIds.add(historyId);
+ historyIds.add(historyId);
}
- historyIdsForTenant.put(tenantIds[j], parentIds);
+ historyIdsForTenant.put(tenantIds[j], historyIds);
}
conn.commit();
return historyIdsForTenant;
@@ -156,29 +188,29 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
}
}
- private int upsertSelectRecordsInCursorTableForTenant(String baseTableName, boolean dataTableMultiTenant, String tenantId, String tenantViewName, String cursorQueryId) throws Exception {
+ private int upsertSelectRecordsInCursorTableForTenant(String tableOrViewName, boolean queryAgainstTenantView, String tenantId, String cursorQueryId) throws Exception {
String sequenceName = "\"" + tenantId + "_SEQ\"";
- Connection conn = dataTableMultiTenant ? getTenantSpecificConnection(tenantId) : DriverManager.getConnection(getUrl());
+ Connection conn = queryAgainstTenantView ? getTenantSpecificConnection(tenantId) : DriverManager.getConnection(getUrl());
// Create a sequence. This sequence is used to fill cursor_order column for each row inserted in the cursor table.
conn.createStatement().execute("CREATE SEQUENCE " + sequenceName + " CACHE " + Long.MAX_VALUE);
conn.setAutoCommit(true);
- if (dataTableMultiTenant) {
- createTenantSpecificViewIfNecessary(baseTableName, tenantViewName, conn);
+ if (queryAgainstTenantView) {
+ createTenantSpecificViewIfNecessary(tableOrViewName, conn);
}
try {
- String tableName = dataTableMultiTenant ? tenantViewName : baseTableName;
- String tenantIdFilter = dataTableMultiTenant ? "" : " WHERE TENANT_ID = ? ";
+ String tenantIdFilter = queryAgainstTenantView ? "" : " WHERE TENANT_ID = ? ";
// Using dynamic columns, we can use the same cursor table for storing primary keys for all the tables.
String upsertSelectDML = "UPSERT INTO CURSOR_TABLE " +
"(TENANT_ID, QUERY_ID, CURSOR_ORDER, PARENT_ID CHAR(15), CREATED_DATE DATE, ENTITY_HISTORY_ID CHAR(15)) " +
"SELECT ?, ?, NEXT VALUE FOR " + sequenceName + ", PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID " +
- " FROM " + tableName + tenantIdFilter;
+ " FROM " + tableOrViewName + tenantIdFilter;
+
PreparedStatement stmt = conn.prepareStatement(upsertSelectDML);
stmt.setString(1, tenantId);
stmt.setString(2, cursorQueryId);
- if (!dataTableMultiTenant) {
+ if (!queryAgainstTenantView) {
stmt.setString(3, tenantId);
}
int numRecords = stmt.executeUpdate();
@@ -198,18 +230,19 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
return DriverManager.getConnection(getUrl(), props);
}
- private String createTenantSpecificViewIfNecessary(String baseTableName, String tenantViewName, Connection tenantConn) throws Exception {
- tenantConn.createStatement().execute("CREATE VIEW IF NOT EXISTS " + tenantViewName + " AS SELECT * FROM " + baseTableName);
+ private String createTenantSpecificViewIfNecessary(String tenantViewName, Connection tenantConn) throws Exception {
+ tenantConn.createStatement().execute("CREATE VIEW IF NOT EXISTS " + tenantViewName + " AS SELECT * FROM " + dataTableName);
return tenantViewName;
}
- private String[] getRecordsOutofCursorTable(String dataTableName, String tenantId, String cursorQueryId, int startOrder, int endOrder, int numRecordsThatShouldBeRetrieved) throws Exception {
+ private String[] getRecordsOutofCursorTable(String tableOrViewName, boolean queryAgainstTenantSpecificView, String tenantId, String cursorQueryId, int startOrder, int endOrder) throws Exception {
Connection conn = DriverManager.getConnection(getUrl());
- List<String> pkIds = Lists.newArrayListWithCapacity(numRecordsThatShouldBeRetrieved);
-
- String selectCursorSql = "SELECT TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID " +
+ List<String> pkIds = new ArrayList<String>();
+ String cols = queryAgainstTenantSpecificView ? "PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID" : "TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID";
+ String dynCols = queryAgainstTenantSpecificView ? "(PARENT_ID CHAR(15), CREATED_DATE DATE, ENTITY_HISTORY_ID CHAR(15))" : "(TENANT_ID CHAR(15), PARENT_ID CHAR(15), CREATED_DATE DATE, ENTITY_HISTORY_ID CHAR(15))";
+ String selectCursorSql = "SELECT " + cols + " " +
"FROM CURSOR_TABLE \n" +
- "(TENANT_ID CHAR(15), PARENT_ID CHAR(15), CREATED_DATE DATE, ENTITY_HISTORY_ID CHAR(15)) \n" +
+ dynCols + " \n" +
"WHERE TENANT_ID = ? AND \n" +
"QUERY_ID = ? AND \n" +
"CURSOR_ORDER > ? AND \n" +
@@ -222,33 +255,34 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
stmt.setInt(4, endOrder);
ResultSet rs = stmt.executeQuery();
+ @SuppressWarnings("unchecked")
+ List<Pair<String, String>> columns = queryAgainstTenantSpecificView ? Lists.newArrayList(new Pair<String, String>(null, "PARENT_ID"), new Pair<String, String>(null, "CREATED_DATE"), new Pair<String, String>(null, "ENTITY_HISTORY_ID")) : Lists.newArrayList(new Pair<String, String>(null, "TENANT_ID"), new Pair<String, String>(null, "PARENT_ID"), new Pair<String, String>(null, "CREATED_DATE"), new Pair<String, String>(null, "ENTITY_HISTORY_ID"));
while(rs.next()) {
- Object[] values = new Object[4];
- for (int i = 0; i < 4; i++) {
+ Object[] values = new Object[columns.size()];
+ for (int i = 0; i < columns.size(); i++) {
values[i] = rs.getObject(i + 1);
}
- pkIds.add(Base64.encodeBytes(PhoenixRuntime.encodePK(conn, dataTableName, values)));
+ conn = getTenantSpecificConnection(tenantId);
+ pkIds.add(Base64.encodeBytes(PhoenixRuntime.encodeValues(conn, tableOrViewName, values, columns)));
}
return pkIds.toArray(new String[pkIds.size()]);
}
- private List<String> doQueryMore(String dataTableName, boolean dataTableMultiTenant, String tenantId, String tenantViewName, String[] cursorIds) throws Exception {
- Connection tenantConn = dataTableMultiTenant ? getTenantSpecificConnection(tenantId) : DriverManager.getConnection(getUrl());
- String tableName = dataTableMultiTenant ? tenantViewName : dataTableName;
+ private List<String> doQueryMore(boolean queryAgainstTenantView, String tenantId, String tenantViewName, String[] cursorIds) throws Exception {
+ Connection conn = queryAgainstTenantView ? getTenantSpecificConnection(tenantId) : DriverManager.getConnection(getUrl());
+ String tableName = queryAgainstTenantView ? tenantViewName : dataTableName;
+ @SuppressWarnings("unchecked")
+ List<Pair<String, String>> columns = queryAgainstTenantView ? Lists.newArrayList(new Pair<String, String>(null, "PARENT_ID"), new Pair<String, String>(null, "CREATED_DATE"), new Pair<String, String>(null, "ENTITY_HISTORY_ID")) : Lists.newArrayList(new Pair<String, String>(null, "TENANT_ID"), new Pair<String, String>(null, "PARENT_ID"), new Pair<String, String>(null, "CREATED_DATE"), new Pair<String, String>(null, "ENTITY_HISTORY_ID"));
StringBuilder sb = new StringBuilder();
- String where = dataTableMultiTenant ? " WHERE (PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID) IN " : " WHERE (TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID) IN ";
+ String where = queryAgainstTenantView ? " WHERE (PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID) IN " : " WHERE (TENANT_ID, PARENT_ID, CREATED_DATE, ENTITY_HISTORY_ID) IN ";
sb.append("SELECT ENTITY_HISTORY_ID FROM " + tableName + where);
- int numPkCols = dataTableMultiTenant ? 3 : 4;
+ int numPkCols = columns.size();
String query = addRvcInBinds(sb, cursorIds.length, numPkCols);
- PreparedStatement stmt = tenantConn.prepareStatement(query);
+ PreparedStatement stmt = conn.prepareStatement(query);
int bindCounter = 1;
for (int i = 0; i < cursorIds.length; i++) {
- Connection globalConn = DriverManager.getConnection(getUrl());
- Object[] pkParts = PhoenixRuntime.decodePK(globalConn, dataTableName, Base64.decode(cursorIds[i]));
- globalConn.close();
- //start at index 1 to ignore organizationId.
- int offset = dataTableMultiTenant ? 1 : 0;
- for (int j = offset; j < pkParts.length; j++) {
+ Object[] pkParts = PhoenixRuntime.decodeValues(conn, tableName, Base64.decode(cursorIds[i]), columns);
+ for (int j = 0; j < pkParts.length; j++) {
stmt.setObject(bindCounter++, pkParts[j]);
}
}
@@ -281,5 +315,4 @@ public class QueryMoreIT extends BaseHBaseManagedTimeIT {
sb.append(")");
return sb.toString();
}
-
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/it/java/org/apache/phoenix/end2end/StddevIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StddevIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StddevIT.java
index b4384f6..f3fef4b 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StddevIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StddevIT.java
@@ -17,7 +17,6 @@
*/
package org.apache.phoenix.end2end;
-import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -28,27 +27,20 @@ import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
-import java.util.Properties;
-import org.apache.phoenix.util.PhoenixRuntime;
-import org.apache.phoenix.util.PropertiesUtil;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-@Category(ClientManagedTimeTest.class)
-public class StddevIT extends BaseClientManagedTimeIT {
+@Category(HBaseManagedTimeTest.class)
+public class StddevIT extends BaseHBaseManagedTimeIT {
@Test
public void testSTDDEV_POP() throws Exception {
- long ts = nextTimestamp();
String tenantId = getOrganizationId();
- initATableValues(tenantId, getDefaultSplits(tenantId), null, ts);
+ initATableValues(tenantId, getDefaultSplits(tenantId), getUrl());
String query = "SELECT STDDEV_POP(A_INTEGER) FROM aTable";
- Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
- props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); // Execute at
- // timestamp 2
- Connection conn = DriverManager.getConnection(getUrl(), props);
+ Connection conn = DriverManager.getConnection(getUrl());
try {
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
@@ -64,16 +56,12 @@ public class StddevIT extends BaseClientManagedTimeIT {
@Test
public void testSTDDEV_SAMP() throws Exception {
- long ts = nextTimestamp();
String tenantId = getOrganizationId();
- initATableValues(tenantId, getDefaultSplits(tenantId), null, ts);
+ initATableValues(tenantId, getDefaultSplits(tenantId), getUrl());
String query = "SELECT STDDEV_SAMP(x_decimal) FROM aTable";
- Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
- props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); // Execute at
- // timestamp 2
- Connection conn = DriverManager.getConnection(getUrl(), props);
+ Connection conn = DriverManager.getConnection(getUrl());
try {
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
@@ -89,16 +77,12 @@ public class StddevIT extends BaseClientManagedTimeIT {
@Test
public void testSTDDEV_POPOnDecimalColType() throws Exception {
- long ts = nextTimestamp();
String tenantId = getOrganizationId();
- initATableValues(tenantId, getDefaultSplits(tenantId), null, ts);
+ initATableValues(tenantId, getDefaultSplits(tenantId), getUrl());
String query = "SELECT STDDEV_POP(x_decimal) FROM aTable";
- Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
- props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); // Execute at
- // timestamp 2
- Connection conn = DriverManager.getConnection(getUrl(), props);
+ Connection conn = DriverManager.getConnection(getUrl());
try {
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
@@ -114,16 +98,12 @@ public class StddevIT extends BaseClientManagedTimeIT {
@Test
public void testSTDDEV_SAMPOnDecimalColType() throws Exception {
- long ts = nextTimestamp();
String tenantId = getOrganizationId();
- initATableValues(tenantId, getDefaultSplits(tenantId), null, ts);
+ initATableValues(tenantId, getDefaultSplits(tenantId), getUrl());
String query = "SELECT STDDEV_SAMP(x_decimal) FROM aTable";
- Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
- props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 2)); // Execute at
- // timestamp 2
- Connection conn = DriverManager.getConnection(getUrl(), props);
+ Connection conn = DriverManager.getConnection(getUrl());
try {
PreparedStatement statement = conn.prepareStatement(query);
ResultSet rs = statement.executeQuery();
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/main/java/org/apache/phoenix/schema/KeyValueSchema.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/KeyValueSchema.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/KeyValueSchema.java
index b668f5f..d6c36c0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/KeyValueSchema.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/KeyValueSchema.java
@@ -22,7 +22,6 @@ import java.util.List;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.io.WritableUtils;
import org.apache.http.annotation.Immutable;
-
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.util.ByteUtil;
@@ -65,7 +64,7 @@ public class KeyValueSchema extends ValueSchema {
}
public KeyValueSchemaBuilder addField(PDatum datum) {
- super.addField(datum, fields.size() < this.minNullable, SortOrder.getDefault());
+ super.addField(datum, fields.size() >= this.minNullable, SortOrder.getDefault());
return this;
}
}
@@ -107,7 +106,7 @@ public class KeyValueSchema extends ValueSchema {
Field field = fields.get(i);
PDataType type = field.getDataType();
for (int j = 0; j < field.getCount(); j++) {
- if (expressions[index].evaluate(tuple, ptr)) { // Skip null values
+ if (expressions[index].evaluate(tuple, ptr) && ptr.getLength() > 0) { // Skip null values
if (index >= minNullableIndex) {
valueSet.set(index - minNullableIndex);
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
index 614eb6a..fa588b8 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PDataType.java
@@ -3402,7 +3402,7 @@ public enum PDataType {
return VARBINARY.getSampleValue(maxLength, arrayLength);
}
},
- INTEGER_ARRAY("INTEGER_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.INTEGER.getSqlType(), PhoenixArray.class, null) {
+ INTEGER_ARRAY("INTEGER ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.INTEGER.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3491,7 +3491,7 @@ public enum PDataType {
}
},
- BOOLEAN_ARRAY("BOOLEAN_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.BOOLEAN.getSqlType(), PhoenixArray.class, null) {
+ BOOLEAN_ARRAY("BOOLEAN ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.BOOLEAN.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3579,7 +3579,7 @@ public enum PDataType {
}
},
- VARCHAR_ARRAY("VARCHAR_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.VARCHAR.getSqlType(), PhoenixArray.class, null) {
+ VARCHAR_ARRAY("VARCHAR ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.VARCHAR.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3673,7 +3673,7 @@ public enum PDataType {
}
},
- VARBINARY_ARRAY("VARBINARY_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.VARBINARY.getSqlType(), PhoenixArray.class, null) {
+ VARBINARY_ARRAY("VARBINARY ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.VARBINARY.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3767,7 +3767,7 @@ public enum PDataType {
return pDataTypeForArray.getSampleValue(PDataType.VARBINARY, arrayLength, maxLength);
}
},
- BINARY_ARRAY("BINARY_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.BINARY.getSqlType(), PhoenixArray.class, null) {
+ BINARY_ARRAY("BINARY ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.BINARY.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3861,7 +3861,7 @@ public enum PDataType {
return pDataTypeForArray.getSampleValue(PDataType.BINARY, arrayLength, maxLength);
}
},
- CHAR_ARRAY("CHAR_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.CHAR.getSqlType(), PhoenixArray.class, null) {
+ CHAR_ARRAY("CHAR ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.CHAR.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -3956,7 +3956,7 @@ public enum PDataType {
}
},
- LONG_ARRAY("LONG_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.LONG.getSqlType(), PhoenixArray.class, null) {
+ LONG_ARRAY("BIGINT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.LONG.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4043,7 +4043,7 @@ public enum PDataType {
}
},
- SMALLINT_ARRAY("SMALLINT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.SMALLINT.getSqlType(), PhoenixArray.class, null) {
+ SMALLINT_ARRAY("SMALLINT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.SMALLINT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4130,7 +4130,7 @@ public enum PDataType {
}
},
- TINYINT_ARRAY("TINYINT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TINYINT.getSqlType(), PhoenixArray.class, null) {
+ TINYINT_ARRAY("TINYINT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TINYINT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4217,7 +4217,7 @@ public enum PDataType {
}
},
- FLOAT_ARRAY("FLOAT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.FLOAT.getSqlType(), PhoenixArray.class, null) {
+ FLOAT_ARRAY("FLOAT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.FLOAT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4305,7 +4305,7 @@ public enum PDataType {
}
},
- DOUBLE_ARRAY("DOUBLE_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DOUBLE.getSqlType(), PhoenixArray.class, null) {
+ DOUBLE_ARRAY("DOUBLE ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DOUBLE.getSqlType(), PhoenixArray.class, null) {
final PArrayDataType pDataTypeForArray = new PArrayDataType();
@Override
public boolean isArrayType() {
@@ -4394,7 +4394,7 @@ public enum PDataType {
},
- DECIMAL_ARRAY("DECIMAL_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DECIMAL.getSqlType(), PhoenixArray.class, null) {
+ DECIMAL_ARRAY("DECIMAL ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DECIMAL.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4489,8 +4489,7 @@ public enum PDataType {
}
},
- TIMESTAMP_ARRAY("TIMESTAMP_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TIMESTAMP.getSqlType(), PhoenixArray.class,
- null) {
+ TIMESTAMP_ARRAY("TIMESTAMP ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TIMESTAMP.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4577,8 +4576,7 @@ public enum PDataType {
}
},
- UNSIGNED_TIMESTAMP_ARRAY("UNSIGNED_TIMESTAMP_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TIMESTAMP.getSqlType(), PhoenixArray.class,
- null) {
+ UNSIGNED_TIMESTAMP_ARRAY("UNSIGNED_TIMESTAMP ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TIMESTAMP.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4665,7 +4663,7 @@ public enum PDataType {
}
},
- TIME_ARRAY("TIME_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TIME.getSqlType(), PhoenixArray.class, null) {
+ TIME_ARRAY("TIME ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.TIME.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4752,7 +4750,7 @@ public enum PDataType {
}
},
- UNSIGNED_TIME_ARRAY("UNSIGNED_TIME_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TIME.getSqlType(), PhoenixArray.class, null) {
+ UNSIGNED_TIME_ARRAY("UNSIGNED_TIME ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TIME.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4839,7 +4837,7 @@ public enum PDataType {
}
},
- DATE_ARRAY("DATE_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DATE.getSqlType(), PhoenixArray.class, null) {
+ DATE_ARRAY("DATE ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.DATE.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -4926,7 +4924,7 @@ public enum PDataType {
}
},
- UNSIGNED_DATE_ARRAY("UNSIGNED_DATE_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_DATE.getSqlType(), PhoenixArray.class, null) {
+ UNSIGNED_DATE_ARRAY("UNSIGNED_DATE ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_DATE.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5013,7 +5011,7 @@ public enum PDataType {
}
},
- UNSIGNED_LONG_ARRAY("UNSIGNED_LONG_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_LONG.getSqlType(), PhoenixArray.class, null) {
+ UNSIGNED_LONG_ARRAY("UNSIGNED_LONG ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_LONG.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5100,7 +5098,7 @@ public enum PDataType {
}
},
- UNSIGNED_INT_ARRAY("UNSIGNED_INT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_INT.getSqlType(), PhoenixArray.class, null) {
+ UNSIGNED_INT_ARRAY("UNSIGNED_INT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_INT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5187,8 +5185,7 @@ public enum PDataType {
}
},
- UNSIGNED_SMALLINT_ARRAY("UNSIGNED_SMALLINT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_SMALLINT.getSqlType(),
- PhoenixArray.class, null) {
+ UNSIGNED_SMALLINT_ARRAY("UNSIGNED_SMALLINT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_SMALLINT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5275,8 +5272,7 @@ public enum PDataType {
}
},
- UNSIGNED_TINYINT_ARRAY("UNSIGNED_TINYINT__ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TINYINT.getSqlType(), PhoenixArray.class,
- null) {
+ UNSIGNED_TINYINT_ARRAY("UNSIGNED_TINYINT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_TINYINT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5362,7 +5358,7 @@ public enum PDataType {
return pDataTypeForArray.getSampleValue(PDataType.UNSIGNED_TINYINT, arrayLength, maxLength);
}
},
- UNSIGNED_FLOAT_ARRAY("UNSIGNED_FLOAT_ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_FLOAT.getSqlType(), PhoenixArray.class, null) {
+ UNSIGNED_FLOAT_ARRAY("UNSIGNED_FLOAT ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_FLOAT.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5449,8 +5445,7 @@ public enum PDataType {
}
},
- UNSIGNED_DOUBLE_ARRAY("UNSIGNED_DOUBLE__ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_DOUBLE.getSqlType(), PhoenixArray.class,
- null) {
+ UNSIGNED_DOUBLE_ARRAY("UNSIGNED_DOUBLE ARRAY", PDataType.ARRAY_TYPE_BASE + PDataType.UNSIGNED_DOUBLE.getSqlType(), PhoenixArray.class, null) {
@Override
public boolean isArrayType() {
return true;
@@ -5551,6 +5546,28 @@ public enum PDataType {
private final PDataCodec codec;
final PArrayDataType pDataTypeForArray = new PArrayDataType();
+ private static final int SQL_TYPE_OFFSET;
+ private static final PDataType[] SQL_TYPE_TO_PCOLUMN_DATA_TYPE;
+ static {
+ int minSqlType = Integer.MAX_VALUE;
+ int maxSqlType = Integer.MIN_VALUE;
+ for (PDataType dataType : PDataType.values()) {
+ int sqlType = dataType.getSqlType();
+ if (sqlType < minSqlType) {
+ minSqlType = sqlType;
+ }
+ if (sqlType > maxSqlType) {
+ maxSqlType = sqlType;
+ }
+ }
+ SQL_TYPE_OFFSET = minSqlType;
+ SQL_TYPE_TO_PCOLUMN_DATA_TYPE = new PDataType[maxSqlType-minSqlType+1];
+ for (PDataType dataType : PDataType.values()) {
+ int sqlType = dataType.getSqlType();
+ SQL_TYPE_TO_PCOLUMN_DATA_TYPE[sqlType-SQL_TYPE_OFFSET] = dataType;
+ }
+ }
+
private PDataType(String sqlTypeName, int sqlType, Class clazz, PDataCodec codec) {
this.sqlTypeName = sqlTypeName;
this.sqlType = sqlType;
@@ -5559,7 +5576,7 @@ public enum PDataType {
this.sqlTypeNameBytes = Bytes.toBytes(sqlTypeName);
this.codec = codec;
}
-
+
public boolean isCastableTo(PDataType targetType) {
return isComparableTo(targetType);
}
@@ -6767,6 +6784,7 @@ public enum PDataType {
public final static Integer BYTE_PRECISION = 3;
public static final int ARRAY_TYPE_BASE = 3000;
+ public static final String ARRAY_TYPE_SUFFIX = "ARRAY";
private static final ThreadLocal<Random> RANDOM = new ThreadLocal<Random>(){
@Override
@@ -7232,30 +7250,7 @@ public enum PDataType {
return fromSqlTypeName.getSqlType() + PDataType.ARRAY_TYPE_BASE;
}
- private static final int SQL_TYPE_OFFSET;
- private static final PDataType[] SQL_TYPE_TO_PCOLUMN_DATA_TYPE;
- static {
- int minSqlType = Integer.MAX_VALUE;
- int maxSqlType = Integer.MIN_VALUE;
- for (PDataType dataType : PDataType.values()) {
- int sqlType = dataType.getSqlType();
- if (sqlType < minSqlType) {
- minSqlType = sqlType;
- }
- if (sqlType > maxSqlType) {
- maxSqlType = sqlType;
- }
- }
- SQL_TYPE_OFFSET = minSqlType;
- SQL_TYPE_TO_PCOLUMN_DATA_TYPE = new PDataType[maxSqlType-minSqlType+1];
- for (PDataType dataType : PDataType.values()) {
- int sqlType = dataType.getSqlType();
- SQL_TYPE_TO_PCOLUMN_DATA_TYPE[sqlType-SQL_TYPE_OFFSET] = dataType;
- }
- }
-
-
- private static interface PhoenixArrayFactory {
+ private static interface PhoenixArrayFactory {
PhoenixArray newArray(PDataType type, Object[] elements);
}
@@ -7402,4 +7397,9 @@ public enum PDataType {
public void pad(ImmutableBytesWritable ptr, Integer maxLength) {
}
+ public static PDataType arrayBaseType(PDataType arrayType) {
+ Preconditions.checkArgument(arrayType.isArrayType(), "Not a phoenix array type");
+ return fromTypeId(arrayType.getSqlType() - ARRAY_TYPE_BASE);
+ }
+
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
index 58709d8..80b8688 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.util;
import java.io.IOException;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,7 @@ import org.apache.phoenix.hbase.index.covered.update.ColumnReference;
import org.apache.phoenix.hbase.index.util.ImmutableBytesPtr;
import org.apache.phoenix.hbase.index.util.KeyValueBuilder;
import org.apache.phoenix.index.IndexMaintainer;
+import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.ColumnFamilyNotFoundException;
import org.apache.phoenix.schema.ColumnNotFoundException;
@@ -209,4 +211,22 @@ public class IndexUtil {
}
return false;
}
+
+ /**
+ * Return a list of {@code PColumn} for the associated data columns given the corresponding index columns. For a tenant
+ * specific view, the connection needs to be tenant specific too.
+ * @param dataTableName
+ * @param indexColumns
+ * @param conn
+ * @return
+ * @throws TableNotFoundException if table cannot be found in the connection's metdata cache
+ */
+ public static List<PColumn> getDataColumns(String dataTableName, List<PColumn> indexColumns, PhoenixConnection conn) throws SQLException {
+ PTable dataTable = PhoenixRuntime.getTable(conn, dataTableName);
+ List<PColumn> dataColumns = new ArrayList<PColumn>(indexColumns.size());
+ for (PColumn indexColumn : indexColumns) {
+ dataColumns.add(getDataColumn(dataTable, indexColumn.getName().getString()));
+ }
+ return dataColumns;
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
index 064ca62..36c3ede 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/PhoenixRuntime.java
@@ -17,13 +17,18 @@
*/
package org.apache.phoenix.util;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.phoenix.schema.PDataType.ARRAY_TYPE_SUFFIX;
+
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.sql.Connection;
import java.sql.DriverManager;
+import java.sql.PreparedStatement;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -31,6 +36,8 @@ import java.util.Properties;
import java.util.Set;
import java.util.TreeSet;
+import javax.annotation.Nullable;
+
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
@@ -42,21 +49,31 @@ import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.client.Mutation;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.compile.QueryPlan;
import org.apache.phoenix.coprocessor.MetaDataProtocol.MetaDataMutationResult;
import org.apache.phoenix.coprocessor.MetaDataProtocol.MutationCode;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.LiteralExpression;
+import org.apache.phoenix.expression.OrderByExpression;
import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.AmbiguousColumnException;
import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.KeyValueSchema;
import org.apache.phoenix.schema.MetaDataClient;
import org.apache.phoenix.schema.PColumn;
import org.apache.phoenix.schema.PColumnFamily;
import org.apache.phoenix.schema.PDataType;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.RowKeySchema;
import org.apache.phoenix.schema.TableNotFoundException;
+import org.apache.phoenix.schema.KeyValueSchema.KeyValueSchemaBuilder;
+import org.apache.phoenix.schema.ValueBitSet;
+import com.google.common.base.Preconditions;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
@@ -640,4 +657,261 @@ public class PhoenixRuntime {
return strict;
}
}
+
+ /**
+ * Returns the opitmized query plan used by phoenix for executing the sql.
+ * @param stmt to return the plan for
+ * @throws SQLException
+ */
+ public static QueryPlan getOptimizedQueryPlan(PreparedStatement stmt) throws SQLException {
+ checkNotNull(stmt);
+ QueryPlan plan = stmt.unwrap(PhoenixPreparedStatement.class).optimizeQuery();
+ return plan;
+ }
+
+ /**
+ * Whether or not the query plan has any order by expressions.
+ * @param plan
+ * @return
+ */
+ public static boolean hasOrderBy(QueryPlan plan) {
+ checkNotNull(plan);
+ List<OrderByExpression> orderBys = plan.getOrderBy().getOrderByExpressions();
+ return orderBys != null && !orderBys.isEmpty();
+ }
+
+ public static int getLimit(QueryPlan plan) {
+ checkNotNull(plan);
+ return plan.getLimit() == null ? 0 : plan.getLimit();
+ }
+
+ private static String addQuotes(String str) {
+ return str == null ? str : "\"" + str + "\"";
+ }
+ /**
+ *
+ * @param columns - Initialized empty list to be filled with the pairs of column family name and column name for columns that are used
+ * as row key for the query plan. Column family names are optional and hence the first part of the pair is nullable.
+ * Column names and family names are enclosed in double quotes to allow for case sensitivity and for presence of
+ * special characters. Salting column and view index id column are not included. If the connection is tenant specific
+ * and the table used by the query plan is multi-tenant, then the tenant id column is not included as well.
+ * @param plan - query plan to get info for.
+ * @param conn - connection used to generate the query plan. Caller should take care of closing the connection appropriately.
+ * @param forDataTable - if true, then family names and column names correspond to the data table even if the query plan uses
+ * the secondary index table. If false, and if the query plan uses the secondary index table, then the family names and column
+ * names correspond to the index table.
+ * @throws SQLException
+ */
+ public static void getPkColsForSql(List<Pair<String, String>> columns, QueryPlan plan, Connection conn, boolean forDataTable) throws SQLException {
+ checkNotNull(columns);
+ checkNotNull(plan);
+ checkNotNull(conn);
+ List<PColumn> pkColumns = getPkColumns(plan.getTableRef().getTable(), conn, forDataTable);
+ String columnName;
+ String familyName;
+ for (PColumn pCol : pkColumns ) {
+ columnName = addQuotes(pCol.getName().getString());
+ familyName = pCol.getFamilyName() != null ? addQuotes(pCol.getFamilyName().getString()) : null;
+ columns.add(new Pair<String, String>(familyName, columnName));
+ }
+ }
+
+ /**
+ * @param columns - Initialized empty list to be filled with the pairs of column family name and column name for columns that are used
+ * as row key for the query plan. Column family names are optional and hence the first part of the pair is nullable.
+ * Column names and family names are enclosed in double quotes to allow for case sensitivity and for presence of
+ * special characters. Salting column and view index id column are not included. If the connection is tenant specific
+ * and the table used by the query plan is multi-tenant, then the tenant id column is not included as well.
+ * @param datatypes - Initialized empty list to be filled with the corresponding data type for the columns in @param columns.
+ * @param plan - query plan to get info for
+ * @param conn - phoenix connection used to generate the query plan. Caller should take care of closing the connection appropriately.
+ * @param forDataTable - if true, then column names and data types correspond to the data table even if the query plan uses
+ * the secondary index table. If false, and if the query plan uses the secondary index table, then the column names and data
+ * types correspond to the index table.
+ * @throws SQLException
+ */
+ public static void getPkColsDataTypesForSql(List<Pair<String, String>> columns, List<String> dataTypes, QueryPlan plan, Connection conn, boolean forDataTable) throws SQLException {
+ checkNotNull(columns);
+ checkNotNull(dataTypes);
+ checkNotNull(plan);
+ checkNotNull(conn);
+ List<PColumn> pkColumns = getPkColumns(plan.getTableRef().getTable(), conn, forDataTable);
+ String columnName;
+ String familyName;
+ for (PColumn pCol : pkColumns) {
+ String sqlTypeName = getSqlTypeName(pCol);
+ dataTypes.add(sqlTypeName);
+ columnName = addQuotes(pCol.getName().getString());
+ familyName = pCol.getFamilyName() != null ? addQuotes(pCol.getFamilyName().getString()) : null;
+ columns.add(new Pair<String, String>(familyName, columnName));
+ }
+ }
+
+ /**
+ *
+ * @param pCol
+ * @return sql type name that could be used in DDL statements, dynamic column types etc.
+ */
+ public static String getSqlTypeName(PColumn pCol) {
+ PDataType dataType = pCol.getDataType();
+ Integer maxLength = pCol.getMaxLength();
+ Integer scale = pCol.getScale();
+ return dataType.isArrayType() ? getArraySqlTypeName(maxLength, scale, dataType) : appendMaxLengthAndScale(maxLength, scale, dataType.getSqlTypeName());
+ }
+
+ public static String getArraySqlTypeName(@Nullable Integer maxLength, @Nullable Integer scale, PDataType arrayType) {
+ String baseTypeSqlName = PDataType.arrayBaseType(arrayType).getSqlTypeName();
+ return appendMaxLengthAndScale(maxLength, scale, baseTypeSqlName) + " " + ARRAY_TYPE_SUFFIX; // for ex - decimal(10,2) ARRAY
+ }
+
+ private static String appendMaxLengthAndScale(@Nullable Integer maxLength, @Nullable Integer scale, String sqlTypeName) {
+ if (maxLength != null) {
+ sqlTypeName = sqlTypeName + "(" + maxLength;
+ if (scale != null) {
+ sqlTypeName = sqlTypeName + "," + scale; // has both max length and scale. For ex- decimal(10,2)
+ }
+ sqlTypeName = sqlTypeName + ")";
+ }
+ return sqlTypeName;
+ }
+
+ private static List<PColumn> getPkColumns(PTable ptable, Connection conn, boolean forDataTable) throws SQLException {
+ PhoenixConnection pConn = conn.unwrap(PhoenixConnection.class);
+ List<PColumn> pkColumns = ptable.getPKColumns();
+
+ // Skip the salting column and the view index id column if present.
+ // Skip the tenant id column too if the connection is tenant specific and the table used by the query plan is multi-tenant
+ int offset = (ptable.getBucketNum() == null ? 0 : 1) + (ptable.isMultiTenant() && pConn.getTenantId() != null ? 1 : 0) + (ptable.getViewIndexId() == null ? 0 : 1);
+
+ // get a sublist of pkColumns by skipping the offset columns.
+ pkColumns = pkColumns.subList(offset, pkColumns.size());
+
+ if (ptable.getType() == PTableType.INDEX && forDataTable) {
+ // index tables have the same schema name as their parent/data tables.
+ String fullDataTableName = ptable.getParentName().getString();
+
+ // Get the corresponding columns of the data table.
+ List<PColumn> dataColumns = IndexUtil.getDataColumns(fullDataTableName, pkColumns, pConn);
+ pkColumns = dataColumns;
+ }
+ return pkColumns;
+ }
+
+ /**
+ *
+ * @param conn connection that was used for reading/generating value.
+ * @param fullTableName fully qualified table name
+ * @param values values of the columns
+ * @param columns list of pair of column that includes column family as first part and column name as the second part.
+ * Column family is optional and hence nullable. Columns in the list have to be in the same order as the order of occurence
+ * of their values in the object array.
+ * @return values encoded in a byte array
+ * @throws SQLException
+ * @see {@link #decodeValues(Connection, String, byte[], List)}
+ */
+ public static byte[] encodeValues(Connection conn, String fullTableName, Object[] values, List<Pair<String, String>> columns) throws SQLException {
+ PTable table = getTable(conn, fullTableName);
+ List<PColumn> pColumns = getPColumns(table, columns);
+ List<Expression> expressions = new ArrayList<Expression>(pColumns.size());
+ int i = 0;
+ for (PColumn col : pColumns) {
+ Object value = values[i];
+ // for purposes of encoding, sort order of the columns doesn't matter.
+ Expression expr = LiteralExpression.newConstant(value, col.getDataType(), col.getMaxLength(), col.getScale());
+ expressions.add(expr);
+ i++;
+ }
+ KeyValueSchema kvSchema = buildKeyValueSchema(pColumns);
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable();
+ ValueBitSet valueSet = ValueBitSet.newInstance(kvSchema);
+ return kvSchema.toBytes(expressions.toArray(new Expression[0]), valueSet, ptr);
+ }
+
+
+ /**
+ *
+ * @param conn connection that was used for reading/generating value.
+ * @param fullTableName fully qualified table name
+ * @param value byte value of the columns concatenated as a single byte array. @see {@link #encodeValues(Connection, String, Object[], List)}
+ * @param columns list of column names for the columns that have their respective values
+ * present in the byte array. The column names should be in the same order as their values are in the byte array.
+ * The column name includes both family name, if present, and column name.
+ * @return decoded values for each column
+ * @throws SQLException
+ *
+ */
+ public static Object[] decodeValues(Connection conn, String fullTableName, byte[] value, List<Pair<String, String>> columns) throws SQLException {
+ PTable table = getTable(conn, fullTableName);
+ KeyValueSchema kvSchema = buildKeyValueSchema(getPColumns(table, columns));
+ ImmutableBytesWritable ptr = new ImmutableBytesWritable(value);
+ ValueBitSet valueSet = ValueBitSet.newInstance(kvSchema);
+ valueSet.clear();
+ valueSet.or(ptr);
+ int maxOffset = ptr.getOffset() + ptr.getLength();
+ Boolean hasValue;
+ kvSchema.iterator(ptr);
+ int i = 0;
+ List<Object> values = new ArrayList<Object>();
+ while(hasValue = kvSchema.next(ptr, i, maxOffset, valueSet) != null) {
+ if(hasValue) {
+ values.add(kvSchema.getField(i).getDataType().toObject(ptr));
+ }
+ i++;
+ }
+ return values.toArray();
+ }
+
+ private static KeyValueSchema buildKeyValueSchema(List<PColumn> columns) {
+ KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(getMinNullableIndex(columns));
+ for (PColumn col : columns) {
+ builder.addField(col);
+ }
+ return builder.build();
+ }
+
+ private static int getMinNullableIndex(List<PColumn> columns) {
+ int minNullableIndex = columns.size();
+ for (int i = 0; i < columns.size(); i++) {
+ if (columns.get(i).isNullable()) {
+ minNullableIndex = i;
+ break;
+ }
+ }
+ return minNullableIndex;
+ }
+
+ /**
+ * @param table table to get the {@code PColumn} for
+ * @param columns list of pair of column that includes column family as first part and column name as the second part.
+ * Column family is optional and hence nullable.
+ * @return list of {@code PColumn} for fullyQualifiedColumnNames
+ * @throws SQLException
+ */
+ private static List<PColumn> getPColumns(PTable table, List<Pair<String, String>> columns) throws SQLException {
+ List<PColumn> pColumns = new ArrayList<PColumn>(columns.size());
+ for (Pair<String, String> column : columns) {
+ pColumns.add(getPColumn(table, column.getFirst(), column.getSecond()));
+ }
+ return pColumns;
+ }
+
+ private static PColumn getPColumn(PTable table, @Nullable String familyName, String columnName) throws SQLException {
+ if (table==null) {
+ throw new SQLException("Table must not be null.");
+ }
+ if (columnName==null) {
+ throw new SQLException("columnName must not be null.");
+ }
+ // normalize and remove quotes from family and column names before looking up.
+ familyName = SchemaUtil.normalizeIdentifier(familyName);
+ columnName = SchemaUtil.normalizeIdentifier(columnName);
+ PColumn pColumn = null;
+ if (familyName != null) {
+ PColumnFamily family = table.getColumnFamily(familyName);
+ pColumn = family.getColumn(columnName);
+ } else {
+ pColumn = table.getColumn(columnName);
+ }
+ return pColumn;
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java
index 4fc78df..e5be16a 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/SchemaUtil.java
@@ -17,6 +17,8 @@
*/
package org.apache.phoenix.util;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES;
import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SYSTEM_STATS_NAME_BYTES;
@@ -28,6 +30,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
+import javax.annotation.Nullable;
+
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.exception.SQLExceptionCode;
@@ -54,6 +58,7 @@ import org.apache.phoenix.schema.SortOrder;
import org.apache.phoenix.schema.ValueSchema.Field;
import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
@@ -611,4 +616,26 @@ public class SchemaUtil {
Preconditions.checkNotNull(argument,"Argument passed cannot be null");
return ESCAPE_CHARACTER + argument + ESCAPE_CHARACTER;
}
+
+ /**
+ *
+ * @return a fully qualified column name in the format: "CFNAME"."COLNAME" or "COLNAME" depending on whether or not
+ * there is a column family name present.
+ */
+ public static String getQuotedFullColumnName(PColumn pCol) {
+ checkNotNull(pCol);
+ String columnName = pCol.getName().getString();
+ String columnFamilyName = pCol.getFamilyName() != null ? pCol.getFamilyName().getString() : null;
+ return getQuotedFullColumnName(columnFamilyName, columnName);
+ }
+
+ /**
+ *
+ * @return a fully qualified column name in the format: "CFNAME"."COLNAME" or "COLNAME" depending on whether or not
+ * there is a column family name present.
+ */
+ public static String getQuotedFullColumnName(@Nullable String columnFamilyName, String columnName) {
+ checkArgument(!Strings.isNullOrEmpty(columnName), "Column name cannot be null or empty");
+ return columnFamilyName == null ? ("\"" + columnName + "\"") : ("\"" + columnFamilyName + "\"" + QueryConstants.NAME_SEPARATOR + "\"" + columnName + "\"");
+ }
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/878570d0/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
index 45a61a7..81f4a45 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
@@ -20,15 +20,31 @@ package org.apache.phoenix.compile;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import java.sql.Array;
import java.sql.Connection;
+import java.sql.Date;
import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+import org.apache.hadoop.hbase.util.Pair;
import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
import org.apache.phoenix.jdbc.PhoenixStatement;
import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.SchemaUtil;
+import org.junit.Ignore;
import org.junit.Test;
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+
public class QueryOptimizerTest extends BaseConnectionlessQueryTest {
public static final String SCHEMA_NAME = "";
@@ -306,4 +322,252 @@ public class QueryOptimizerTest extends BaseConnectionlessQueryTest {
QueryPlan plan = stmt.optimizeQuery(query);
assertEquals("T", plan.getTableRef().getTable().getTableName().getString());
}
+
+ @Test
+ // Multi-tenant = false; Query uses index = false; Salted = true
+ public void testAssertQueryPlanDetails1() throws Exception {
+ testAssertQueryPlanDetails(false, false, true);
+ }
+
+ @Test
+ // Multi-tenant = true; Query uses index = false; Salted = true
+ public void testAssertQueryPlanDetails2() throws Exception {
+ testAssertQueryPlanDetails(true, false, true);
+ }
+
+ @Test
+ @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+ // Multi-tenant = true; Query uses index = true; Salted = false
+ public void testAssertQueryPlanDetails3() throws Exception {
+ testAssertQueryPlanDetails(true, true, true);
+ }
+
+ @Test
+ // Multi-tenant = false; Query uses index = true; Salted = true
+ public void testAssertQueryPlanDetails4() throws Exception {
+ testAssertQueryPlanDetails(false, true, true);
+ }
+
+ @Test
+ // Multi-tenant = false; Query uses index = false; Salted = false
+ public void testAssertQueryPlanDetails5() throws Exception {
+ testAssertQueryPlanDetails(false, false, false);
+ }
+
+ @Test
+ // Multi-tenant = true; Query uses index = false; Salted = false
+ public void testAssertQueryPlanDetails6() throws Exception {
+ testAssertQueryPlanDetails(true, false, false);
+ }
+
+ @Test
+ @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+ // Multi-tenant = true; Query uses index = true; Salted = false
+ public void testAssertQueryPlanDetails7() throws Exception {
+ testAssertQueryPlanDetails(true, true, false);
+ }
+
+ @Test
+ // Multi-tenant = false; Query uses index = true; Salted = false
+ public void testAssertQueryPlanDetails8() throws Exception {
+ testAssertQueryPlanDetails(false, true, false);
+ }
+
+ private void testAssertQueryPlanDetails(boolean multitenant, boolean useIndex, boolean salted) throws Exception {
+ String sql;
+ PreparedStatement stmt;
+ Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+ try {
+ // create table
+ conn.createStatement().execute("create table "
+ + "XYZ.ABC"
+ + " (organization_id char(15) not null, \n"
+ + " dec DECIMAL(10,2) not null,\n"
+ + " a_string_array varchar(100) array[] not null,\n"
+ + " b_string varchar(100),\n"
+ + " CF.a_integer integer,\n"
+ + " a_date date,\n"
+ + " CONSTRAINT pk PRIMARY KEY (organization_id, dec, a_string_array)\n"
+ + ")" + (salted ? "SALT_BUCKETS=4" : "") + (multitenant == true ? (salted ? ",MULTI_TENANT=true" : "MULTI_TENANT=true") : ""));
+
+
+ if (useIndex) {
+ // create index
+ conn.createStatement().execute("CREATE INDEX ABC_IDX ON XYZ.ABC (CF.a_integer) INCLUDE (a_date)");
+ }
+
+ // switch to a tenant specific connection if multi-tenant.
+ conn = multitenant ? DriverManager.getConnection(getUrl("tenantId")) : conn;
+
+ // create a tenant specific view if multi-tenant
+ if (multitenant) {
+ conn.createStatement().execute("CREATE VIEW ABC_VIEW (ORGANIZATION_ID VARCHAR) AS SELECT * FROM XYZ.ABC");
+ }
+
+ String expectedColNames = multitenant ? addQuotes(null, "DEC,A_STRING_ARRAY") : addQuotes(null,"ORGANIZATION_ID,DEC,A_STRING_ARRAY");
+ String expectedColumnNameDataTypes = multitenant ? "\"DEC\" DECIMAL(10,2),\"A_STRING_ARRAY\" VARCHAR(100) ARRAY" : "\"ORGANIZATION_ID\" CHAR(15),\"DEC\" DECIMAL(10,2),\"A_STRING_ARRAY\" VARCHAR(100) ARRAY";
+ String tableName = multitenant ? "ABC_VIEW" : "XYZ.ABC";
+ String tenantFilter = multitenant ? "" : "organization_id = ? AND ";
+ String orderByRowKeyClause = multitenant ? "dec" : "organization_id";
+
+ // Filter on row key columns of data table. No order by. No limit.
+ sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ?";
+ stmt = conn.prepareStatement(sql);
+ int counter = 1;
+ if (!multitenant) {
+ stmt.setString(counter++, "ORGID");
+ }
+ stmt.setDouble(counter++, 1.23);
+ String[] strArray = new String[2];
+ strArray[0] = "AB";
+ strArray[1] = "CD";
+ Array array = conn.createArrayOf("VARCHAR", strArray);
+ stmt.setArray(counter++, array);
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 0);
+
+ counter = 1;
+ // Filter on row key columns of data table. Order by row key columns. Limit specified.
+ sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ? ORDER BY " + orderByRowKeyClause + " LIMIT 100";
+ stmt = conn.prepareStatement(sql);
+ if (!multitenant) {
+ stmt.setString(counter++, "ORGID");
+ }
+ stmt.setDouble(counter++, 1.23);
+ array = conn.createArrayOf("VARCHAR", strArray);
+ stmt.setArray(counter++, array);
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 100);
+
+ counter = 1;
+ // Filter on row key columns of data table. Order by non-row key columns. Limit specified.
+ sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ? ORDER BY a_date LIMIT 100";
+ stmt = conn.prepareStatement(sql);
+ if (!multitenant) {
+ stmt.setString(counter++, "ORGID");
+ }
+ stmt.setDouble(counter++, 1.23);
+ array = conn.createArrayOf("VARCHAR", strArray);
+ stmt.setArray(counter++, array);
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, true, 100);
+
+ if (useIndex) {
+
+ expectedColNames = multitenant ? ("\"CF\".\"A_INTEGER\"" + ",\"DEC\"" + ",\"A_STRING_ARRAY\"") : ("\"CF\".\"A_INTEGER\"" + ",\"ORGANIZATION_ID\"" + ",\"DEC\"" + ",\"A_STRING_ARRAY\"");
+ expectedColumnNameDataTypes = multitenant ? ("\"CF\".\"A_INTEGER\"" + " " + "INTEGER" + ",\"DEC\"" + " " + "DECIMAL(10,2)" + ",\"A_STRING_ARRAY\""+ " " + "VARCHAR(100) ARRAY") : ("\"CF\".\"A_INTEGER\"" + " " + "INTEGER" + ",\"ORGANIZATION_ID\"" + " " + "CHAR(15)" + ",\"DEC\"" + " " + "DECIMAL(10,2)" + ",\"A_STRING_ARRAY\""+ " " + "VARCHAR(100) ARRAY");
+
+ // Filter on columns that the secondary index is on. No order by. No limit.
+ sql = "SELECT a_date FROM " + tableName + " where CF.a_integer = ?";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, 1000);
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 0);
+
+ // Filter on columns that the secondary index is on. Order by on the indexed column. Limit specified.
+ sql = "SELECT a_date FROM " + tableName + " where CF.a_integer = ? ORDER BY CF.a_integer LIMIT 100";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, 1000);
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 100);
+
+ // Filter on columns that the secondary index is on. Order by on the non-indexed column. Limit specified.
+ sql = "SELECT a_integer FROM " + tableName + " where CF.a_integer = ? and a_date = ? ORDER BY a_date LIMIT 100";
+ stmt = conn.prepareStatement(sql);
+ stmt.setInt(1, 1000);
+ stmt.setDate(2, new Date(909000));
+ assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, true, 100);
+ }
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Test
+ @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+ public void testAssertQueryAgainstTenantSpecificViewGoesThroughIndex() throws Exception {
+ Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+
+ // create table
+ conn.createStatement().execute("create table "
+ + "XYZ.ABC"
+ + " (organization_id char(15) not null, \n"
+ + " entity_id char(15) not null,\n"
+ + " a_string_array varchar(100) array[] not null,\n"
+ + " b_string varchar(100),\n"
+ + " a_string varchar,\n"
+ + " a_date date,\n"
+ + " CONSTRAINT pk PRIMARY KEY (organization_id, entity_id, a_string_array)\n"
+ + ")" + "MULTI_TENANT=true");
+
+
+ // create index
+ conn.createStatement().execute("CREATE INDEX ABC_IDX ON XYZ.ABC (a_string) INCLUDE (a_date)");
+
+ conn.close();
+
+ // switch to a tenant specific connection
+ conn = DriverManager.getConnection(getUrl("tenantId"));
+
+ // create a tenant specific view
+ conn.createStatement().execute("CREATE VIEW ABC_VIEW AS SELECT * FROM XYZ.ABC");
+
+ // query against the tenant specific view
+ String sql = "SELECT a_date FROM ABC_VIEW where a_string = ?";
+ PreparedStatement stmt = conn.prepareStatement(sql);
+ stmt.setString(1, "1000");
+ QueryPlan plan = stmt.unwrap(PhoenixPreparedStatement.class).optimizeQuery();
+ assertEquals("Query should use index", PTableType.INDEX, plan.getTableRef().getTable().getType());
+
+ }
+
+ private void assertPlanDetails(PreparedStatement stmt, String expectedPkCols, String expectedPkColsDataTypes, boolean expectedHasOrderBy, int expectedLimit) throws SQLException {
+ Connection conn = stmt.getConnection();
+ QueryPlan plan = PhoenixRuntime.getOptimizedQueryPlan(stmt);
+
+ List<Pair<String, String>> columns = new ArrayList<Pair<String, String>>();
+ PhoenixRuntime.getPkColsForSql(columns, plan, conn, true);
+ assertEquals(expectedPkCols, Joiner.on(",").join(getColumnNames(columns)));
+ List<String> dataTypes = new ArrayList<String>();
+ columns = new ArrayList<Pair<String,String>>();
+ PhoenixRuntime.getPkColsDataTypesForSql(columns, dataTypes, plan, conn, true);
+
+ assertEquals(expectedPkColsDataTypes, appendColNamesDataTypes(columns, dataTypes));
+ assertEquals(expectedHasOrderBy, PhoenixRuntime.hasOrderBy(plan));
+ assertEquals(expectedLimit, PhoenixRuntime.getLimit(plan));
+ }
+
+ private static List<String> getColumnNames(List<Pair<String, String>> columns) {
+ List<String> columnNames = new ArrayList<String>(columns.size());
+ for (Pair<String, String> col : columns) {
+ String familyName = col.getFirst();
+ String columnName = col.getSecond();
+ if (familyName != null) {
+ columnName = familyName + QueryConstants.NAME_SEPARATOR + columnName;
+ }
+ columnNames.add(columnName);
+ }
+ return columnNames;
+ }
+
+ private String addQuotes(String familyName, String columnNames) {
+ Iterable<String> columnNamesList = Splitter.on(",").split(columnNames);
+ List<String> quotedColumnNames = new ArrayList<String>();
+ for (String columnName : columnNamesList) {
+ String quotedColumnName = SchemaUtil.getQuotedFullColumnName(familyName, columnName);
+ quotedColumnNames.add(quotedColumnName);
+ }
+ return Joiner.on(",").join(quotedColumnNames);
+ }
+
+ private String appendColNamesDataTypes(List<Pair<String, String>> columns, List<String> dataTypes) {
+ int size = columns.size();
+ assertEquals(size, dataTypes.size()); // they will be equal, but what the heck?
+ List<String> pkColsDataTypes = new ArrayList<String>(size);
+ for (int i = 0; i < size; i++) {
+ String familyName = columns.get(i).getFirst();
+ String columnName = columns.get(i).getSecond();
+ if (familyName != null) {
+ columnName = familyName + QueryConstants.NAME_SEPARATOR + columnName;
+ }
+ pkColsDataTypes.add(columnName + " " + dataTypes.get(i));
+ }
+ return Joiner.on(",").join(pkColsDataTypes);
+ }
+
}
\ No newline at end of file
[4/4] git commit: PHOENIX-973 Lexer skips unexpected characters
Posted by ja...@apache.org.
PHOENIX-973 Lexer skips unexpected characters
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/ef062ad2
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/ef062ad2
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/ef062ad2
Branch: refs/heads/3.0
Commit: ef062ad250fc6203cf613dea7417160a68efabd4
Parents: cf07a5d
Author: James Taylor <jt...@salesforce.com>
Authored: Fri Oct 17 18:12:15 2014 -0700
Committer: James Taylor <jt...@salesforce.com>
Committed: Fri Oct 17 18:44:58 2014 -0700
----------------------------------------------------------------------
phoenix-core/src/main/antlr3/PhoenixSQL.g | 13 ++-
.../query/ConnectionQueryServicesImpl.java | 2 +-
.../org/apache/phoenix/schema/SequenceKey.java | 4 +-
.../org/apache/phoenix/util/MetaDataUtil.java | 14 +--
.../org/apache/phoenix/util/UpgradeUtil.java | 95 ++++++++++++--------
.../apache/phoenix/parse/QueryParserTest.java | 16 +++-
.../java/org/apache/phoenix/query/BaseTest.java | 6 +-
7 files changed, 96 insertions(+), 54 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/main/antlr3/PhoenixSQL.g
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/antlr3/PhoenixSQL.g b/phoenix-core/src/main/antlr3/PhoenixSQL.g
index 48049c9..4a3a8d8 100644
--- a/phoenix-core/src/main/antlr3/PhoenixSQL.g
+++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g
@@ -950,13 +950,12 @@ SL_COMMENT2: '--';
// Bind names start with a colon and followed by 1 or more letter/digit/underscores
BIND_NAME
- : COLON (LETTER|DIGIT|'_')+
+ : COLON (DIGIT)+
;
-// Valid names can have a single underscore, but not multiple
-// Turn back on literal testing, all names are literals.
+
NAME
- : LETTER (FIELDCHAR)* ('\"' (DBL_QUOTE_CHAR)* '\"')?
+ : LETTER (FIELDCHAR)*
| '\"' (DBL_QUOTE_CHAR)* '\"'
;
@@ -1174,4 +1173,10 @@ SL_COMMENT
DOT
: '.'
;
+
+OTHER
+ : . { if (true) // to prevent compile error
+ throw new RuntimeException("Unexpected char: '" + $text + "'"); }
+ ;
+
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 688cf42..edeb206 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -1348,7 +1348,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
} catch (TableAlreadyExistsException e) {
// This will occur if we have an older SYSTEM.SEQUENCE, so we need to update it to include
// any new columns we've added.
- if (UpgradeUtil.addSaltByteToSequenceTable(metaConnection, nSaltBuckets)) {
+ if (UpgradeUtil.upgradeSequenceTable(metaConnection, nSaltBuckets)) {
metaConnection.removeTable(null,
PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA,
PhoenixDatabaseMetaData.TYPE_SEQUENCE,
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/main/java/org/apache/phoenix/schema/SequenceKey.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/SequenceKey.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/SequenceKey.java
index 94ca549..6f82630 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/SequenceKey.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/SequenceKey.java
@@ -32,9 +32,9 @@ public class SequenceKey implements Comparable<SequenceKey> {
this.tenantId = tenantId;
this.schemaName = schemaName;
this.sequenceName = sequenceName;
- this.key = ByteUtil.concat(nBuckets <= 0 ? ByteUtil.EMPTY_BYTE_ARRAY : QueryConstants.SEPARATOR_BYTE_ARRAY, tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(tenantId), QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(schemaName), QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes(sequenceName));
+ this.key = ByteUtil.concat((nBuckets <= 0 ? ByteUtil.EMPTY_BYTE_ARRAY : QueryConstants.SEPARATOR_BYTE_ARRAY), tenantId == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(tenantId), QueryConstants.SEPARATOR_BYTE_ARRAY, schemaName == null ? ByteUtil.EMPTY_BYTE_ARRAY : Bytes.toBytes(schemaName), QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes(sequenceName));
if (nBuckets > 0) {
- key[0] = SaltingUtil.getSaltingByte(key, SaltingUtil.NUM_SALTING_BYTES, key.length - SaltingUtil.NUM_SALTING_BYTES, SaltingUtil.MAX_BUCKET_NUM);
+ key[0] = SaltingUtil.getSaltingByte(key, SaltingUtil.NUM_SALTING_BYTES, key.length - SaltingUtil.NUM_SALTING_BYTES, nBuckets);
}
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
index b7d6d98..608bfc2 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
@@ -61,6 +61,7 @@ public class MetaDataUtil {
public static final String VIEW_INDEX_TABLE_PREFIX = "_IDX_";
public static final byte[] VIEW_INDEX_TABLE_PREFIX_BYTES = Bytes.toBytes(VIEW_INDEX_TABLE_PREFIX);
public static final String VIEW_INDEX_SEQUENCE_PREFIX = "_SEQ_";
+ public static final String VIEW_INDEX_SEQUENCE_NAME_PREFIX = "_ID_";
public static final byte[] VIEW_INDEX_SEQUENCE_PREFIX_BYTES = Bytes.toBytes(VIEW_INDEX_SEQUENCE_PREFIX);
public static final String VIEW_INDEX_ID_COLUMN_NAME = "_INDEX_ID";
@@ -260,13 +261,17 @@ public class MetaDataUtil {
}
+ public static String getViewIndexSchemaName(PName physicalName) {
+ return VIEW_INDEX_SEQUENCE_PREFIX + physicalName.getString();
+ }
+
public static SequenceKey getViewIndexSequenceKey(String tenantId, PName physicalName, int nSaltBuckets) {
// Create global sequence of the form: <prefixed base table name><tenant id>
// rather than tenant-specific sequence, as it makes it much easier
// to cleanup when the physical table is dropped, as we can delete
// all global sequences leading with <prefix> + physical name.
- String schemaName = VIEW_INDEX_SEQUENCE_PREFIX + physicalName.getString();
- String tableName = tenantId == null ? "" : tenantId;
+ String schemaName = getViewIndexSchemaName(physicalName);
+ String tableName = VIEW_INDEX_SEQUENCE_NAME_PREFIX + (tenantId == null ? "" : tenantId);
return new SequenceKey(null, schemaName, tableName, nSaltBuckets);
}
@@ -297,11 +302,10 @@ public class MetaDataUtil {
}
public static void deleteViewIndexSequences(PhoenixConnection connection, PName name) throws SQLException {
- int nSequenceSaltBuckets = connection.getQueryServices().getSequenceSaltBuckets();
- SequenceKey key = getViewIndexSequenceKey(null, name, nSequenceSaltBuckets);
+ String schemaName = getViewIndexSchemaName(name);
connection.createStatement().executeUpdate("DELETE FROM " + PhoenixDatabaseMetaData.SEQUENCE_FULLNAME_ESCAPED +
" WHERE " + PhoenixDatabaseMetaData.TENANT_ID + " IS NULL AND " +
- PhoenixDatabaseMetaData.SEQUENCE_SCHEMA + " = '" + key.getSchemaName() + "'");
+ PhoenixDatabaseMetaData.SEQUENCE_SCHEMA + " = '" + schemaName + "'");
}
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
index 3054200..b51b455 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/UpgradeUtil.java
@@ -29,10 +29,14 @@ import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
+import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.coprocessor.MetaDataProtocol;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
+import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PName;
+import org.apache.phoenix.schema.PNameFactory;
import org.apache.phoenix.schema.SaltingUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -41,15 +45,13 @@ import com.google.common.collect.Lists;
public class UpgradeUtil {
private static final Logger logger = LoggerFactory.getLogger(UpgradeUtil.class);
+ private static final byte[] SEQ_PREFIX_BYTES = ByteUtil.concat(QueryConstants.SEPARATOR_BYTE_ARRAY, Bytes.toBytes("_SEQ_"));
private UpgradeUtil() {
}
- public static boolean addSaltByteToSequenceTable(PhoenixConnection conn, int nSaltBuckets) throws SQLException {
- if (nSaltBuckets <= 0) {
- logger.info("Not upgrading SYSTEM.SEQUENCE table because SALT_BUCKETS is zero");
- return false;
- }
+ @SuppressWarnings("deprecation")
+ public static boolean upgradeSequenceTable(PhoenixConnection conn, int nSaltBuckets) throws SQLException {
logger.info("Upgrading SYSTEM.SEQUENCE table");
byte[] seqTableKey = SchemaUtil.getTableKey(null, PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA, PhoenixDatabaseMetaData.TYPE_SEQUENCE);
@@ -89,31 +91,33 @@ public class UpgradeUtil {
Result result;
while ((result = scanner.next()) != null) {
for (KeyValue keyValue : result.raw()) {
- KeyValue newKeyValue = addSaltByte(keyValue);
- sizeBytes += newKeyValue.getLength();
- if (KeyValue.Type.codeToType(newKeyValue.getType()) == KeyValue.Type.Put) {
- // Delete old value
- byte[] buf = keyValue.getBuffer();
- Delete delete = new Delete(keyValue.getRow());
- KeyValue deleteKeyValue = new KeyValue(buf, keyValue.getRowOffset(), keyValue.getRowLength(),
- buf, keyValue.getFamilyOffset(), keyValue.getFamilyLength(),
- buf, keyValue.getQualifierOffset(), keyValue.getQualifierLength(),
- keyValue.getTimestamp(), KeyValue.Type.Delete,
- ByteUtil.EMPTY_BYTE_ARRAY,0,0);
- delete.addDeleteMarker(deleteKeyValue);
- mutations.add(delete);
- sizeBytes += deleteKeyValue.getLength();
- // Put new value
- Put put = new Put(newKeyValue.getRow());
- put.add(newKeyValue);
- mutations.add(put);
- } else if (KeyValue.Type.codeToType(newKeyValue.getType()) == KeyValue.Type.Delete){
- // Copy delete marker using new key so that it continues
- // to delete the key value preceding it that will be updated
- // as well.
- Delete delete = new Delete(newKeyValue.getRow());
- delete.addDeleteMarker(newKeyValue);
- mutations.add(delete);
+ KeyValue newKeyValue = addSaltByte(keyValue, nSaltBuckets);
+ if (newKeyValue != null) {
+ sizeBytes += newKeyValue.getLength();
+ if (KeyValue.Type.codeToType(newKeyValue.getType()) == KeyValue.Type.Put) {
+ // Delete old value
+ byte[] buf = keyValue.getBuffer();
+ Delete delete = new Delete(keyValue.getRow());
+ KeyValue deleteKeyValue = new KeyValue(buf, keyValue.getRowOffset(), keyValue.getRowLength(),
+ buf, keyValue.getFamilyOffset(), keyValue.getFamilyLength(),
+ buf, keyValue.getQualifierOffset(), keyValue.getQualifierLength(),
+ keyValue.getTimestamp(), KeyValue.Type.Delete,
+ ByteUtil.EMPTY_BYTE_ARRAY,0,0);
+ delete.addDeleteMarker(deleteKeyValue);
+ mutations.add(delete);
+ sizeBytes += deleteKeyValue.getLength();
+ // Put new value
+ Put put = new Put(newKeyValue.getRow());
+ put.add(newKeyValue);
+ mutations.add(put);
+ } else if (KeyValue.Type.codeToType(newKeyValue.getType()) == KeyValue.Type.Delete){
+ // Copy delete marker using new key so that it continues
+ // to delete the key value preceding it that will be updated
+ // as well.
+ Delete delete = new Delete(newKeyValue.getRow());
+ delete.addDeleteMarker(newKeyValue);
+ mutations.add(delete);
+ }
}
if (sizeBytes >= batchSizeBytes) {
logger.info("Committing bactch of SYSTEM.SEQUENCE rows");
@@ -179,13 +183,34 @@ public class UpgradeUtil {
}
}
- private static KeyValue addSaltByte(KeyValue keyValue) {
+ @SuppressWarnings("deprecation")
+ private static KeyValue addSaltByte(KeyValue keyValue, int nSaltBuckets) {
+ byte[] buf = keyValue.getBuffer();
int length = keyValue.getRowLength();
int offset = keyValue.getRowOffset();
- byte[] buf = keyValue.getBuffer();
- byte[] newBuf = new byte[length + 1];
- System.arraycopy(buf, offset, newBuf, SaltingUtil.NUM_SALTING_BYTES, length);
- newBuf[0] = SaltingUtil.getSaltingByte(newBuf, SaltingUtil.NUM_SALTING_BYTES, length, SaltingUtil.MAX_BUCKET_NUM);
+ boolean isViewSeq = length > SEQ_PREFIX_BYTES.length && Bytes.compareTo(SEQ_PREFIX_BYTES, 0, SEQ_PREFIX_BYTES.length, buf, offset, SEQ_PREFIX_BYTES.length) == 0;
+ if (!isViewSeq && nSaltBuckets == 0) {
+ return null;
+ }
+ byte[] newBuf;
+ if (isViewSeq) { // We messed up the name for the sequences for view indexes so we'll take this opportunity to fix it
+ if (buf[length-1] == 0) { // Global indexes on views have trailing null byte
+ length--;
+ }
+ byte[][] rowKeyMetaData = new byte[3][];
+ SchemaUtil.getVarChars(buf, offset, length, 0, rowKeyMetaData);
+ byte[] schemaName = rowKeyMetaData[PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX];
+ byte[] unprefixedSchemaName = new byte[schemaName.length - MetaDataUtil.VIEW_INDEX_SEQUENCE_PREFIX_BYTES.length];
+ System.arraycopy(schemaName, MetaDataUtil.VIEW_INDEX_SEQUENCE_PREFIX_BYTES.length, unprefixedSchemaName, 0, unprefixedSchemaName.length);
+ byte[] tableName = rowKeyMetaData[PhoenixDatabaseMetaData.TABLE_NAME_INDEX];
+ PName physicalName = PNameFactory.newName(unprefixedSchemaName);
+ // Reformulate key based on correct data
+ newBuf = MetaDataUtil.getViewIndexSequenceKey(tableName == null ? null : Bytes.toString(tableName), physicalName, nSaltBuckets).getKey();
+ } else {
+ newBuf = new byte[length + 1];
+ System.arraycopy(buf, offset, newBuf, SaltingUtil.NUM_SALTING_BYTES, length);
+ newBuf[0] = SaltingUtil.getSaltingByte(newBuf, SaltingUtil.NUM_SALTING_BYTES, length, nSaltBuckets);
+ }
return new KeyValue(newBuf, 0, newBuf.length,
buf, keyValue.getFamilyOffset(), keyValue.getFamilyLength(),
buf, keyValue.getQualifierOffset(), keyValue.getQualifierLength(),
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
index 9bf3896..201172b 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
@@ -28,10 +28,9 @@ import java.sql.SQLFeatureNotSupportedException;
import java.util.List;
import org.apache.hadoop.hbase.util.Pair;
-import org.junit.Test;
-
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.schema.SortOrder;
+import org.junit.Test;
public class QueryParserTest {
@@ -629,6 +628,19 @@ public class QueryParserTest {
}
@Test
+ public void testTableNameStartsWithUnderscore() throws Exception {
+ SQLParser parser = new SQLParser(
+ new StringReader(
+ "select* from _t where k in ( 1,2 )"));
+ try {
+ parser.parseStatement();
+ fail();
+ } catch (SQLException e) {
+ assertEquals(SQLExceptionCode.PARSER_ERROR.getErrorCode(), e.getErrorCode());
+ }
+ }
+
+ @Test
public void testValidUpsertSelectHint() throws Exception {
SQLParser parser = new SQLParser(
new StringReader(
http://git-wip-us.apache.org/repos/asf/phoenix/blob/ef062ad2/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java
index cfa8787..b7ecfeb 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java
@@ -795,11 +795,7 @@ public abstract class BaseTest {
+ PhoenixDatabaseMetaData.SEQUENCE_NAME
+ " FROM " + PhoenixDatabaseMetaData.SEQUENCE_FULLNAME_ESCAPED);
while (rs.next()) {
- try {
- conn.createStatement().execute("DROP SEQUENCE " + SchemaUtil.getTableName(rs.getString(1), rs.getString(2)));
- } catch (Exception e) {
- //FIXME: see https://issues.apache.org/jira/browse/PHOENIX-973
- }
+ conn.createStatement().execute("DROP SEQUENCE " + SchemaUtil.getEscapedTableName(rs.getString(1), rs.getString(2)));
}
}