phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject [3/3] git commit: PHOENIX-891 Multi-tenant - Upserting values without specifying columns names upserts values in wrong columns (JamesTaylor)
Date Wed, 26 Mar 2014 15:22:37 GMT
PHOENIX-891 Multi-tenant - Upserting values without specifying columns names upserts values
in wrong columns (JamesTaylor)


Project: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/commit/c356da2d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/tree/c356da2d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-phoenix/diff/c356da2d

Branch: refs/heads/master
Commit: c356da2d06f7a627b644ea90fa13370ddde9f84d
Parents: 9c9bf3c
Author: James Taylor <jamestaylor@apache.org>
Authored: Wed Mar 26 03:31:50 2014 -0700
Committer: James Taylor <jamestaylor@apache.org>
Committed: Wed Mar 26 08:20:39 2014 -0700

----------------------------------------------------------------------
 .../phoenix/end2end/RowValueConstructorIT.java  | 28 ++++++
 .../end2end/TenantSpecificTablesDMLIT.java      | 45 ++++++++-
 .../end2end/TenantSpecificViewIndexIT.java      | 34 ++++++-
 .../phoenix/compile/ProjectionCompiler.java     | 97 ++++++++++++++++----
 4 files changed, 182 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c356da2d/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java
index a7429e7..7315ea0 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/RowValueConstructorIT.java
@@ -864,4 +864,32 @@ public class RowValueConstructorIT extends BaseClientManagedTimeIT {
             conn.close();
         }
     }
+    
+    @Test
+    public void testRVCWithMultiCompKeysForIn() throws Exception {
+        long ts = nextTimestamp();
+        Properties props = new Properties(TEST_PROPERTIES);
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 10));
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        conn.createStatement().execute("CREATE TABLE t (pk1 varchar, pk2 varchar, constraint
pk primary key (pk1,pk2))");
+        conn.close();
+
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 20));
+        conn = DriverManager.getConnection(getUrl(), props);
+        conn.setAutoCommit(true);
+        conn.createStatement().execute("UPSERT INTO t VALUES('a','a')");
+        conn.createStatement().execute("UPSERT INTO t VALUES('b','b')");
+        conn.close();
+        
+        props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts + 30));
+        conn = DriverManager.getConnection(getUrl(), props);
+        ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM t WHERE (pk1,pk2)
IN (('a','a'),('b','b'))");
+        assertTrue(rs.next());
+        assertEquals("a",rs.getString(1));
+        assertEquals("a",rs.getString(2));
+        assertTrue(rs.next());
+        assertEquals("b",rs.getString(1));
+        assertEquals("b",rs.getString(2));
+        assertFalse(rs.next());
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c356da2d/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDMLIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDMLIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDMLIT.java
index d615db9..21d9126 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDMLIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificTablesDMLIT.java
@@ -68,10 +68,9 @@ public class TenantSpecificTablesDMLIT extends BaseTenantSpecificTablesIT
{
             conn1.commit();
             
             
-            conn2.setAutoCommit(false);
+            conn2.setAutoCommit(true);
             conn2.createStatement().executeUpdate("upsert into " + TENANT_TABLE_NAME + "
values ('them','" + TENANT_TYPE_ID + "',1,'Long Hair')");
-            conn2.createStatement().executeUpdate("upsert into " + TENANT_TABLE_NAME + "
values ('us','" + TENANT_TYPE_ID + "',2,'Hot Chicks')");
-            conn2.commit();
+            conn2.createStatement().executeUpdate("upsert into " + TENANT_TABLE_NAME + "
values ('us','" + TENANT_TYPE_ID + "',2,'Black Hat')");
 
             conn2.close();            
             conn1.close();
@@ -87,8 +86,46 @@ public class TenantSpecificTablesDMLIT extends BaseTenantSpecificTablesIT
{
             rs = conn2.createStatement().executeQuery("select * from " + TENANT_TABLE_NAME
+ " where id = 2");
             assertTrue("Expected 1 row in result set", rs.next());
             assertEquals(2, rs.getInt(3));
-            assertEquals("Hot Chicks", rs.getString(4));
+            assertEquals("Black Hat", rs.getString(4));
             assertFalse("Expected 1 row in result set", rs.next());
+            conn2.close();
+            
+            conn2 = nextConnection(PHOENIX_JDBC_TENANT_SPECIFIC_URL2);
+            conn2.createStatement().executeUpdate("upsert into " + TENANT_TABLE_NAME + "
select * from " + TENANT_TABLE_NAME );
+            conn2.commit();
+            conn2.close();
+            
+            conn2 = nextConnection(PHOENIX_JDBC_TENANT_SPECIFIC_URL2);
+            rs = conn2.createStatement().executeQuery("select * from " + TENANT_TABLE_NAME);
+            assertTrue("Expected row in result set", rs.next());
+            assertEquals(1, rs.getInt(3));
+            assertEquals("Long Hair", rs.getString(4));
+            assertTrue("Expected row in result set", rs.next());
+            assertEquals(2, rs.getInt(3));
+            assertEquals("Black Hat", rs.getString(4));
+            assertFalse("Expected 2 rows total", rs.next());
+            conn2.close();
+            
+            conn2 = nextConnection(PHOENIX_JDBC_TENANT_SPECIFIC_URL2);
+            conn2.setAutoCommit(true);;
+            conn2.createStatement().executeUpdate("upsert into " + TENANT_TABLE_NAME + "
select 'all', tenant_type_id, id, 'Big ' || tenant_col from " + TENANT_TABLE_NAME );
+            conn2.close();
+
+            conn2 = nextConnection(PHOENIX_JDBC_TENANT_SPECIFIC_URL2);
+            rs = conn2.createStatement().executeQuery("select * from " + TENANT_TABLE_NAME);
+            assertTrue("Expected row in result set", rs.next());
+            assertEquals("all", rs.getString(1));
+            assertEquals(TENANT_TYPE_ID, rs.getString(2));
+            assertEquals(1, rs.getInt(3));
+            assertEquals("Big Long Hair", rs.getString(4));
+            assertTrue("Expected row in result set", rs.next());
+            assertEquals("all", rs.getString(1));
+            assertEquals(TENANT_TYPE_ID, rs.getString(2));
+            assertEquals(2, rs.getInt(3));
+            assertEquals("Big Black Hat", rs.getString(4));
+            assertFalse("Expected 2 rows total", rs.next());
+            conn2.close();
+            
         }
         finally {
             conn1.close();

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c356da2d/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java
index 8711cdd..8ade47d 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/TenantSpecificViewIndexIT.java
@@ -20,12 +20,14 @@ package org.apache.phoenix.end2end;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.util.Properties;
 
+import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.QueryUtil;
 import org.junit.Test;
@@ -51,13 +53,20 @@ public class TenantSpecificViewIndexIT extends BaseTenantSpecificViewIndexIT
{
         conn.createStatement().execute(ddl);
         conn.createStatement().execute("UPSERT INTO MT_BASE values ('a','b','c','d')");
         conn.commit();
+        
+        ResultSet rs = conn.createStatement().executeQuery("select * from mt_base where (pk1,pk2)
IN (('a','b'),('b','b'))");
+        assertTrue(rs.next());
+        assertEquals("a",rs.getString(1));
+        assertEquals("b",rs.getString(2));
+        assertFalse(rs.next());
+        
         conn.close();
         String tenantId = "a";
         Properties props = new Properties();
         props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId);
         conn = DriverManager.getConnection(getUrl(),props);
         conn.createStatement().execute("CREATE VIEW acme AS SELECT * FROM MT_BASE");
-        ResultSet rs = conn.createStatement().executeQuery("select * from acme");
+        rs = conn.createStatement().executeQuery("select * from acme");
         assertTrue(rs.next());
         assertEquals("b",rs.getString(1));
         assertEquals("c",rs.getString(2));
@@ -86,5 +95,28 @@ public class TenantSpecificViewIndexIT extends BaseTenantSpecificViewIndexIT
{
         assertFalse(rs.next());
         rs = conn.createStatement().executeQuery("explain select pk2,col1 from acme where
col1='f'");
         assertEquals("CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_MT_BASE ['a',-32768,'f']",QueryUtil.getExplainPlan(rs));
+        
+        try {
+            // Cannot reference tenant_id column in tenant specific connection
+            conn.createStatement().executeQuery("select * from mt_base where (pk1,pk2) IN
(('a','b'),('b','b'))");
+            fail();
+        } catch (ColumnNotFoundException e) {
+        }
+        
+        // This is ok, though
+        rs = conn.createStatement().executeQuery("select * from mt_base where pk2 IN ('b','e')");
+        assertTrue(rs.next());
+        assertEquals("b",rs.getString(1));
+        assertTrue(rs.next());
+        assertEquals("e",rs.getString(1));
+        assertFalse(rs.next());
+        
+        rs = conn.createStatement().executeQuery("select * from acme where pk2 IN ('b','e')");
+        assertTrue(rs.next());
+        assertEquals("b",rs.getString(1));
+        assertTrue(rs.next());
+        assertEquals("e",rs.getString(1));
+        assertFalse(rs.next());
+        
     }
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/c356da2d/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
index 1bdbd2a..b7277b3 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ProjectionCompiler.java
@@ -17,9 +17,17 @@
  */
 package org.apache.phoenix.compile;
 
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.sql.SQLException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Set;
 
 import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -29,7 +37,11 @@ import org.apache.phoenix.compile.GroupByCompiler.GroupBy;
 import org.apache.phoenix.coprocessor.BaseScannerRegionObserver;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.exception.SQLExceptionInfo;
-import org.apache.phoenix.expression.*;
+import org.apache.phoenix.expression.BaseTerminalExpression;
+import org.apache.phoenix.expression.CoerceExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LiteralExpression;
 import org.apache.phoenix.expression.aggregator.ClientAggregators;
 import org.apache.phoenix.expression.aggregator.ServerAggregators;
 import org.apache.phoenix.expression.function.ArrayIndexFunction;
@@ -37,15 +49,44 @@ import org.apache.phoenix.expression.function.SingleAggregateFunction;
 import org.apache.phoenix.expression.visitor.KeyValueExpressionVisitor;
 import org.apache.phoenix.expression.visitor.SingleAggregateFunctionVisitor;
 import org.apache.phoenix.jdbc.PhoenixConnection;
-import org.apache.phoenix.parse.*;
+import org.apache.phoenix.parse.AliasedNode;
+import org.apache.phoenix.parse.BindParseNode;
+import org.apache.phoenix.parse.ColumnParseNode;
+import org.apache.phoenix.parse.FamilyWildcardParseNode;
+import org.apache.phoenix.parse.FunctionParseNode;
+import org.apache.phoenix.parse.ParseNode;
+import org.apache.phoenix.parse.SelectStatement;
+import org.apache.phoenix.parse.SequenceValueParseNode;
+import org.apache.phoenix.parse.TableName;
+import org.apache.phoenix.parse.TableWildcardParseNode;
+import org.apache.phoenix.parse.WildcardParseNode;
 import org.apache.phoenix.query.QueryConstants;
-import org.apache.phoenix.schema.*;
+import org.apache.phoenix.schema.ArgumentTypeMismatchException;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.ColumnRef;
+import org.apache.phoenix.schema.KeyValueSchema;
 import org.apache.phoenix.schema.KeyValueSchema.KeyValueSchemaBuilder;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PColumnFamily;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PDatum;
+import org.apache.phoenix.schema.PName;
+import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.PTable.ViewType;
+import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.RowKeySchema;
+import org.apache.phoenix.schema.TableRef;
+import org.apache.phoenix.schema.ValueBitSet;
 import org.apache.phoenix.schema.tuple.Tuple;
-import org.apache.phoenix.util.*;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.IndexUtil;
+import org.apache.phoenix.util.SchemaUtil;
+import org.apache.phoenix.util.SizedUtil;
 
-import com.google.common.collect.*;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 
 /**
@@ -71,9 +112,9 @@ public class ProjectionCompiler {
         return compile(context, statement, groupBy, Collections.<PColumn>emptyList());
     }
     
-    private static int getPosOffset(PTable table, PName tenantId) {
-        int posOffset = table.getBucketNum() == null ? 0 : 1;
+    private static int getMinPKOffset(PTable table, PName tenantId) {
         // In SELECT *, don't include tenant column or index ID column for tenant connection
+        int posOffset = table.getBucketNum() == null ? 0 : 1;
         if (table.isMultiTenant() && tenantId != null) {
             posOffset++;
         }
@@ -86,8 +127,16 @@ public class ProjectionCompiler {
     private static void projectAllTableColumns(StatementContext context, TableRef tableRef,
boolean resolveColumn, List<Expression> projectedExpressions, List<ExpressionProjector>
projectedColumns, List<? extends PDatum> targetColumns) throws SQLException {
         ColumnResolver resolver = context.getResolver();
         PTable table = tableRef.getTable();
-        int posOffset = getPosOffset(table, context.getConnection().getTenantId());
-        for (int i = posOffset; i < table.getColumns().size(); i++) {
+        int projectedOffset = projectedExpressions.size();
+        int posOffset = table.getBucketNum() == null ? 0 : 1;
+        int minPKOffset = getMinPKOffset(table, context.getConnection().getTenantId());
+        for (int i = posOffset, j = posOffset; i < table.getColumns().size(); i++) {
+            PColumn column = table.getColumns().get(i);
+            // Skip tenant ID column (which may not be the first column, but is the first
PK column)
+            if (SchemaUtil.isPKColumn(column) && j++ < minPKOffset) {
+                posOffset++;
+                continue;
+            }
             ColumnRef ref = new ColumnRef(tableRef,i);
             String colName = ref.getColumn().getName().getString();
             if (resolveColumn) {
@@ -101,7 +150,11 @@ public class ProjectionCompiler {
                 }
             }
             Expression expression = ref.newColumnExpression();
-            expression = coerceIfNecessary(i-posOffset, targetColumns, expression);
+            expression = coerceIfNecessary(i-posOffset+projectedOffset, targetColumns, expression);
+            ImmutableBytesWritable ptr = context.getTempPtr();
+            if (IndexUtil.getViewConstantValue(column, ptr)) {
+                expression = LiteralExpression.newConstant(column.getDataType().toObject(ptr),
expression.getDataType());
+            }
             projectedExpressions.add(expression);
             boolean isCaseSensitive = !SchemaUtil.normalizeIdentifier(colName).equals(colName);
             projectedColumns.add(new ExpressionProjector(colName, table.getName().getString(),
expression, isCaseSensitive));
@@ -111,17 +164,25 @@ public class ProjectionCompiler {
     private static void projectAllIndexColumns(StatementContext context, TableRef tableRef,
boolean resolveColumn, List<Expression> projectedExpressions, List<ExpressionProjector>
projectedColumns, List<? extends PDatum> targetColumns) throws SQLException {
         ColumnResolver resolver = context.getResolver();
         PTable index = tableRef.getTable();
+        int projectedOffset = projectedExpressions.size();
         PhoenixConnection conn = context.getConnection();
         PName tenantId = conn.getTenantId();
         String tableName = index.getParentName().getString();
         PTable table = conn.getMetaDataCache().getTable(new PTableKey(conn.getTenantId(),
tableName));
-        int tableOffset = getPosOffset(table, tenantId);
-        int indexOffset = getPosOffset(index, tenantId);
-        if (index.getColumns().size()-indexOffset != table.getColumns().size()-tableOffset)
{
+        int tableOffset = table.getBucketNum() == null ? 0 : 1;
+        int minTablePKOffset = getMinPKOffset(table, tenantId);
+        int minIndexPKOffset = getMinPKOffset(index, tenantId);
+        if (index.getColumns().size()-minIndexPKOffset != table.getColumns().size()-minTablePKOffset)
{
             // We'll end up not using this by the optimizer, so just throw
             throw new ColumnNotFoundException(WildcardParseNode.INSTANCE.toString());
         }
-        for (int i = tableOffset; i < table.getColumns().size(); i++) {
+        for (int i = tableOffset, j = tableOffset; i < table.getColumns().size(); i++)
{
+            PColumn column = table.getColumns().get(i);
+            // Skip tenant ID column (which may not be the first column, but is the first
PK column)
+            if (SchemaUtil.isPKColumn(column) && j++ < minTablePKOffset) {
+                tableOffset++;
+                continue;
+            }
             PColumn tableColumn = table.getColumns().get(i);
             String indexColName = IndexUtil.getIndexColumnName(tableColumn);
             PColumn indexColumn = index.getColumn(indexColName);
@@ -138,7 +199,9 @@ public class ProjectionCompiler {
                 }
             }
             Expression expression = ref.newColumnExpression();
-            expression = coerceIfNecessary(i-tableOffset, targetColumns, expression);
+            expression = coerceIfNecessary(i-tableOffset+projectedOffset, targetColumns,
expression);
+            // We do not need to check if the column is a viewConstant, because view constants
never
+            // appear as a column in an index
             projectedExpressions.add(expression);
             boolean isCaseSensitive = !SchemaUtil.normalizeIdentifier(colName).equals(colName);
             ExpressionProjector projector = new ExpressionProjector(colName, table.getName().getString(),
expression, isCaseSensitive);


Mime
View raw message