blob: b1f1354bc299fa6f1c7374e42a08a276c4626422 [file] [log] [blame]
/*
* 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.functions;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.junit.Test;
import org.apache.cassandra.cql3.CQLTester;
import org.quicktheories.WithQuickTheories;
public class LengthFctsTest extends CQLTester implements WithQuickTheories
{
@Test
public void testOctetLengthNonStrings()
{
createTable("CREATE TABLE %s (a tinyint primary key,"
+ " b smallint,"
+ " c int,"
+ " d bigint,"
+ " e float,"
+ " f double,"
+ " g decimal,"
+ " h varint,"
+ " i int)");
execute("INSERT INTO %s (a, b, c, d, e, f, g, h) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
(byte) 1, (short) 2, 3, 4L, 5.2F, 6.3, BigDecimal.valueOf(6.3), BigInteger.valueOf(4));
assertRows(execute("SELECT OCTET_LENGTH(a), " +
"OCTET_LENGTH(b), " +
"OCTET_LENGTH(c), " +
"OCTET_LENGTH(d), " +
"OCTET_LENGTH(e), " +
"OCTET_LENGTH(f), " +
"OCTET_LENGTH(g), " +
"OCTET_LENGTH(h), " +
"OCTET_LENGTH(i) FROM %s"),
row(1, 2, 4, 8, 4, 8, 5, 1, null));
}
@Test
public void testStringLengthUTF8() throws Throwable
{
createTable("CREATE TABLE %s (key text primary key, value blob)");
// UTF-8 7 codepoint, 21 byte encoded string
String key = "こんにちは世界";
execute("INSERT INTO %s (key) VALUES (?)", key);
assertRows(execute("SELECT LENGTH(key), OCTET_LENGTH(key), OCTET_LENGTH(value) FROM %s where key = ?", key),
row(7, 21, null));
// Quickly check that multiple arguments leads to an exception as expected
assertInvalidMessage("Invalid number of arguments in call to function system.length",
"SELECT LENGTH(key, value) FROM %s where key = 'こんにちは世界'");
assertInvalidMessage("Invalid call to function octet_length, none of its type signatures match",
"SELECT OCTET_LENGTH(key, value) FROM %s where key = 'こんにちは世界'");
}
@Test
public void testOctetLengthStringFuzz()
{
createTable("CREATE TABLE %s (key text primary key, value blob)");
qt().withExamples(1024).forAll(strings().allPossible().ofLengthBetween(32, 100)).checkAssert(
(randString) -> {
int sLen = randString.length();
byte[] randBytes = randString.getBytes(StandardCharsets.UTF_8);
// UTF-8 length (code unit count) and byte length are often
// different. Spot checked a few of these, and they are different
// most of the time in this test - but testing that reproducibly
// requires seeding that would decrease the test power...
execute("INSERT INTO %s (key, value) VALUES (?, ?)", randString, ByteBuffer.wrap(randBytes));
assertRows(execute("SELECT LENGTH(key), OCTET_LENGTH(key), OCTET_LENGTH(value) FROM %s where key = ?", randString),
row(sLen, randBytes.length, randBytes.length));
});
}
}