mirror of https://github.com/apache/cassandra
Allow dropping COMPACT STORAGE flag
Patch by Alex Petrov; reviewed by Sylvain Lebresne for CASSANDRA-10857.
This commit is contained in:
parent
b8697441d7
commit
6c29ee84a2
17
NEWS.txt
17
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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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]");
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -17,33 +17,39 @@
|
|||
*/
|
||||
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.apache.cassandra.cql3.*;
|
||||
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.compaction.CompactionManager;
|
||||
import org.apache.cassandra.db.partitions.*;
|
||||
import org.apache.cassandra.db.rows.*;
|
||||
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;
|
||||
|
||||
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.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.rows.Row;
|
||||
import org.apache.cassandra.schema.KeyspaceMetadata;
|
||||
import org.apache.cassandra.service.ClientState;
|
||||
import org.apache.cassandra.utils.FBUtilities;
|
||||
|
||||
/**
|
||||
* A View copies data from a base table into a view table which can be queried independently from the
|
||||
* base. Every update which targets the base table must be fed through the {@link ViewManager} to ensure
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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))
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -104,6 +104,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())
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
}
|
|
@ -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" +
|
||||
" $$");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,525 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.cassandra.cql3.validation.operations;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.config.ColumnDefinition;
|
||||
import org.apache.cassandra.cql3.ColumnSpecification;
|
||||
import org.apache.cassandra.cql3.UntypedResultSet;
|
||||
import org.apache.cassandra.db.Keyspace;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.db.marshal.AsciiType;
|
||||
import org.apache.cassandra.db.marshal.BytesType;
|
||||
import org.apache.cassandra.db.marshal.CompositeType;
|
||||
import org.apache.cassandra.db.marshal.EmptyType;
|
||||
import org.apache.cassandra.db.marshal.Int32Type;
|
||||
import org.apache.cassandra.db.marshal.MapType;
|
||||
import org.apache.cassandra.db.marshal.UTF8Type;
|
||||
import org.apache.cassandra.locator.SimpleStrategy;
|
||||
import org.apache.cassandra.thrift.Cassandra;
|
||||
import org.apache.cassandra.thrift.CfDef;
|
||||
import org.apache.cassandra.thrift.Column;
|
||||
import org.apache.cassandra.thrift.ColumnDef;
|
||||
import org.apache.cassandra.thrift.ColumnOrSuperColumn;
|
||||
import org.apache.cassandra.thrift.ColumnParent;
|
||||
import org.apache.cassandra.thrift.IndexType;
|
||||
import org.apache.cassandra.thrift.KsDef;
|
||||
import org.apache.cassandra.thrift.Mutation;
|
||||
import org.apache.cassandra.thrift.SuperColumn;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
import static org.apache.cassandra.thrift.ConsistencyLevel.ONE;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class DropCompactStorageThriftTest extends ThriftCQLTester
|
||||
{
|
||||
@Test
|
||||
public void thriftCreatedTableTest() throws Throwable
|
||||
{
|
||||
final String KEYSPACE = "thrift_created_table_test_ks";
|
||||
final String TABLE = "test_table_1";
|
||||
|
||||
CfDef cfDef = new CfDef().setDefault_validation_class(Int32Type.instance.toString())
|
||||
.setKey_validation_class(AsciiType.instance.toString())
|
||||
.setComparator_type(AsciiType.instance.toString())
|
||||
.setColumn_metadata(Arrays.asList(new ColumnDef(ByteBufferUtil.bytes("col1"),
|
||||
AsciiType.instance.toString())
|
||||
.setIndex_name("col1Index")
|
||||
.setIndex_type(IndexType.KEYS),
|
||||
new ColumnDef(ByteBufferUtil.bytes("col2"),
|
||||
AsciiType.instance.toString())
|
||||
.setIndex_name("col2Index")
|
||||
.setIndex_type(IndexType.KEYS)))
|
||||
.setKeyspace(KEYSPACE)
|
||||
.setName(TABLE);
|
||||
|
||||
KsDef ksDef = new KsDef(KEYSPACE,
|
||||
SimpleStrategy.class.getName(),
|
||||
Arrays.asList(cfDef));
|
||||
ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1"));
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.system_add_keyspace(ksDef);
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("col1"), ByteBufferUtil.bytes("val1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("col2"), ByteBufferUtil.bytes("val2")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("dynamicKey1"), ByteBufferUtil.bytes(100)),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("dynamicKey2"), ByteBufferUtil.bytes(200)),
|
||||
ONE);
|
||||
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(AsciiType.instance, resultSet, "key");
|
||||
assertColumnType(AsciiType.instance, resultSet, "column1");
|
||||
assertColumnType(Int32Type.instance, resultSet, "value");
|
||||
assertColumnType(AsciiType.instance, resultSet, "col1");
|
||||
assertColumnType(AsciiType.instance, resultSet, "col2");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "dynamicKey1", "val1", "val2", 100),
|
||||
row("key1", "dynamicKey2", "val1", "val2", 200));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftStaticCompatTableTest() throws Throwable
|
||||
{
|
||||
String KEYSPACE = keyspace();
|
||||
String TABLE = createTable("CREATE TABLE %s (key ascii PRIMARY KEY, val ascii) WITH COMPACT STORAGE");
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("val"), ByteBufferUtil.bytes("val1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("dynamicKey1"), ByteBufferUtil.bytes("dynamicValue1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("dynamicKey2"), ByteBufferUtil.bytes("dynamicValue2")),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(AsciiType.instance, resultSet, "key");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "column1");
|
||||
assertColumnType(AsciiType.instance, resultSet, "val");
|
||||
assertColumnType(BytesType.instance, resultSet, "value");
|
||||
|
||||
// Values are interpreted as bytes by default:
|
||||
assertRows(resultSet,
|
||||
row("key1", "dynamicKey1", "val1", ByteBufferUtil.bytes("dynamicValue1")),
|
||||
row("key1", "dynamicKey2", "val1", ByteBufferUtil.bytes("dynamicValue2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSparseCompactTableIndex() throws Throwable
|
||||
{
|
||||
createTable("CREATE TABLE %s (key ascii PRIMARY KEY, val ascii) WITH COMPACT STORAGE");
|
||||
|
||||
// Indexes are allowed only on the sparse compact tables
|
||||
createIndex("CREATE INDEX ON %s(val)");
|
||||
for (int i = 0; i < 10; i++)
|
||||
execute("INSERT INTO %s (key, val) VALUES (?, ?)", Integer.toString(i), Integer.toString(i * 10));
|
||||
|
||||
alterTable("ALTER TABLE %s DROP COMPACT STORAGE");
|
||||
|
||||
assertRows(execute("SELECT * FROM %s WHERE val = '50'"),
|
||||
row("5", null, "50", null));
|
||||
assertRows(execute("SELECT * FROM %s WHERE key = '5'"),
|
||||
row("5", null, "50", null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftCompatTableTest() throws Throwable
|
||||
{
|
||||
String KEYSPACE = keyspace();
|
||||
String TABLE = createTable("CREATE TABLE %s (pkey ascii, ckey ascii, PRIMARY KEY (pkey, ckey)) WITH COMPACT STORAGE");
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckeyValue1"), ByteBufferUtil.EMPTY_BYTE_BUFFER),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckeyValue2"), ByteBufferUtil.EMPTY_BYTE_BUFFER),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(AsciiType.instance, resultSet, "pkey");
|
||||
assertColumnType(AsciiType.instance, resultSet, "ckey");
|
||||
assertColumnType(EmptyType.instance, resultSet, "value");
|
||||
|
||||
// Value is always empty
|
||||
assertRows(resultSet,
|
||||
row("key1", "ckeyValue1", ByteBufferUtil.EMPTY_BYTE_BUFFER),
|
||||
row("key1", "ckeyValue2", ByteBufferUtil.EMPTY_BYTE_BUFFER));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftDenseTableTest() throws Throwable
|
||||
{
|
||||
String KEYSPACE = keyspace();
|
||||
String TABLE = createTable("CREATE TABLE %s (pkey text, ckey text, v text, PRIMARY KEY (pkey, ckey)) WITH COMPACT STORAGE");
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey1"), ByteBufferUtil.bytes("cvalue1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey2"), ByteBufferUtil.bytes("cvalue2")),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(UTF8Type.instance, resultSet, "pkey");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "ckey");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "v");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "ckey1", "cvalue1"),
|
||||
row("key1", "ckey2", "cvalue2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftTableWithIntKey() throws Throwable
|
||||
{
|
||||
final String KEYSPACE = "thrift_table_with_int_key_ks";
|
||||
final String TABLE = "test_table_1";
|
||||
|
||||
ByteBuffer columnName = ByteBufferUtil.bytes("columnname");
|
||||
CfDef cfDef = new CfDef().setDefault_validation_class(UTF8Type.instance.toString())
|
||||
.setKey_validation_class(BytesType.instance.toString())
|
||||
.setComparator_type(BytesType.instance.toString())
|
||||
.setColumn_metadata(Arrays.asList(new ColumnDef(columnName,
|
||||
Int32Type.instance.toString())
|
||||
.setIndex_name("col1Index")
|
||||
.setIndex_type(IndexType.KEYS)))
|
||||
.setKeyspace(KEYSPACE)
|
||||
.setName(TABLE);
|
||||
|
||||
KsDef ksDef = new KsDef(KEYSPACE,
|
||||
SimpleStrategy.class.getName(),
|
||||
Arrays.asList(cfDef));
|
||||
ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1"));
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.system_add_keyspace(ksDef);
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(columnName, ByteBufferUtil.bytes(100)),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
|
||||
assertEquals(resultSet.metadata()
|
||||
.stream()
|
||||
.filter((cs) -> cs.name.toString().equals(BytesType.instance.getString(columnName)))
|
||||
.findFirst()
|
||||
.get().type,
|
||||
Int32Type.instance);
|
||||
|
||||
assertRows(resultSet,
|
||||
row(UTF8Type.instance.decompose("key1"), null, 100, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftCompatTableWithSupercolumnsTest() throws Throwable
|
||||
{
|
||||
final String KEYSPACE = "thrift_compact_table_with_supercolumns_test";
|
||||
final String TABLE = "test_table_1";
|
||||
|
||||
CfDef cfDef = new CfDef().setColumn_type("Super")
|
||||
.setSubcomparator_type(Int32Type.instance.toString())
|
||||
.setComparator_type(AsciiType.instance.toString())
|
||||
.setDefault_validation_class(AsciiType.instance.toString())
|
||||
.setKey_validation_class(AsciiType.instance.toString())
|
||||
.setKeyspace(KEYSPACE)
|
||||
.setName(TABLE);
|
||||
|
||||
KsDef ksDef = new KsDef(KEYSPACE,
|
||||
SimpleStrategy.class.getName(),
|
||||
Arrays.asList(cfDef));
|
||||
ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1"));
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.system_add_keyspace(ksDef);
|
||||
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
Mutation mutation = new Mutation();
|
||||
ColumnOrSuperColumn csoc = new ColumnOrSuperColumn();
|
||||
csoc.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val1"),
|
||||
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(1), ByteBufferUtil.bytes("value1")),
|
||||
getColumnForInsert(ByteBufferUtil.bytes(2), ByteBufferUtil.bytes("value2")),
|
||||
getColumnForInsert(ByteBufferUtil.bytes(3), ByteBufferUtil.bytes("value3")))));
|
||||
mutation.setColumn_or_supercolumn(csoc);
|
||||
|
||||
Mutation mutation2 = new Mutation();
|
||||
ColumnOrSuperColumn csoc2 = new ColumnOrSuperColumn();
|
||||
csoc2.setSuper_column(getSuperColumnForInsert(ByteBufferUtil.bytes("val2"),
|
||||
Arrays.asList(getColumnForInsert(ByteBufferUtil.bytes(4), ByteBufferUtil.bytes("value7")),
|
||||
getColumnForInsert(ByteBufferUtil.bytes(5), ByteBufferUtil.bytes("value8")),
|
||||
getColumnForInsert(ByteBufferUtil.bytes(6), ByteBufferUtil.bytes("value9")))));
|
||||
mutation2.setColumn_or_supercolumn(csoc2);
|
||||
|
||||
client.batch_mutate(Collections.singletonMap(ByteBufferUtil.bytes("key1"),
|
||||
Collections.singletonMap(TABLE, Arrays.asList(mutation, mutation2))),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(AsciiType.instance, resultSet, "key");
|
||||
assertColumnType(AsciiType.instance, resultSet, "column1");
|
||||
assertColumnType(MapType.getInstance(Int32Type.instance, AsciiType.instance, true), resultSet, "");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "val1", map(1, "value1", 2, "value2", 3, "value3")),
|
||||
row("key1", "val2", map(4, "value7", 5, "value8", 6, "value9")));
|
||||
|
||||
assertRows(execute(String.format("SELECT \"\" FROM %s.%s;", KEYSPACE, TABLE)),
|
||||
row(map(1, "value1", 2, "value2", 3, "value3")),
|
||||
row(map(4, "value7", 5, "value8", 6, "value9")));
|
||||
|
||||
assertInvalidMessage("Range deletions are not supported for specific columns",
|
||||
String.format("DELETE \"\" FROM %s.%s WHERE key=?;", KEYSPACE, TABLE),
|
||||
"key1");
|
||||
|
||||
execute(String.format("TRUNCATE %s.%s;", KEYSPACE, TABLE));
|
||||
|
||||
execute(String.format("INSERT INTO %s.%s (key, column1, \"\") VALUES (?, ?, ?);", KEYSPACE, TABLE),
|
||||
"key3", "val1", map(7, "value7", 8, "value8"));
|
||||
|
||||
assertRows(execute(String.format("SELECT \"\" FROM %s.%s;", KEYSPACE, TABLE)),
|
||||
row(map(7, "value7", 8, "value8")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void thriftCreatedTableWithCompositeColumnsTest() throws Throwable
|
||||
{
|
||||
final String KEYSPACE = "thrift_created_table_with_composites_test_ks";
|
||||
final String TABLE = "test_table_1";
|
||||
|
||||
CompositeType type = CompositeType.getInstance(AsciiType.instance, AsciiType.instance, AsciiType.instance);
|
||||
CfDef cfDef = new CfDef().setDefault_validation_class(AsciiType.instance.toString())
|
||||
.setComparator_type(type.toString())
|
||||
.setKey_validation_class(AsciiType.instance.toString())
|
||||
.setKeyspace(KEYSPACE)
|
||||
.setName(TABLE);
|
||||
|
||||
KsDef ksDef = new KsDef(KEYSPACE,
|
||||
SimpleStrategy.class.getName(),
|
||||
Arrays.asList(cfDef));
|
||||
ksDef.setStrategy_options(Collections.singletonMap("replication_factor", "1"));
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.system_add_keyspace(ksDef);
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(type.decompose("a", "b", "c"), ByteBufferUtil.bytes("val1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(type.decompose("d", "e", "f"), ByteBufferUtil.bytes("val2")),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
|
||||
assertColumnType(AsciiType.instance, resultSet, "key");
|
||||
assertColumnType(AsciiType.instance, resultSet, "column1");
|
||||
assertColumnType(AsciiType.instance, resultSet, "column2");
|
||||
assertColumnType(AsciiType.instance, resultSet, "column3");
|
||||
assertColumnType(AsciiType.instance, resultSet, "value");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "a", "b", "c", "val1"),
|
||||
row("key1", "d", "e", "f", "val2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compactTableWithoutClusteringKeyTest() throws Throwable
|
||||
{
|
||||
String KEYSPACE = keyspace();
|
||||
String TABLE = createTable("CREATE TABLE %s (pkey text PRIMARY KEY, s1 text, s2 text) WITH COMPACT STORAGE");
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey1"), ByteBufferUtil.bytes("val1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey2"), ByteBufferUtil.bytes("val2")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("s1"), ByteBufferUtil.bytes("s1Val")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("s2"), ByteBufferUtil.bytes("s2Val")),
|
||||
ONE);
|
||||
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
|
||||
assertColumnType(UTF8Type.instance, resultSet, "pkey");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "s1");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "s2");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "column1");
|
||||
assertColumnType(BytesType.instance, resultSet, "value");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "ckey1", "s1Val", "s2Val", ByteBufferUtil.bytes("val1")),
|
||||
row("key1", "ckey2", "s1Val", "s2Val", ByteBufferUtil.bytes("val2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void denseTableTestTest() throws Throwable
|
||||
{
|
||||
String KEYSPACE = keyspace();
|
||||
String TABLE = createTable("CREATE TABLE %s (pkey text PRIMARY KEY, s text) WITH COMPACT STORAGE");
|
||||
|
||||
Cassandra.Client client = getClient();
|
||||
client.set_keyspace(KEYSPACE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey1"), ByteBufferUtil.bytes("val1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("ckey2"), ByteBufferUtil.bytes("val2")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("s"), ByteBufferUtil.bytes("sval1")),
|
||||
ONE);
|
||||
|
||||
client.insert(UTF8Type.instance.decompose("key1"),
|
||||
new ColumnParent(TABLE),
|
||||
getColumnForInsert(ByteBufferUtil.bytes("s"), ByteBufferUtil.bytes("sval2")),
|
||||
ONE);
|
||||
|
||||
// `s` becomes static, `column1` becomes a clustering key, `value` becomes visible
|
||||
execute(String.format("ALTER TABLE %s.%s DROP COMPACT STORAGE;", KEYSPACE, TABLE));
|
||||
UntypedResultSet resultSet = execute(String.format("select * from %s.%s",
|
||||
KEYSPACE, TABLE));
|
||||
assertColumnType(UTF8Type.instance, resultSet, "pkey");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "s");
|
||||
assertColumnType(UTF8Type.instance, resultSet, "column1");
|
||||
assertColumnType(BytesType.instance, resultSet, "value");
|
||||
|
||||
assertRows(resultSet,
|
||||
row("key1", "ckey1", "sval2", ByteBufferUtil.bytes("val1")),
|
||||
row("key1", "ckey2", "sval2", ByteBufferUtil.bytes("val2")));
|
||||
}
|
||||
|
||||
private Column getColumnForInsert(ByteBuffer columnName, ByteBuffer value)
|
||||
{
|
||||
Column column = new Column();
|
||||
column.setName(columnName);
|
||||
column.setValue(value);
|
||||
column.setTimestamp(System.currentTimeMillis());
|
||||
return column;
|
||||
}
|
||||
|
||||
private SuperColumn getSuperColumnForInsert(ByteBuffer columnName, List<Column> columns)
|
||||
{
|
||||
SuperColumn column = new SuperColumn();
|
||||
column.setName(columnName);
|
||||
for (Column c : columns)
|
||||
column.addToColumns(c);
|
||||
return column;
|
||||
}
|
||||
|
||||
private static void assertColumnType(AbstractType t, UntypedResultSet resultSet, String columnName)
|
||||
{
|
||||
for (ColumnSpecification columnSpecification : resultSet.metadata())
|
||||
{
|
||||
if (columnSpecification.name.toString().equals(columnName))
|
||||
{
|
||||
assertEquals(t, columnSpecification.type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fail(String.format("Could not find a column with name '%s'", columnName));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue