mirror of https://github.com/apache/cassandra
Merge branch 'cassandra-4.0' into cassandra-4.1
This commit is contained in:
commit
7c7d8f4414
|
|
@ -5,6 +5,7 @@ Merged from 4.0:
|
|||
* Fix BulkLoader ignoring cipher suites options (CASSANDRA-18582)
|
||||
* Migrate Python optparse to argparse (CASSANDRA-17914)
|
||||
Merged from 3.11:
|
||||
* Fix NPE when using udfContext in UDF after a restart of a node (CASSANDRA-18739)
|
||||
Merged from 3.0:
|
||||
* CQLSH emits a warning when the server version doesn't match (CASSANDRA-18745)
|
||||
* Fix missing speculative retries in tablestats (CASSANDRA-18767)
|
||||
|
|
|
|||
|
|
@ -22,12 +22,16 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.google.common.base.Suppliers;
|
||||
|
||||
import org.apache.cassandra.cql3.ColumnIdentifier;
|
||||
import org.apache.cassandra.db.marshal.AbstractType;
|
||||
import org.apache.cassandra.schema.CQLTypeParser;
|
||||
import org.apache.cassandra.schema.KeyspaceMetadata;
|
||||
import org.apache.cassandra.cql3.functions.types.*;
|
||||
import org.apache.cassandra.schema.Schema;
|
||||
import org.apache.cassandra.utils.ByteBufferUtil;
|
||||
|
||||
/**
|
||||
|
|
@ -35,19 +39,25 @@ import org.apache.cassandra.utils.ByteBufferUtil;
|
|||
*/
|
||||
public final class UDFContextImpl implements UDFContext
|
||||
{
|
||||
private final KeyspaceMetadata keyspaceMetadata;
|
||||
private final Map<String, TypeCodec<Object>> byName = new HashMap<>();
|
||||
private final TypeCodec<Object>[] argCodecs;
|
||||
private final TypeCodec<Object> returnCodec;
|
||||
private final String keyspace;
|
||||
|
||||
UDFContextImpl(List<ColumnIdentifier> argNames, TypeCodec<Object>[] argCodecs, TypeCodec<Object> returnCodec,
|
||||
KeyspaceMetadata keyspaceMetadata)
|
||||
/*
|
||||
metadata can not be retrieved within the constructor as the keyspace itself may be being
|
||||
constructed and an NPE will result.
|
||||
*/
|
||||
private final Supplier<KeyspaceMetadata> metadata;
|
||||
|
||||
UDFContextImpl(List<ColumnIdentifier> argNames, TypeCodec<Object>[] argCodecs, TypeCodec<Object> returnCodec, String keyspace)
|
||||
{
|
||||
for (int i = 0; i < argNames.size(); i++)
|
||||
byName.put(argNames.get(i).toString(), argCodecs[i]);
|
||||
this.argCodecs = argCodecs;
|
||||
this.returnCodec = returnCodec;
|
||||
this.keyspaceMetadata = keyspaceMetadata;
|
||||
this.keyspace = keyspace;
|
||||
this.metadata = Suppliers.memoize(() -> Schema.instance.getKeyspaceMetadata(keyspace));
|
||||
}
|
||||
|
||||
public UDTValue newArgUDTValue(String argName)
|
||||
|
|
@ -67,9 +77,9 @@ public final class UDFContextImpl implements UDFContext
|
|||
|
||||
public UDTValue newUDTValue(String udtName)
|
||||
{
|
||||
Optional<org.apache.cassandra.db.marshal.UserType> udtType = keyspaceMetadata.types.get(ByteBufferUtil.bytes(udtName));
|
||||
Optional<org.apache.cassandra.db.marshal.UserType> udtType = metadata.get().types.get(ByteBufferUtil.bytes(udtName));
|
||||
DataType dataType = UDHelper.driverType(udtType.orElseThrow(
|
||||
() -> new IllegalArgumentException("No UDT named " + udtName + " in keyspace " + keyspaceMetadata.name)
|
||||
() -> new IllegalArgumentException("No UDT named " + udtName + " in keyspace " + keyspace)
|
||||
));
|
||||
return newUDTValue(dataType);
|
||||
}
|
||||
|
|
@ -91,7 +101,7 @@ public final class UDFContextImpl implements UDFContext
|
|||
|
||||
public TupleValue newTupleValue(String cqlDefinition)
|
||||
{
|
||||
AbstractType<?> abstractType = CQLTypeParser.parse(keyspaceMetadata.name, cqlDefinition, keyspaceMetadata.types);
|
||||
AbstractType<?> abstractType = CQLTypeParser.parse(keyspace, cqlDefinition, metadata.get().types);
|
||||
DataType dataType = UDHelper.driverType(abstractType);
|
||||
return newTupleValue(dataType);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -234,9 +234,7 @@ public abstract class UDFunction extends AbstractFunction implements ScalarFunct
|
|||
this.argCodecs = UDHelper.codecsFor(argDataTypes);
|
||||
this.returnCodec = UDHelper.codecFor(returnDataType);
|
||||
this.calledOnNullInput = calledOnNullInput;
|
||||
KeyspaceMetadata keyspaceMetadata = Schema.instance.getKeyspaceMetadata(name.keyspace);
|
||||
this.udfContext = new UDFContextImpl(argNames, argCodecs, returnCodec,
|
||||
keyspaceMetadata);
|
||||
this.udfContext = new UDFContextImpl(argNames, argCodecs, returnCodec, name.keyspace);
|
||||
}
|
||||
|
||||
public static UDFunction tryCreate(FunctionName name,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.distributed.test;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.apache.cassandra.distributed.Cluster;
|
||||
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static org.apache.cassandra.distributed.api.ConsistencyLevel.ALL;
|
||||
import static org.apache.cassandra.distributed.shared.AssertUtils.assertRows;
|
||||
import static org.apache.cassandra.distributed.shared.AssertUtils.row;
|
||||
|
||||
public class UDFTest extends TestBaseImpl
|
||||
{
|
||||
@Test
|
||||
public void testUDFContextKeyspaceNotNull() throws Throwable
|
||||
{
|
||||
/*
|
||||
To test the keyspace is not null in the context we call UDFContext.newUDTValue() because it
|
||||
relies on the keyspace not being null.
|
||||
*/
|
||||
String[] createStmts = {
|
||||
"CREATE TABLE " + KEYSPACE + ".current (city text, PRIMARY KEY (city))",
|
||||
"CREATE TYPE IF NOT EXISTS " + KEYSPACE + ".aggst (lt int, ge int)",
|
||||
"CREATE FUNCTION " + KEYSPACE + ".udf_not_null ()\n" +
|
||||
"CALLED ON NULL INPUT\n" +
|
||||
"RETURNS boolean LANGUAGE java AS $$\n" +
|
||||
"udfContext.newUDTValue(\"aggst\");\n" +
|
||||
"return Boolean.TRUE;\n" +
|
||||
"$$;",
|
||||
};
|
||||
|
||||
try (Cluster cluster = init(Cluster.create(1, config -> config.set("enable_user_defined_functions", "true"))))
|
||||
{
|
||||
for (String stmt : createStmts)
|
||||
cluster.schemaChange(stmt);
|
||||
|
||||
cluster.coordinator(1).execute("INSERT INTO " + KEYSPACE + ".current (city) VALUES ('Helsinki')", ALL);
|
||||
|
||||
assertRows(cluster.coordinator(1).execute("SELECT " + KEYSPACE + ".udf_not_null() AS m FROM " + KEYSPACE + ".current", ALL), row(TRUE));
|
||||
|
||||
cluster.get(1).shutdown().get();
|
||||
cluster.get(1).startup();
|
||||
|
||||
assertRows(cluster.coordinator(1).execute("SELECT " + KEYSPACE + ".udf_not_null() AS m FROM " + KEYSPACE + ".current", ALL), row(TRUE));
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue