[ 
https://issues.apache.org/jira/browse/CASSANDRA-21745?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Nadav Har'El updated CASSANDRA-21745:
-------------------------------------
    Description: 
In CQL, a value of almost any type can be an "empty value" - a zero-length 
value, which is different from null. For most non-string types (numbers, UUIDs, 
dates, ...) this is a historical accident that makes no sense, and as 
CASSANDRA-8354 explains, it is a nuisance. Users shouldn't be able to write 
such values by accident - but currently, an empty string {{""}} written where a 
value of a non-string type is expected is sometimes silently accepted as an 
empty value, and sometimes rejected, depending on the type and on how the value 
is written.

All the results below were tested on Cassandra 5.0.9 and 6.0-alpha2, with 
identical results.
h3. INSERT JSON and fromJson()

INSERT JSON and the fromJson() function accept a JSON string for many 
non-string types, e.g., "123" for an {{{}int{}}}. With a table having one 
column of each type, we wrote an empty string to each column {{v}} with these 
two statements:
{code:java}
INSERT INTO t JSON '{"k": 1, "v": ""}';
INSERT INTO t (k, v) VALUES (1, fromJson('""'));
{code}
The results:
||Type||INSERT JSON with ""||fromJson('""')||
|int, bigint, boolean, decimal, double, float, uuid, timeuuid, inet, 
timestamp|accepted (empty value)|accepted (empty value)|
|smallint, tinyint, duration|accepted (empty value)|server error 
(RuntimeException, see below)|
|varint|InvalidRequest ("Value '' is not a valid representation of a varint 
value")|FunctionFailure|
|blob, date, time|InvalidRequest|FunctionFailure|

The server errors for smallint, tinyint and duration happen because fromJson() 
returns an empty value, which these types don't accept, so FunctionCall's check 
of the return value throws a RuntimeException ("Return of function 
system.fromjson : (text) -> smallint () is not a valid value for its declared 
return type smallint") - an instance of CASSANDRA-18484.
h3. CQL string literals

The same inconsistency exists also for plain CQL string literals. The 
non-string types date, time, inet and timestamp accept a string literal (e.g., 
'2024-01-01' for a date), but an empty string literal is rejected for date and 
time, and accepted for inet and timestamp:
{code:java}
CREATE TABLE t (k int PRIMARY KEY, d date, t time, i inet, ts timestamp);
INSERT INTO t (k, d) VALUES (1, '');   -- InvalidRequest: Unable to coerce '' 
to a formatted date (long)
INSERT INTO t (k, t) VALUES (1, '');   -- InvalidRequest: (TimeType) Unable to 
coerce '' to a formatted time (long)
INSERT INTO t (k, i) VALUES (1, '');   -- accepted, writes an empty value
INSERT INTO t (k, ts) VALUES (1, '');  -- accepted, writes an empty value
{code}
h3. Suggested fix

An empty string is not a valid integer, float, UUID, boolean, IP address, 
timestamp, etc. I suggest that an empty string be rejected as a value of every 
type except the string types (ascii and text/varchar), consistently in INSERT 
JSON, fromJson() and CQL string literals - as Cassandra already does for some 
of these types (varint, blob, date, time). The user most likely made a mistake, 
and almost certainly didn't intend to write an empty value. An empty value can 
still be written deliberately, e.g., with {{blobAsInt(0x)}} or by binding an 
empty value.

  was:
In CQL, a value of almost any type can be an "empty value" - a zero-length 
value, which is different from null. For most non-string types (numbers, UUIDs, 
dates, ...) this is a historical accident that makes no sense, and as 
CASSANDRA-8354 explains, it is a nuisance. Users shouldn't be able to write 
such values by accident - but currently, an empty string {{""}} written where a 
value of a non-string type is expected is sometimes silently accepted as an 
empty value, and sometimes rejected, depending on the type and on how the value 
is written.

All the results below were tested on Cassandra 5.0.9 and 6.0-alpha2, with 
identical results.

h3. INSERT JSON and fromJson()

INSERT JSON and the fromJson() function accept a JSON string for many 
non-string types, e.g., "123" for an {{int}}. With a table having one column of 
each type, using {{INSERT INTO t JSON '{"k": 1, "v": ""}'}} and {{INSERT INTO t 
(k, v) VALUES (1, fromJson('""'))}}:

||Type||INSERT JSON with ""||fromJson('""')||
|int, bigint, boolean, decimal, double, float, uuid, timeuuid, inet, 
timestamp|accepted (empty value)|accepted (empty value)|
|smallint, tinyint, duration|accepted (empty value)|server error 
(RuntimeException, see below)|
|varint|InvalidRequest ("Value '' is not a valid representation of a varint 
value")|FunctionFailure|
|blob, date, time|InvalidRequest|FunctionFailure|

The server errors for smallint, tinyint and duration happen because fromJson() 
returns an empty value, which these types don't accept, so FunctionCall's check 
of the return value throws a RuntimeException ("Return of function 
system.fromjson : (text) -> smallint () is not a valid value for its declared 
return type smallint") - an instance of CASSANDRA-18484.

h3. CQL string literals

The same inconsistency exists also for plain CQL string literals. The 
non-string types date, time, inet and timestamp accept a string literal (e.g., 
'2024-01-01' for a date), but an empty string literal is rejected for date and 
time, and accepted for inet and timestamp:

{code}
CREATE TABLE t (k int PRIMARY KEY, d date, t time, i inet, ts timestamp);
INSERT INTO t (k, d) VALUES (1, '');   -- InvalidRequest: Unable to coerce '' 
to a formatted date (long)
INSERT INTO t (k, t) VALUES (1, '');   -- InvalidRequest: (TimeType) Unable to 
coerce '' to a formatted time (long)
INSERT INTO t (k, i) VALUES (1, '');   -- accepted, writes an empty value
INSERT INTO t (k, ts) VALUES (1, '');  -- accepted, writes an empty value
{code}

h3. Suggested fix

An empty string is not a valid integer, float, UUID, boolean, IP address, 
timestamp, etc. I suggest that an empty string be rejected as a value of every 
type except the string types (ascii and text/varchar), consistently in INSERT 
JSON, fromJson() and CQL string literals - as Cassandra already does for some 
of these types (varint, blob, date, time). The user most likely made a mistake, 
and almost certainly didn't intend to write an empty value. An empty value can 
still be written deliberately, e.g., with {{blobAsInt(0x)}} or by binding an 
empty value.



> Empty string inconsistently accepted as a value of non-string types (INSERT 
> JSON, fromJson(), string literals)
> --------------------------------------------------------------------------------------------------------------
>
>                 Key: CASSANDRA-21745
>                 URL: https://issues.apache.org/jira/browse/CASSANDRA-21745
>             Project: Apache Cassandra
>          Issue Type: Bug
>            Reporter: Nadav Har'El
>            Priority: Normal
>
> In CQL, a value of almost any type can be an "empty value" - a zero-length 
> value, which is different from null. For most non-string types (numbers, 
> UUIDs, dates, ...) this is a historical accident that makes no sense, and as 
> CASSANDRA-8354 explains, it is a nuisance. Users shouldn't be able to write 
> such values by accident - but currently, an empty string {{""}} written where 
> a value of a non-string type is expected is sometimes silently accepted as an 
> empty value, and sometimes rejected, depending on the type and on how the 
> value is written.
> All the results below were tested on Cassandra 5.0.9 and 6.0-alpha2, with 
> identical results.
> h3. INSERT JSON and fromJson()
> INSERT JSON and the fromJson() function accept a JSON string for many 
> non-string types, e.g., "123" for an {{{}int{}}}. With a table having one 
> column of each type, we wrote an empty string to each column {{v}} with these 
> two statements:
> {code:java}
> INSERT INTO t JSON '{"k": 1, "v": ""}';
> INSERT INTO t (k, v) VALUES (1, fromJson('""'));
> {code}
> The results:
> ||Type||INSERT JSON with ""||fromJson('""')||
> |int, bigint, boolean, decimal, double, float, uuid, timeuuid, inet, 
> timestamp|accepted (empty value)|accepted (empty value)|
> |smallint, tinyint, duration|accepted (empty value)|server error 
> (RuntimeException, see below)|
> |varint|InvalidRequest ("Value '' is not a valid representation of a varint 
> value")|FunctionFailure|
> |blob, date, time|InvalidRequest|FunctionFailure|
> The server errors for smallint, tinyint and duration happen because 
> fromJson() returns an empty value, which these types don't accept, so 
> FunctionCall's check of the return value throws a RuntimeException ("Return 
> of function system.fromjson : (text) -> smallint () is not a valid value for 
> its declared return type smallint") - an instance of CASSANDRA-18484.
> h3. CQL string literals
> The same inconsistency exists also for plain CQL string literals. The 
> non-string types date, time, inet and timestamp accept a string literal 
> (e.g., '2024-01-01' for a date), but an empty string literal is rejected for 
> date and time, and accepted for inet and timestamp:
> {code:java}
> CREATE TABLE t (k int PRIMARY KEY, d date, t time, i inet, ts timestamp);
> INSERT INTO t (k, d) VALUES (1, '');   -- InvalidRequest: Unable to coerce '' 
> to a formatted date (long)
> INSERT INTO t (k, t) VALUES (1, '');   -- InvalidRequest: (TimeType) Unable 
> to coerce '' to a formatted time (long)
> INSERT INTO t (k, i) VALUES (1, '');   -- accepted, writes an empty value
> INSERT INTO t (k, ts) VALUES (1, '');  -- accepted, writes an empty value
> {code}
> h3. Suggested fix
> An empty string is not a valid integer, float, UUID, boolean, IP address, 
> timestamp, etc. I suggest that an empty string be rejected as a value of 
> every type except the string types (ascii and text/varchar), consistently in 
> INSERT JSON, fromJson() and CQL string literals - as Cassandra already does 
> for some of these types (varint, blob, date, time). The user most likely made 
> a mistake, and almost certainly didn't intend to write an empty value. An 
> empty value can still be written deliberately, e.g., with {{blobAsInt(0x)}} 
> or by binding an empty value.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to