| /* |
| * 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)); |
| }); |
| } |
| } |