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/cassandra-3.11 Commit: 6c29ee84a2f62ccd05c328bbaa0c364eb1a7a821 Parents: b869744 Author: Alex Petrov <oleksandr.pet...@gmail.com> Authored: Sat Sep 30 08:56:22 2017 +0200 Committer: Alex Petrov <oleksandr.pet...@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-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org