You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by if...@apache.org on 2017/11/06 15:50:16 UTC

[06/25] cassandra git commit: Allow dropping COMPACT STORAGE flag

Allow dropping COMPACT STORAGE flag

Patch by Alex Petrov; reviewed by Sylvain Lebresne for CASSANDRA-10857.


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/6c29ee84
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/6c29ee84
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/6c29ee84

Branch: refs/heads/trunk
Commit: 6c29ee84a2f62ccd05c328bbaa0c364eb1a7a821
Parents: b869744
Author: Alex Petrov <ol...@gmail.com>
Authored: Sat Sep 30 08:56:22 2017 +0200
Committer: Alex Petrov <ol...@gmail.com>
Committed: Mon Nov 6 15:44:51 2017 +0100

----------------------------------------------------------------------
 NEWS.txt                                        |  17 +
 bin/cqlsh.py                                    |   6 +-
 doc/native_protocol_v4.spec                     |   4 +
 ...dra-driver-internal-only-3.11.0-bb96859b.zip | Bin 0 -> 266661 bytes
 ...driver-internal-only-3.7.1.post0-19c1603.zip | Bin 252027 -> 0 bytes
 .../cassandra/auth/CassandraRoleManager.java    |   3 +-
 .../org/apache/cassandra/config/CFMetaData.java |  59 ++-
 src/java/org/apache/cassandra/cql3/Cql.g        |  27 +-
 .../apache/cassandra/cql3/QueryProcessor.java   |   2 +-
 .../cql3/statements/AlterTableStatement.java    |  42 +-
 .../statements/AuthenticationStatement.java     |   2 +-
 .../cql3/statements/AuthorizationStatement.java |   2 +-
 .../cql3/statements/BatchStatement.java         |   4 +-
 .../statements/CreateAggregateStatement.java    |   4 +-
 .../statements/CreateFunctionStatement.java     |   4 +-
 .../cql3/statements/CreateIndexStatement.java   |   9 +-
 .../cql3/statements/CreateTableStatement.java   |   2 +-
 .../cql3/statements/CreateViewStatement.java    |   2 +-
 .../cql3/statements/DropFunctionStatement.java  |   4 +-
 .../cql3/statements/ModificationStatement.java  |  11 +-
 .../cql3/statements/ParsedStatement.java        |   3 +-
 .../statements/SchemaAlteringStatement.java     |  32 +-
 .../cql3/statements/SelectStatement.java        |   8 +-
 .../cql3/statements/TruncateStatement.java      |   2 +-
 .../cassandra/cql3/statements/UseStatement.java |   2 +-
 src/java/org/apache/cassandra/db/view/View.java |  38 +-
 .../index/internal/keys/KeysSearcher.java       |   8 +-
 .../apache/cassandra/repair/RepairRunnable.java |   3 +-
 .../apache/cassandra/service/ClientState.java   |  16 +
 .../cassandra/thrift/ThriftValidation.java      |  10 +-
 .../transport/messages/StartupMessage.java      |   4 +
 .../org/apache/cassandra/cql3/ViewTest.java     |  15 +-
 .../cql3/validation/entities/UFTest.java        |  25 +
 .../cql3/validation/entities/UserTypesTest.java |  20 +
 .../cql3/validation/operations/AlterTest.java   |  15 +-
 .../DropCompactStorageThriftTest.java           | 525 +++++++++++++++++++
 36 files changed, 843 insertions(+), 87 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/NEWS.txt
----------------------------------------------------------------------
diff --git a/NEWS.txt b/NEWS.txt
index 60cf77c..621866b 100644
--- a/NEWS.txt
+++ b/NEWS.txt
@@ -37,6 +37,23 @@ Upgrading
    - Nothing specific to this release, but please see previous upgrading sections,
      especially if you are upgrading from 2.2.
 
+Compact Storage
+---------------
+    - Starting version 4.0, Thrift and COMPACT STORAGE is no longer supported.
+      'ALTER ... DROP COMPACT STORAGE' statement makes Compact Tables CQL-compatible,
+      exposing internal structure of Thrift/Compact Tables. You can find more details
+      on exposed internal structure under: 
+      http://cassandra.apache.org/doc/latest/cql/appendices.html#appendix-c-dropping-compact-storage
+
+      For uninterrupted cluster upgrades, drivers now support 'NO_COMPACT' startup option.
+      Supplying this flag will have same effect as 'DROP COMPACT STORAGE', but only for the
+      current connection.
+
+      In order to upgrade, clients supporting a non-compact schema view can be rolled out
+      gradually. When all the clients are updated 'ALTER ... DROP COMPACT STORAGE' can be
+      executed. After dropping compact storage, ’NO_COMPACT' option will have no effect
+      after that.
+
 Materialized Views
 -------------------
     - Cassandra will no longer allow dropping columns on tables with Materialized Views.

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/bin/cqlsh.py
----------------------------------------------------------------------
diff --git a/bin/cqlsh.py b/bin/cqlsh.py
index 8eb42a3..8d05d9d 100644
--- a/bin/cqlsh.py
+++ b/bin/cqlsh.py
@@ -205,6 +205,7 @@ parser.add_option("--browser", dest='browser', help="""The browser to use to dis
                                                     - one of the supported browsers in https://docs.python.org/2/library/webbrowser.html.
                                                     - browser path followed by %s, example: /usr/bin/google-chrome-stable %s""")
 parser.add_option('--ssl', action='store_true', help='Use SSL', default=False)
+parser.add_option('--no_compact', action='store_true', help='No Compact', default=False)
 parser.add_option("-u", "--username", help="Authenticate as user.")
 parser.add_option("-p", "--password", help="Authenticate using password.")
 parser.add_option('-k', '--keyspace', help='Authenticate to the given keyspace.')
@@ -702,6 +703,7 @@ class Shell(cmd.Cmd):
                  completekey=DEFAULT_COMPLETEKEY, browser=None, use_conn=None,
                  cqlver=DEFAULT_CQLVER, keyspace=None,
                  tracing_enabled=False, expand_enabled=False,
+                 no_compact=False,
                  display_nanotime_format=DEFAULT_NANOTIME_FORMAT,
                  display_timestamp_format=DEFAULT_TIMESTAMP_FORMAT,
                  display_date_format=DEFAULT_DATE_FORMAT,
@@ -732,7 +734,7 @@ class Shell(cmd.Cmd):
         else:
             self.conn = Cluster(contact_points=(self.hostname,), port=self.port, cql_version=cqlver,
                                 protocol_version=protocol_version,
-                                auth_provider=self.auth_provider,
+                                auth_provider=self.auth_provider, no_compact=no_compact,
                                 ssl_options=sslhandling.ssl_settings(hostname, CONFIG_FILE) if ssl else None,
                                 load_balancing_policy=WhiteListRoundRobinPolicy([self.hostname]),
                                 control_connection_timeout=connect_timeout,
@@ -2486,6 +2488,7 @@ def read_options(cmdlineargs, environment):
     optvalues.debug = False
     optvalues.file = None
     optvalues.ssl = False
+    optvalues.no_compact = False
     optvalues.encoding = option_with_default(configs.get, 'ui', 'encoding', UTF8)
 
     optvalues.tty = option_with_default(configs.getboolean, 'ui', 'tty', sys.stdin.isatty())
@@ -2643,6 +2646,7 @@ def main(options, hostname, port):
                       browser=options.browser,
                       cqlver=options.cqlversion,
                       keyspace=options.keyspace,
+                      no_compact=options.no_compact,
                       display_timestamp_format=options.time_format,
                       display_nanotime_format=options.nanotime_format,
                       display_date_format=options.date_format,

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/doc/native_protocol_v4.spec
----------------------------------------------------------------------
diff --git a/doc/native_protocol_v4.spec b/doc/native_protocol_v4.spec
index 44dac18..2188a33 100644
--- a/doc/native_protocol_v4.spec
+++ b/doc/native_protocol_v4.spec
@@ -271,6 +271,10 @@ Table of Contents
       different from the protocol version.
     - "COMPRESSION": the compression algorithm to use for frames (See section 5).
       This is optional; if not specified no compression will be used.
+    - "NO_COMPACT": whether or not connection has to be established in compatibility
+      mode. This mode will make all Thrift and Compact Tables to be exposed as if
+      they were CQL Tables. This is optional; if not specified, the option will
+      not be used.
 
 
 4.1.2. AUTH_RESPONSE

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/lib/cassandra-driver-internal-only-3.11.0-bb96859b.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.11.0-bb96859b.zip b/lib/cassandra-driver-internal-only-3.11.0-bb96859b.zip
new file mode 100644
index 0000000..d31abc3
Binary files /dev/null and b/lib/cassandra-driver-internal-only-3.11.0-bb96859b.zip differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/lib/cassandra-driver-internal-only-3.7.1.post0-19c1603.zip
----------------------------------------------------------------------
diff --git a/lib/cassandra-driver-internal-only-3.7.1.post0-19c1603.zip b/lib/cassandra-driver-internal-only-3.7.1.post0-19c1603.zip
deleted file mode 100644
index 900d64d..0000000
Binary files a/lib/cassandra-driver-internal-only-3.7.1.post0-19c1603.zip and /dev/null differ

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/auth/CassandraRoleManager.java b/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
index e5b98e4..c6716e5 100644
--- a/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
+++ b/src/java/org/apache/cassandra/auth/CassandraRoleManager.java
@@ -39,6 +39,7 @@ import org.apache.cassandra.db.ConsistencyLevel;
 import org.apache.cassandra.db.marshal.UTF8Type;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.net.MessagingService;
+import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.transport.messages.ResultMessage;
@@ -465,7 +466,7 @@ public class CassandraRoleManager implements IRoleManager
     {
         try
         {
-            return QueryProcessor.parseStatement(String.format(template, keyspace, table)).prepare().statement;
+            return QueryProcessor.parseStatement(String.format(template, keyspace, table)).prepare(ClientState.forInternalCalls()).statement;
         }
         catch (RequestValidationException e)
         {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/config/CFMetaData.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/config/CFMetaData.java b/src/java/org/apache/cassandra/config/CFMetaData.java
index fd1c9e5..c1b2171 100644
--- a/src/java/org/apache/cassandra/config/CFMetaData.java
+++ b/src/java/org/apache/cassandra/config/CFMetaData.java
@@ -79,10 +79,6 @@ public final class CFMetaData
     public final Pair<String, String> ksAndCFName;
     public final byte[] ksAndCFBytes;
 
-    private final ImmutableSet<Flag> flags;
-    private final boolean isDense;
-    private final boolean isCompound;
-    private final boolean isSuper;
     private final boolean isCounter;
     private final boolean isView;
     private final boolean isIndex;
@@ -94,6 +90,11 @@ public final class CFMetaData
     private final Serializers serializers;
 
     // non-final, for now
+    private volatile ImmutableSet<Flag> flags;
+    private volatile boolean isDense;
+    private volatile boolean isCompound;
+    private volatile boolean isSuper;
+
     public volatile TableParams params = TableParams.DEFAULT;
 
     private volatile Map<ByteBuffer, DroppedColumn> droppedColumns = new HashMap<>();
@@ -127,6 +128,9 @@ public final class CFMetaData
     private volatile ColumnDefinition superCfKeyColumn;
     private volatile ColumnDefinition superCfValueColumn;
 
+    /** Caches a non-compact version of the metadata for compact tables to be used with the NO_COMPACT protocol option. */
+    private volatile CFMetaData nonCompactCopy = null;
+
     public boolean isSuperColumnKeyColumn(ColumnDefinition cd)
     {
         return cd.name.equals(superCfKeyColumn.name);
@@ -330,6 +334,9 @@ public final class CFMetaData
     // are kept because they are often useful in a different format.
     private void rebuild()
     {
+        // A non-compact copy will be created lazily
+        this.nonCompactCopy = null;
+
         if (isCompactTable())
         {
             this.compactValueColumn = isSuper() ?
@@ -505,6 +512,38 @@ public final class CFMetaData
         return params(indexParams.build());
     }
 
+    /**
+     * Returns a cached non-compact version of this table. Cached version has to be invalidated
+     * every time the table is rebuilt.
+     */
+    public CFMetaData asNonCompact()
+    {
+        assert isCompactTable() : "Can't get non-compact version of a CQL table";
+
+        // Note that this is racy, but re-computing the non-compact copy a few times on first uses isn't a big deal so
+        // we don't bother.
+        if (nonCompactCopy == null)
+        {
+            nonCompactCopy = copyOpts(new CFMetaData(ksName,
+                                                     cfName,
+                                                     cfId,
+                                                     false,
+                                                     isCounter,
+                                                     false,
+                                                     true,
+                                                     isView,
+                                                     copy(partitionKeyColumns),
+                                                     copy(clusteringColumns),
+                                                     copy(partitionColumns),
+                                                     partitioner,
+                                                     superCfKeyColumn,
+                                                     superCfValueColumn),
+                                      this);
+        }
+
+        return nonCompactCopy;
+    }
+
     public CFMetaData copy()
     {
         return copy(cfId);
@@ -842,6 +881,12 @@ public final class CFMetaData
         superCfKeyColumn = cfm.superCfKeyColumn;
         superCfValueColumn = cfm.superCfValueColumn;
 
+        isDense = cfm.isDense;
+        isCompound = cfm.isCompound;
+        isSuper = cfm.isSuper;
+
+        flags = cfm.flags;
+
         rebuild();
 
         // compaction thresholds are checked by ThriftValidation. We shouldn't be doing
@@ -874,12 +919,6 @@ public final class CFMetaData
         if (!cfm.cfId.equals(cfId))
             throw new ConfigurationException(String.format("Column family ID mismatch (found %s; expected %s)",
                                                            cfm.cfId, cfId));
-
-        // Dense flag can get set, see CASSANDRA-12373 for details. We have to remove flag from both parts because
-        // there's no guaranteed call order in the call.
-
-        if (!cfm.flags.equals(flags) && (!isSuper() || !Sets.difference(cfm.flags, Sets.immutableEnumSet(Flag.DENSE)).equals(Sets.difference(flags, Sets.immutableEnumSet(Flag.DENSE)))))
-            throw new ConfigurationException("Types do not match: " + cfm.flags + " != " + flags);
     }
 
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g b/src/java/org/apache/cassandra/cql3/Cql.g
index 3123877..0234327 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -781,7 +781,7 @@ createTriggerStatement returns [CreateTriggerStatement expr]
     @init {
         boolean ifNotExists = false;
     }
-    : K_CREATE K_TRIGGER (K_IF K_NOT K_EXISTS { ifNotExists = true; } )? (name=cident)
+    : K_CREATE K_TRIGGER (K_IF K_NOT K_EXISTS { ifNotExists = true; } )? (name=noncol_ident)
         K_ON cf=columnFamilyName K_USING cls=STRING_LITERAL
       { $expr = new CreateTriggerStatement(cf, name.toString(), $cls.text, ifNotExists); }
     ;
@@ -791,7 +791,7 @@ createTriggerStatement returns [CreateTriggerStatement expr]
  */
 dropTriggerStatement returns [DropTriggerStatement expr]
      @init { boolean ifExists = false; }
-    : K_DROP K_TRIGGER (K_IF K_EXISTS { ifExists = true; } )? (name=cident) K_ON cf=columnFamilyName
+    : K_DROP K_TRIGGER (K_IF K_EXISTS { ifExists = true; } )? (name=noncol_ident) K_ON cf=columnFamilyName
       { $expr = new DropTriggerStatement(cf, name.toString(), ifExists); }
     ;
 
@@ -816,20 +816,21 @@ alterTableStatement returns [AlterTableStatement expr]
     @init {
         AlterTableStatement.Type type = null;
         TableAttributes attrs = new TableAttributes();
-        Map<ColumnIdentifier.Raw, ColumnIdentifier.Raw> renames = new HashMap<ColumnIdentifier.Raw, ColumnIdentifier.Raw>();
+        Map<ColumnIdentifier.Raw, ColumnIdentifier> renames = new HashMap<ColumnIdentifier.Raw, ColumnIdentifier>();
         boolean isStatic = false;
         Long dropTimestamp = null;
     }
     : K_ALTER K_COLUMNFAMILY cf=columnFamilyName
-          ( K_ALTER id=cident K_TYPE v=comparatorType { type = AlterTableStatement.Type.ALTER; }
-          | K_ADD   id=cident v=comparatorType ({ isStatic=true; } K_STATIC)? { type = AlterTableStatement.Type.ADD; }
+          ( K_ALTER id=cident K_TYPE v=comparatorType { type = AlterTableStatement.Type.ALTER;  }
+          | K_ADD   aid=ident {id=new ColumnIdentifier.ColumnIdentifierValue(aid);} v=comparatorType ({ isStatic=true; } K_STATIC)? { type = AlterTableStatement.Type.ADD; }
           | K_DROP  id=cident                               { type = AlterTableStatement.Type.DROP; }
           | K_DROP  id=cident K_USING K_TIMESTAMP t=INTEGER { type = AlterTableStatement.Type.DROP;
                                                               dropTimestamp = Long.parseLong(Constants.Literal.integer($t.text).getText()); }
+          | K_DROP  K_COMPACT K_STORAGE                     { type = AlterTableStatement.Type.DROP_COMPACT_STORAGE; }
           | K_WITH  properties[attrs]                       { type = AlterTableStatement.Type.OPTS; }
           | K_RENAME                                        { type = AlterTableStatement.Type.RENAME; }
-               id1=cident K_TO toId1=cident { renames.put(id1, toId1); }
-               ( K_AND idn=cident K_TO toIdn=cident { renames.put(idn, toIdn); } )*
+               id1=cident K_TO toId1=ident { renames.put(id1, toId1); }
+               ( K_AND idn=cident K_TO toIdn=ident { renames.put(idn, toIdn); } )*
           )
     {
         $expr = new AlterTableStatement(cf, type, id, v, attrs, renames, isStatic, dropTimestamp);
@@ -1169,10 +1170,14 @@ userPassword[RoleOptions opts]
 // Column Identifiers.  These need to be treated differently from other
 // identifiers because the underlying comparator is not necessarily text. See
 // CASSANDRA-8178 for details.
+// Also, we need to support the internal of the super column map (for backward
+// compatibility) which is empty (we only want to allow this is queries, not for
+// creating table or other).
 cident returns [ColumnIdentifier.Raw id]
     : t=IDENT              { $id = new ColumnIdentifier.Literal($t.text, false); }
     | t=QUOTED_NAME        { $id = new ColumnIdentifier.Literal($t.text, true); }
     | k=unreserved_keyword { $id = new ColumnIdentifier.Literal(k, false); }
+    | EMPTY_QUOTED_NAME    { $id = new ColumnIdentifier.Literal("", false); }
     ;
 
 // Column identifiers where the comparator is known to be text
@@ -1309,7 +1314,9 @@ intValue returns [Term.Raw value]
     ;
 
 functionName returns [FunctionName s]
-    : (ks=keyspaceName '.')? f=allowedFunctionName   { $s = new FunctionName(ks, f); }
+     // antlr might try to recover and give a null for f. It will still error out in the end, but FunctionName
+     // wouldn't be happy with that so we should bypass this for now or we'll have a weird user-facing error
+    : (ks=keyspaceName '.')? f=allowedFunctionName   { $s = f == null ? null : new FunctionName(ks, f); }
     ;
 
 allowedFunctionName returns [String s]
@@ -1822,6 +1829,10 @@ STRING_LITERAL
       )
     ;
 
+EMPTY_QUOTED_NAME
+    : '\"' '\"'
+    ;
+
 QUOTED_NAME
     @init{ StringBuilder b = new StringBuilder(); }
     @after{ setText(b.toString()); }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/QueryProcessor.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
index af94d3e..ddee6c7 100644
--- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java
+++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java
@@ -517,7 +517,7 @@ public class QueryProcessor implements QueryHandler
             ((CFStatement)statement).prepareKeyspace(clientState);
 
         Tracing.trace("Preparing statement");
-        return statement.prepare();
+        return statement.prepare(clientState);
     }
 
     public static ParsedStatement parseStatement(String queryStr) throws SyntaxException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
index befdd25..a5fa12d 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AlterTableStatement.java
@@ -31,8 +31,6 @@ import org.apache.cassandra.db.ColumnFamilyStore;
 import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.db.marshal.AbstractType;
 import org.apache.cassandra.db.marshal.CollectionType;
-import org.apache.cassandra.db.marshal.CounterColumnType;
-import org.apache.cassandra.db.marshal.ReversedType;
 import org.apache.cassandra.db.view.View;
 import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.schema.IndexMetadata;
@@ -49,14 +47,14 @@ public class AlterTableStatement extends SchemaAlteringStatement
 {
     public enum Type
     {
-        ADD, ALTER, DROP, OPTS, RENAME
+        ADD, ALTER, DROP, DROP_COMPACT_STORAGE, OPTS, RENAME
     }
 
     public final Type oType;
     public final CQL3Type.Raw validator;
     public final ColumnIdentifier.Raw rawColumnName;
     private final TableAttributes attrs;
-    private final Map<ColumnIdentifier.Raw, ColumnIdentifier.Raw> renames;
+    private final Map<ColumnIdentifier.Raw, ColumnIdentifier> renames;
     private final boolean isStatic; // Only for ALTER ADD
     private final Long deleteTimestamp;
 
@@ -65,7 +63,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
                                ColumnIdentifier.Raw columnName,
                                CQL3Type.Raw validator,
                                TableAttributes attrs,
-                               Map<ColumnIdentifier.Raw, ColumnIdentifier.Raw> renames,
+                               Map<ColumnIdentifier.Raw, ColumnIdentifier> renames,
                                boolean isStatic,
                                Long deleteTimestamp)
     {
@@ -95,15 +93,15 @@ public class AlterTableStatement extends SchemaAlteringStatement
         if (meta.isView())
             throw new InvalidRequestException("Cannot use ALTER TABLE on Materialized View");
 
-        CFMetaData cfm = meta.copy();
+        CFMetaData cfm;
 
         CQL3Type validator = this.validator == null ? null : this.validator.prepare(keyspace());
         ColumnIdentifier columnName = null;
         ColumnDefinition def = null;
         if (rawColumnName != null)
         {
-            columnName = rawColumnName.prepare(cfm);
-            def = cfm.getColumnDefinition(columnName);
+            columnName = rawColumnName.prepare(meta);
+            def = meta.getColumnDefinition(columnName);
         }
 
         List<ViewDefinition> viewUpdates = null;
@@ -115,9 +113,11 @@ public class AlterTableStatement extends SchemaAlteringStatement
                 throw new InvalidRequestException("Altering of types is not allowed");
             case ADD:
                 assert columnName != null;
-                if (cfm.isDense())
+                if (meta.isDense())
                     throw new InvalidRequestException("Cannot add new column to a COMPACT STORAGE table");
 
+                cfm = meta.copy();
+
                 if (isStatic)
                 {
                     if (!cfm.isCompound())
@@ -190,11 +190,14 @@ public class AlterTableStatement extends SchemaAlteringStatement
 
             case DROP:
                 assert columnName != null;
-                if (!cfm.isCQLTable())
+                if (!meta.isCQLTable())
                     throw new InvalidRequestException("Cannot drop columns from a non-CQL3 table");
+
                 if (def == null)
                     throw new InvalidRequestException(String.format("Column %s was not found in table %s", columnName, columnFamily()));
 
+                cfm = meta.copy();
+
                 switch (def.kind)
                 {
                     case PARTITION_KEY:
@@ -238,11 +241,19 @@ public class AlterTableStatement extends SchemaAlteringStatement
                                                                     columnName.toString(),
                                                                     keyspace()));
                 break;
+            case DROP_COMPACT_STORAGE:
+                if (!meta.isCompactTable())
+                    throw new InvalidRequestException("Cannot DROP COMPACT STORAGE on table without COMPACT STORAGE");
+
+                cfm = meta.asNonCompact();
+                break;
             case OPTS:
                 if (attrs == null)
                     throw new InvalidRequestException("ALTER TABLE WITH invoked, but no parameters found");
                 attrs.validate();
 
+                cfm = meta.copy();
+
                 TableParams params = attrs.asAlteredTableParams(cfm.params);
 
                 if (!Iterables.isEmpty(views) && params.gcGraceSeconds == 0)
@@ -261,10 +272,13 @@ public class AlterTableStatement extends SchemaAlteringStatement
 
                 break;
             case RENAME:
-                for (Map.Entry<ColumnIdentifier.Raw, ColumnIdentifier.Raw> entry : renames.entrySet())
+                cfm = meta.copy();
+
+                for (Map.Entry<ColumnIdentifier.Raw, ColumnIdentifier> entry : renames.entrySet())
                 {
                     ColumnIdentifier from = entry.getKey().prepare(cfm);
-                    ColumnIdentifier to = entry.getValue().prepare(cfm);
+                    ColumnIdentifier to = entry.getValue();
+
                     cfm.renameColumn(from, to);
 
                     // If the view includes a renamed column, it must be renamed in the view table and the definition.
@@ -274,7 +288,7 @@ public class AlterTableStatement extends SchemaAlteringStatement
 
                         ViewDefinition viewCopy = view.copy();
                         ColumnIdentifier viewFrom = entry.getKey().prepare(viewCopy.metadata);
-                        ColumnIdentifier viewTo = entry.getValue().prepare(viewCopy.metadata);
+                        ColumnIdentifier viewTo = entry.getValue();
                         viewCopy.renameColumn(viewFrom, viewTo);
 
                         if (viewUpdates == null)
@@ -283,6 +297,8 @@ public class AlterTableStatement extends SchemaAlteringStatement
                     }
                 }
                 break;
+            default:
+                throw new InvalidRequestException("Can not alter table: unknown option type " + oType);
         }
 
         MigrationManager.announceColumnFamilyUpdate(cfm, viewUpdates, isLocalOnly);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java b/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
index 151e4f0..30ab6b0 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AuthenticationStatement.java
@@ -31,7 +31,7 @@ import org.apache.cassandra.transport.messages.ResultMessage;
 public abstract class AuthenticationStatement extends ParsedStatement implements CQLStatement
 {
     @Override
-    public Prepared prepare()
+    public Prepared prepare(ClientState clientState)
     {
         return new Prepared(this);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java b/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
index 098e22c..fa2a993 100644
--- a/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/AuthorizationStatement.java
@@ -32,7 +32,7 @@ import org.apache.cassandra.transport.messages.ResultMessage;
 public abstract class AuthorizationStatement extends ParsedStatement implements CQLStatement
 {
     @Override
-    public Prepared prepare()
+    public Prepared prepare(ClientState clientState)
     {
         return new Prepared(this);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
index cd9358c..1c3cfa6 100644
--- a/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/BatchStatement.java
@@ -516,7 +516,7 @@ public class BatchStatement implements CQLStatement
                 statement.prepareKeyspace(state);
         }
 
-        public ParsedStatement.Prepared prepare() throws InvalidRequestException
+        public ParsedStatement.Prepared prepare(ClientState clientState) throws InvalidRequestException
         {
             VariableSpecifications boundNames = getBoundVariables();
 
@@ -537,7 +537,7 @@ public class BatchStatement implements CQLStatement
                     haveMultipleCFs = !firstKS.equals(parsed.keyspace()) || !firstCF.equals(parsed.columnFamily());
                 }
 
-                statements.add(parsed.prepare(boundNames));
+                statements.add(parsed.prepare(boundNames, clientState));
             }
 
             Attributes prepAttrs = attrs.prepare("[batch]", "[batch]");

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/CreateAggregateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateAggregateStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateAggregateStatement.java
index ca0270f..9d91693 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateAggregateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateAggregateStatement.java
@@ -78,7 +78,7 @@ public final class CreateAggregateStatement extends SchemaAlteringStatement
         this.ifNotExists = ifNotExists;
     }
 
-    public Prepared prepare()
+    public Prepared prepare(ClientState clientState)
     {
         argTypes = new ArrayList<>(argRawTypes.size());
         for (CQL3Type.Raw rawType : argRawTypes)
@@ -136,7 +136,7 @@ public final class CreateAggregateStatement extends SchemaAlteringStatement
                 throw new InvalidRequestException("INITCOND must not be empty for all types except TEXT, ASCII, BLOB");
         }
 
-        return super.prepare();
+        return super.prepare(clientState);
     }
 
     private AbstractType<?> prepareType(String typeName, CQL3Type.Raw rawType)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
index c8d38f5..dfe522b 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateFunctionStatement.java
@@ -76,7 +76,7 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
         this.ifNotExists = ifNotExists;
     }
 
-    public Prepared prepare() throws InvalidRequestException
+    public Prepared prepare(ClientState clientState) throws InvalidRequestException
     {
         if (new HashSet<>(argNames).size() != argNames.size())
             throw new InvalidRequestException(String.format("duplicate argument names for given function %s with argument names %s",
@@ -87,7 +87,7 @@ public final class CreateFunctionStatement extends SchemaAlteringStatement
             argTypes.add(prepareType("arguments", rawType));
 
         returnType = prepareType("return type", rawReturnType);
-        return super.prepare();
+        return super.prepare(clientState);
     }
 
     public void prepareKeyspace(ClientState state) throws InvalidRequestException

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
index c21441c..47d54fe 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateIndexStatement.java
@@ -103,8 +103,13 @@ public class CreateIndexStatement extends SchemaAlteringStatement
                 throw new InvalidRequestException("No column definition found for column " + target.column);
 
             // TODO: we could lift that limitation
-            if (cfm.isCompactTable() && cd.isPrimaryKeyColumn())
-                throw new InvalidRequestException("Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables");
+            if (cfm.isCompactTable())
+            {
+                if (cd.isPrimaryKeyColumn())
+                    throw new InvalidRequestException("Secondary indexes are not supported on PRIMARY KEY columns in COMPACT STORAGE tables");
+                if (cfm.compactValueColumn().equals(cd))
+                    throw new InvalidRequestException("Secondary indexes are not supported on compact value column of COMPACT STORAGE tables");
+            }
 
             // It would be possible to support 2ndary index on static columns (but not without modifications of at least ExtendedFilter and
             // CompositesIndex) and maybe we should, but that means a query like:

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
index ef950dc..9f14194 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateTableStatement.java
@@ -191,7 +191,7 @@ public class CreateTableStatement extends SchemaAlteringStatement
         /**
          * Transform this raw statement into a CreateTableStatement.
          */
-        public ParsedStatement.Prepared prepare() throws RequestValidationException
+        public ParsedStatement.Prepared prepare(ClientState clientState) throws RequestValidationException
         {
             KeyspaceMetadata ksm = Schema.instance.getKSMetaData(keyspace());
             if (ksm == null)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java b/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java
index 778a3f4..cce954f 100644
--- a/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/CreateViewStatement.java
@@ -214,7 +214,7 @@ public class CreateViewStatement extends SchemaAlteringStatement
         rawSelect.prepareKeyspace(state);
         rawSelect.setBoundVariables(getBoundVariables());
 
-        ParsedStatement.Prepared prepared = rawSelect.prepare(true);
+        ParsedStatement.Prepared prepared = rawSelect.prepare(true, queryState.getClientState());
         SelectStatement select = (SelectStatement) prepared.statement;
         StatementRestrictions restrictions = select.getRestrictions();
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
index 138691e..8845a82 100644
--- a/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/DropFunctionStatement.java
@@ -63,7 +63,7 @@ public final class DropFunctionStatement extends SchemaAlteringStatement
     }
 
     @Override
-    public Prepared prepare() throws InvalidRequestException
+    public Prepared prepare(ClientState clientState) throws InvalidRequestException
     {
         if (Schema.instance.getKSMetaData(functionName.keyspace) != null)
         {
@@ -82,7 +82,7 @@ public final class DropFunctionStatement extends SchemaAlteringStatement
             }
         }
 
-        return super.prepare();
+        return super.prepare(clientState);
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
index 28fc90f..8ae4d64 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java
@@ -793,17 +793,16 @@ public abstract class ModificationStatement implements CQLStatement
             this.ifExists = ifExists;
         }
 
-        public ParsedStatement.Prepared prepare()
+        public ParsedStatement.Prepared prepare(ClientState clientState)
         {
             VariableSpecifications boundNames = getBoundVariables();
-            ModificationStatement statement = prepare(boundNames);
-            CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
-            return new ParsedStatement.Prepared(statement, boundNames, boundNames.getPartitionKeyBindIndexes(cfm));
+            ModificationStatement statement = prepare(boundNames, clientState);
+            return new ParsedStatement.Prepared(statement, boundNames, boundNames.getPartitionKeyBindIndexes(statement.cfm));
         }
 
-        public ModificationStatement prepare(VariableSpecifications boundNames)
+        public ModificationStatement prepare(VariableSpecifications boundNames, ClientState clientState)
         {
-            CFMetaData metadata = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
+            CFMetaData metadata = ThriftValidation.validateColumnFamilyWithCompactMode(keyspace(), columnFamily(), clientState.isNoCompactMode());
 
             Attributes preparedAttributes = attrs.prepare(keyspace(), columnFamily());
             preparedAttributes.collectMarkerSpecification(boundNames);

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java b/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
index 4c3f8a9..01a1b5e 100644
--- a/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/ParsedStatement.java
@@ -23,6 +23,7 @@ import java.util.List;
 import org.apache.cassandra.cql3.*;
 import org.apache.cassandra.cql3.functions.Function;
 import org.apache.cassandra.exceptions.RequestValidationException;
+import org.apache.cassandra.service.ClientState;
 
 public abstract class ParsedStatement
 {
@@ -44,7 +45,7 @@ public abstract class ParsedStatement
         this.variables = variables;
     }
 
-    public abstract Prepared prepare() throws RequestValidationException;
+    public abstract Prepared prepare(ClientState clientState) throws RequestValidationException;
 
     public static class Prepared
     {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
index 62ba0ae..e7ecb14 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SchemaAlteringStatement.java
@@ -18,6 +18,8 @@
 package org.apache.cassandra.cql3.statements;
 
 import org.apache.cassandra.auth.AuthenticatedUser;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.Schema;
 import org.apache.cassandra.cql3.CFName;
 import org.apache.cassandra.cql3.CQLStatement;
 import org.apache.cassandra.cql3.QueryOptions;
@@ -25,9 +27,12 @@ import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.exceptions.RequestValidationException;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
+import org.apache.cassandra.thrift.ThriftValidation;
 import org.apache.cassandra.transport.Event;
 import org.apache.cassandra.transport.messages.ResultMessage;
 
+import static org.apache.cassandra.cql3.statements.RequestValidations.invalidRequest;
+
 /**
  * Abstract class for statements that alter the schema.
  */
@@ -60,8 +65,33 @@ public abstract class SchemaAlteringStatement extends CFStatement implements CQL
     }
 
     @Override
-    public Prepared prepare()
+    public Prepared prepare(ClientState clientState)
     {
+        // We don't allow schema changes in no-compact mode on compact tables because it feels like unnecessary
+        // complication: applying the change on the non compact version of the table might be unsafe (the table is
+        // still compact in general), and applying it to the compact version in a no-compact connection feels
+        // confusing/unintuitive. If user want to alter the compact version, they can simply do so in a normal
+        // connection; if they want to alter the non-compact version, they should finish their transition and properly
+        // DROP COMPACT STORAGE on the table before doing so.
+        if (isColumnFamilyLevel && clientState.isNoCompactMode())
+        {
+            CFMetaData table = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
+            if (table.isCompactTable())
+            {
+                throw invalidRequest("Cannot alter schema of compact table %s.%s from a connection in NO-COMPACT mode",
+                                     table.ksName, table.cfName);
+            }
+            else if (table.isView())
+            {
+                CFMetaData baseTable = Schema.instance.getView(table.ksName, table.cfName).baseTableMetadata();
+                if (baseTable.isCompactTable())
+                    throw new InvalidRequestException(String.format("Cannot ALTER schema of view %s.%s on compact table %s from "
+                                                                    + "a connection in NO-COMPACT mode",
+                                                                    table.ksName, table.cfName,
+                                                                    baseTable.ksName, baseTable.cfName));
+            }
+        }
+
         return new Prepared(this);
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
index 2e090fa..1e867bc 100644
--- a/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/SelectStatement.java
@@ -887,14 +887,14 @@ public class SelectStatement implements CQLStatement
             this.limit = limit;
         }
 
-        public ParsedStatement.Prepared prepare() throws InvalidRequestException
+        public ParsedStatement.Prepared prepare(ClientState clientState) throws InvalidRequestException
         {
-            return prepare(false);
+            return prepare(false, clientState);
         }
 
-        public ParsedStatement.Prepared prepare(boolean forView) throws InvalidRequestException
+        public ParsedStatement.Prepared prepare(boolean forView, ClientState clientState) throws InvalidRequestException
         {
-            CFMetaData cfm = ThriftValidation.validateColumnFamily(keyspace(), columnFamily());
+            CFMetaData cfm = ThriftValidation.validateColumnFamilyWithCompactMode(keyspace(), columnFamily(), clientState.isNoCompactMode());
             VariableSpecifications boundNames = getBoundVariables();
 
             Selection selection = selectClause.isEmpty()

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
index 66b3da0..b697910 100644
--- a/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/TruncateStatement.java
@@ -45,7 +45,7 @@ public class TruncateStatement extends CFStatement implements CQLStatement
         return 0;
     }
 
-    public Prepared prepare() throws InvalidRequestException
+    public Prepared prepare(ClientState clientState) throws InvalidRequestException
     {
         return new Prepared(this);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/cql3/statements/UseStatement.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/statements/UseStatement.java b/src/java/org/apache/cassandra/cql3/statements/UseStatement.java
index fe3d518..e4685cc 100644
--- a/src/java/org/apache/cassandra/cql3/statements/UseStatement.java
+++ b/src/java/org/apache/cassandra/cql3/statements/UseStatement.java
@@ -39,7 +39,7 @@ public class UseStatement extends ParsedStatement implements CQLStatement
         return 0;
     }
 
-    public Prepared prepare() throws InvalidRequestException
+    public Prepared prepare(ClientState clientState) throws InvalidRequestException
     {
         return new Prepared(this);
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/db/view/View.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/view/View.java b/src/java/org/apache/cassandra/db/view/View.java
index 58e2a84..9716dc4 100644
--- a/src/java/org/apache/cassandra/db/view/View.java
+++ b/src/java/org/apache/cassandra/db/view/View.java
@@ -17,32 +17,38 @@
  */
 package org.apache.cassandra.db.view;
 
-import java.nio.ByteBuffer;
-import java.util.*;
-import java.util.concurrent.TimeUnit;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.UUID;
 import java.util.stream.Collectors;
-
 import javax.annotation.Nullable;
 
 import com.google.common.collect.Iterables;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import org.apache.cassandra.cql3.*;
+import org.apache.cassandra.config.CFMetaData;
+import org.apache.cassandra.config.ColumnDefinition;
+import org.apache.cassandra.config.Schema;
+import org.apache.cassandra.config.ViewDefinition;
+import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.cql3.MultiColumnRelation;
+import org.apache.cassandra.cql3.QueryOptions;
+import org.apache.cassandra.cql3.Relation;
+import org.apache.cassandra.cql3.SingleColumnRelation;
+import org.apache.cassandra.cql3.Term;
 import org.apache.cassandra.cql3.statements.ParsedStatement;
 import org.apache.cassandra.cql3.statements.SelectStatement;
-import org.apache.cassandra.db.*;
-import org.apache.cassandra.config.*;
-import org.apache.cassandra.cql3.ColumnIdentifier;
+import org.apache.cassandra.db.ColumnFamilyStore;
+import org.apache.cassandra.db.DecoratedKey;
+import org.apache.cassandra.db.ReadQuery;
 import org.apache.cassandra.db.compaction.CompactionManager;
-import org.apache.cassandra.db.partitions.*;
-import org.apache.cassandra.db.rows.*;
+import org.apache.cassandra.db.rows.Row;
 import org.apache.cassandra.schema.KeyspaceMetadata;
 import org.apache.cassandra.service.ClientState;
-import org.apache.cassandra.service.pager.QueryPager;
-import org.apache.cassandra.transport.Server;
 import org.apache.cassandra.utils.FBUtilities;
-import org.apache.cassandra.utils.btree.BTreeSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * A View copies data from a base table into a view table which can be queried independently from the
@@ -176,7 +182,7 @@ public class View
             ClientState state = ClientState.forInternalCalls();
             state.setKeyspace(baseCfs.keyspace.getName());
             rawSelect.prepareKeyspace(state);
-            ParsedStatement.Prepared prepared = rawSelect.prepare(true);
+            ParsedStatement.Prepared prepared = rawSelect.prepare(true, ClientState.forInternalCalls());
             select = (SelectStatement) prepared.statement;
         }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java b/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java
index c14c5a7..7cf4c51 100644
--- a/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java
+++ b/src/java/org/apache/cassandra/index/internal/keys/KeysSearcher.java
@@ -197,7 +197,13 @@ public class KeysSearcher extends CassandraIndexSearcher
         }
         else
         {
-            assert iterator.metadata().isCompactTable();
+            if (!iterator.metadata().isCompactTable())
+            {
+                logger.warn("Non-composite index was used on the table '{}' during the query. Starting from Cassandra 4.0, only " +
+                            "composite indexes will be supported. If compact flags were dropped for this table, drop and re-create " +
+                            "the index.", iterator.metadata().cfName);
+            }
+
             Row data = iterator.staticRow();
             if (index.isStale(data, indexedValue, nowInSec))
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/repair/RepairRunnable.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/repair/RepairRunnable.java b/src/java/org/apache/cassandra/repair/RepairRunnable.java
index 213e5c5..77726d4 100644
--- a/src/java/org/apache/cassandra/repair/RepairRunnable.java
+++ b/src/java/org/apache/cassandra/repair/RepairRunnable.java
@@ -45,6 +45,7 @@ import org.apache.cassandra.dht.Range;
 import org.apache.cassandra.dht.Token;
 import org.apache.cassandra.repair.messages.RepairOption;
 import org.apache.cassandra.service.ActiveRepairService;
+import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.service.QueryState;
 import org.apache.cassandra.service.StorageService;
 import org.apache.cassandra.tracing.TraceKeyspace;
@@ -385,7 +386,7 @@ public class RepairRunnable extends WrappedRunnable implements ProgressEventNoti
 
                 String format = "select event_id, source, activity from %s.%s where session_id = ? and event_id > ? and event_id < ?;";
                 String query = String.format(format, TraceKeyspace.NAME, TraceKeyspace.EVENTS);
-                SelectStatement statement = (SelectStatement) QueryProcessor.parseStatement(query).prepare().statement;
+                SelectStatement statement = (SelectStatement) QueryProcessor.parseStatement(query).prepare(ClientState.forInternalCalls()).statement;
 
                 ByteBuffer sessionIdBytes = ByteBufferUtil.bytes(sessionId);
                 InetAddress source = FBUtilities.getBroadcastAddress();

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/service/ClientState.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/service/ClientState.java b/src/java/org/apache/cassandra/service/ClientState.java
index 32849bc..641d174 100644
--- a/src/java/org/apache/cassandra/service/ClientState.java
+++ b/src/java/org/apache/cassandra/service/ClientState.java
@@ -81,6 +81,12 @@ public class ClientState
     private volatile AuthenticatedUser user;
     private volatile String keyspace;
 
+    /**
+     * Force Compact Tables to be represented as CQL ones for the current client session (simulates
+     * ALTER .. DROP COMPACT STORAGE but only for this session)
+     */
+    private volatile boolean noCompactMode;
+
     private static final QueryHandler cqlQueryHandler;
     static
     {
@@ -253,6 +259,16 @@ public class ClientState
         keyspace = ks;
     }
 
+    public void setNoCompactMode()
+    {
+        this.noCompactMode = true;
+    }
+
+    public boolean isNoCompactMode()
+    {
+        return noCompactMode;
+    }
+
     /**
      * Attempts to login the given user.
      */

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/thrift/ThriftValidation.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/thrift/ThriftValidation.java b/src/java/org/apache/cassandra/thrift/ThriftValidation.java
index 99aed05..6ad791d 100644
--- a/src/java/org/apache/cassandra/thrift/ThriftValidation.java
+++ b/src/java/org/apache/cassandra/thrift/ThriftValidation.java
@@ -105,6 +105,11 @@ public class ThriftValidation
     // To be used when the operation should be authorized whether this is a counter CF or not
     public static CFMetaData validateColumnFamily(String keyspaceName, String cfName) throws org.apache.cassandra.exceptions.InvalidRequestException
     {
+        return validateColumnFamilyWithCompactMode(keyspaceName, cfName, false);
+    }
+
+    public static CFMetaData validateColumnFamilyWithCompactMode(String keyspaceName, String cfName, boolean noCompactMode) throws org.apache.cassandra.exceptions.InvalidRequestException
+    {
         validateKeyspace(keyspaceName);
         if (cfName.isEmpty())
             throw new org.apache.cassandra.exceptions.InvalidRequestException("non-empty table is required");
@@ -113,7 +118,10 @@ public class ThriftValidation
         if (metadata == null)
             throw new org.apache.cassandra.exceptions.InvalidRequestException("unconfigured table " + cfName);
 
-        return metadata;
+        if (metadata.isCompactTable() && noCompactMode)
+            return metadata.asNonCompact();
+        else
+            return metadata;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/src/java/org/apache/cassandra/transport/messages/StartupMessage.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/transport/messages/StartupMessage.java b/src/java/org/apache/cassandra/transport/messages/StartupMessage.java
index 04d8e62..774be6a 100644
--- a/src/java/org/apache/cassandra/transport/messages/StartupMessage.java
+++ b/src/java/org/apache/cassandra/transport/messages/StartupMessage.java
@@ -35,6 +35,7 @@ public class StartupMessage extends Message.Request
 {
     public static final String CQL_VERSION = "CQL_VERSION";
     public static final String COMPRESSION = "COMPRESSION";
+    public static final String NO_COMPACT = "NO_COMPACT";
 
     public static final Message.Codec<StartupMessage> codec = new Message.Codec<StartupMessage>()
     {
@@ -97,6 +98,9 @@ public class StartupMessage extends Message.Request
             }
         }
 
+        if (options.containsKey(NO_COMPACT) && Boolean.parseBoolean(options.get(NO_COMPACT)))
+            state.getClientState().setNoCompactMode();
+
         if (DatabaseDescriptor.getAuthenticator().requireAuthentication())
             return new AuthenticateMessage(DatabaseDescriptor.getAuthenticator().getClass().getName());
         else

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/test/unit/org/apache/cassandra/cql3/ViewTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/ViewTest.java b/test/unit/org/apache/cassandra/cql3/ViewTest.java
index 4a4fe1a..136ae1c 100644
--- a/test/unit/org/apache/cassandra/cql3/ViewTest.java
+++ b/test/unit/org/apache/cassandra/cql3/ViewTest.java
@@ -48,6 +48,8 @@ import org.apache.cassandra.db.Keyspace;
 import org.apache.cassandra.db.SystemKeyspace;
 import org.apache.cassandra.db.compaction.CompactionManager;
 import org.apache.cassandra.db.marshal.AsciiType;
+import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.SyntaxException;
 import org.apache.cassandra.schema.KeyspaceParams;
 import org.apache.cassandra.utils.FBUtilities;
 
@@ -1237,7 +1239,6 @@ public class ViewTest extends CQLTester
         catch (Exception e)
         {
         }
-
     }
 
     @Test
@@ -1376,4 +1377,16 @@ public class ViewTest extends CQLTester
         assertRows(execute("SELECT k, toJson(listval) from mv"),
                    row(0, "[[\"a\", \"1\"], [\"b\", \"2\"], [\"c\", \"3\"]]"));
     }
+
+    @Test(expected = SyntaxException.class)
+    public void emptyViewNameTest() throws Throwable
+    {
+        execute("CREATE MATERIALIZED VIEW \"\" AS SELECT a, b FROM tbl WHERE b IS NOT NULL PRIMARY KEY (b, a)");
+    }
+
+     @Test(expected = SyntaxException.class)
+     public void emptyBaseTableNameTest() throws Throwable
+     {
+         execute("CREATE MATERIALIZED VIEW myview AS SELECT a, b FROM \"\" WHERE b IS NOT NULL PRIMARY KEY (b, a)");
+     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index 8a743ea..6e6af19 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -34,6 +34,7 @@ import org.apache.cassandra.cql3.functions.FunctionName;
 import org.apache.cassandra.cql3.functions.UDFunction;
 import org.apache.cassandra.db.marshal.CollectionType;
 import org.apache.cassandra.exceptions.InvalidRequestException;
+import org.apache.cassandra.exceptions.SyntaxException;
 import org.apache.cassandra.schema.KeyspaceMetadata;
 import org.apache.cassandra.service.ClientState;
 import org.apache.cassandra.transport.Event;
@@ -968,4 +969,28 @@ public class UFTest extends CQLTester
         assertRows(execute("SELECT " + fNameICC + "(empty_int) FROM %s"), row(0));
         assertRows(execute("SELECT " + fNameICN + "(empty_int) FROM %s"), row(new Object[]{ null }));
     }
+
+    @Test(expected = SyntaxException.class)
+    public void testEmptyFunctionName() throws Throwable
+    {
+        execute("CREATE FUNCTION IF NOT EXISTS " + KEYSPACE + ".\"\" (arg int)\n" +
+                "  RETURNS NULL ON NULL INPUT\n" +
+                "  RETURNS int\n" +
+                "  LANGUAGE java\n" +
+                "  AS $$\n" +
+                "    return a;\n" +
+                "  $$");
+    }
+
+    @Test(expected = SyntaxException.class)
+    public void testEmptyArgName() throws Throwable
+    {
+        execute("CREATE FUNCTION IF NOT EXISTS " + KEYSPACE + ".myfn (\"\" int)\n" +
+                "  RETURNS NULL ON NULL INPUT\n" +
+                "  RETURNS int\n" +
+                "  LANGUAGE java\n" +
+                "  AS $$\n" +
+                "    return a;\n" +
+                "  $$");
+    }
 }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java
index dfc2e5e..68c0b8c 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UserTypesTest.java
@@ -24,6 +24,7 @@ import org.junit.Test;
 
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.dht.ByteOrderedPartitioner;
+import org.apache.cassandra.exceptions.*;
 import org.apache.cassandra.service.StorageService;
 
 public class UserTypesTest extends CQLTester
@@ -713,6 +714,25 @@ public class UserTypesTest extends CQLTester
                        row(1, 1,set(userType(1), userType(1, 1), userType(1, 2), userType(2), userType(2, 1)), 2));
     }
 
+    @Test(expected = SyntaxException.class)
+    public void emptyTypeNameTest() throws Throwable
+    {
+        execute("CREATE TYPE \"\" (a int, b int)");
+    }
+
+    @Test(expected = SyntaxException.class)
+    public void emptyFieldNameTest() throws Throwable
+    {
+        execute("CREATE TYPE mytype (\"\" int, b int)");
+    }
+
+    @Test(expected = SyntaxException.class)
+    public void renameColumnToEmpty() throws Throwable
+    {
+        String typeName = createType("CREATE TYPE %s (a int, b int)");
+        execute(String.format("ALTER TYPE %s.%s RENAME b TO \"\"", keyspace(), typeName));
+    }
+
     private String typeWithKs(String type1)
     {
         return keyspace() + '.' + type1;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/6c29ee84/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
----------------------------------------------------------------------
diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
index c48ffe5..b37462f 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
@@ -17,6 +17,9 @@
  */
 package org.apache.cassandra.cql3.validation.operations;
 
+import org.junit.Assert;
+import org.junit.Test;
+
 import org.apache.cassandra.cql3.CQLTester;
 import org.apache.cassandra.db.ColumnFamilyStore;
 import org.apache.cassandra.db.Keyspace;
@@ -24,11 +27,6 @@ import org.apache.cassandra.exceptions.ConfigurationException;
 import org.apache.cassandra.exceptions.InvalidRequestException;
 import org.apache.cassandra.exceptions.SyntaxException;
 import org.apache.cassandra.schema.SchemaKeyspace;
-import org.apache.cassandra.transport.Server;
-import org.apache.cassandra.utils.ByteBufferUtil;
-
-import org.junit.Assert;
-import org.junit.Test;
 
 import static java.lang.String.format;
 import static org.junit.Assert.assertEquals;
@@ -266,6 +264,13 @@ public class AlterTest extends CQLTester
         execute("alter table %s add v int");
     }
 
+    @Test(expected = SyntaxException.class)
+    public void renameToEmptyTest() throws Throwable
+    {
+        createTable("CREATE TABLE %s (k int, c1 int, v int, PRIMARY KEY (k, c1))");
+        execute("ALTER TABLE %s RENAME c1 TO \"\"");
+    }
+
     @Test
     // tests CASSANDRA-9565
     public void testDoubleWith() throws Throwable


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cassandra.apache.org
For additional commands, e-mail: commits-help@cassandra.apache.org