func TestTransactionClone(t *testing.T) { txn := nonZeroTxn.Clone() fields := util.EqualPtrFields(reflect.ValueOf(nonZeroTxn), reflect.ValueOf(txn), "") sort.Strings(fields) // Verify that the only equal pointer fields after cloning are the ones // listed below. If this test fails, please update the list below and/or // Transaction.Clone(). expFields := []string{ "Intents.EndKey", "Intents.Key", "TxnMeta.ID", "TxnMeta.Key", } if !reflect.DeepEqual(expFields, fields) { t.Fatalf("%s != %s", expFields, fields) } }
func TestDeepCopy(t *testing.T) { testExprs := []string{ "1", "1 + 2", "a = 1", // Bitwise operators. `1 & 3`, `1 | 3`, `1 ^ 3`, // Arithmetic operators. `1 + 1`, `1 - 2`, `3 * 4`, `3.1 % 2.0`, `5 % 3`, `1 + NULL`, `1.1::decimal + 2.4::decimal`, `1.1::decimal - 2.4::decimal`, `1.1::decimal * 2.4::decimal`, `1.1::decimal % 2.4::decimal`, // Division is always done on floats or decimals. `4 / 5`, `1.0 / 0.0`, `-1.0 * (1.0 / 0.0)`, `1.1::decimal / 2.2::decimal`, // Grouping `1 + 2 + (3 * 4)`, // Unary operators. `-3`, `-4.1`, `-6.1::decimal`, // Ones complement operates on signed integers. `~0`, `~0 - 1`, // Hexadecimal numbers. `0xa`, // String concatenation. `'a' || 'b'`, `'a' || (1 + 2)::char`, // Bit shift operators. `1 << 2`, `4 >> 2`, // Boolean expressions. `false AND true`, `false AND NULL`, `false AND false`, `true AND true`, `true AND false`, `true AND NULL`, `NULL AND true`, `NULL AND false`, `NULL AND NULL`, `false OR true`, `false OR NULL`, `false OR false`, `true OR true`, `true OR false`, `true OR NULL`, `NULL OR true`, `NULL OR false`, `NULL OR NULL`, `NOT false`, `NOT true`, `NOT NULL`, // Boolean expressions short-circuit the evaluation. `false AND (a = 1)`, `true OR (a = 1)`, // Comparisons. `0 = 1`, `0 != 1`, `0 < 1`, `0 <= 1`, `0 > 1`, `0 >= 1`, `true = false`, `true != false`, `true < false`, `true <= false`, `true > false`, `true >= false`, `'a' = 'b'`, `'a' != 'b'`, `'a' < 'b'`, `'a' <= 'b'`, `'a' > 'b'`, `'a' >= 'b'`, `'a' >= 'b'`, `'10' > '2'`, `1.1 = 1.2`, `1.1 != 1.2`, `1.1 < 1.2`, `1.1 <= 1.2`, `1.1 > 1.2`, `1.1 >= 1.2`, `1.1::decimal = 1.2::decimal`, `1.1::decimal != 1.2::decimal`, `1.1::decimal < 1.2::decimal`, `1.1::decimal <= 1.2::decimal`, `1.1::decimal > 1.2::decimal`, `1.1::decimal >= 1.2::decimal`, `'2015-10-01'::date = '2015-10-02'::date`, `'2015-10-01'::date != '2015-10-02'::date`, `'2015-10-01'::date < '2015-10-02'::date`, `'2015-10-01'::date <= '2015-10-02'::date`, `'2015-10-01'::date > '2015-10-02'::date`, `'2015-10-01'::date >= '2015-10-02'::date`, `'2015-10-01'::timestamp = '2015-10-02'::timestamp`, `'2015-10-01'::timestamp != '2015-10-02'::timestamp`, `'2015-10-01'::timestamp < '2015-10-02'::timestamp`, `'2015-10-01'::timestamp <= '2015-10-02'::timestamp`, `'2015-10-01'::timestamp > '2015-10-02'::timestamp`, `'2015-10-01'::timestamp >= '2015-10-02'::timestamp`, `'12h2m1s23ms'::interval = '12h2m1s24ms'::interval`, `'12h2m1s23ms'::interval != '12h2m1s24ms'::interval`, `'12h2m1s23ms'::interval < '12h2m1s24ms'::interval`, `'12h2m1s23ms'::interval <= '12h2m1s24ms'::interval`, `'12h2m1s23ms'::interval > '12h2m1s24ms'::interval`, `'12h2m1s23ms'::interval >= '12h2m1s24ms'::interval`, // Comparisons against NULL result in NULL. `0 = NULL`, `NULL = NULL`, // LIKE and NOT LIKE `'TEST' LIKE 'TEST'`, `'TEST' LIKE 'TE%'`, `'TEST' LIKE '%E%'`, `'TEST' LIKE 'TES_'`, `'TEST' LIKE 'TE_%'`, `'TEST' LIKE 'TE_'`, `'TEST' LIKE '%'`, `'TEST' LIKE '%R'`, `'TEST' LIKE 'TESTER'`, `'TEST' LIKE ''`, `'' LIKE ''`, `'T' LIKE '_'`, `'TE' LIKE '_'`, `'TEST' NOT LIKE '%E%'`, `'TEST' NOT LIKE 'TES_'`, `'TEST' NOT LIKE 'TE_'`, // SIMILAR TO and NOT SIMILAR TO `'abc' SIMILAR TO 'abc'`, `'abc' SIMILAR TO 'a'`, `'abc' SIMILAR TO '%(b|d)%'`, `'abc' SIMILAR TO '(b|c)%'`, `'abc' NOT SIMILAR TO '%(b|d)%'`, `'abc' NOT SIMILAR TO '(b|c)%'`, // IS DISTINCT FROM can be used to compare NULLs "safely". `0 IS DISTINCT FROM 0`, `0 IS DISTINCT FROM 1`, `0 IS DISTINCT FROM NULL`, `NULL IS DISTINCT FROM NULL`, `NULL IS DISTINCT FROM 1`, `0 IS NOT DISTINCT FROM 0`, `0 IS NOT DISTINCT FROM 1`, `0 IS NOT DISTINCT FROM NULL`, `NULL IS NOT DISTINCT FROM NULL`, `NULL IS NOT DISTINCT FROM 1`, // IS expressions. `0 IS NULL`, `0 IS NOT NULL`, `NULL IS NULL`, `NULL IS NOT NULL`, `NULL IS UNKNOWN`, `NULL IS NOT UNKNOWN`, `TRUE IS TRUE`, `TRUE IS NOT TRUE`, `FALSE IS TRUE`, `FALSE IS NOT TRUE`, `NULL IS TRUE`, `NULL IS NOT TRUE`, `TRUE IS FALSE`, `TRUE IS NOT FALSE`, `FALSE IS FALSE`, `FALSE IS NOT FALSE`, `NULL IS FALSE`, `NULL IS NOT FALSE`, // IS OF expressions. `TRUE IS OF (BOOL)`, `1 IS OF (INT)`, `1.0 IS OF (FLOAT)`, `1.0::decimal IS OF (DECIMAL)`, `'hello' IS OF (STRING)`, `'hello' IS OF (BYTES)`, `b'hello' IS OF (STRING)`, `b'hello' IS OF (BYTES)`, `'2012-09-21'::date IS OF (DATE)`, `'2010-09-28 12:00:00.1'::timestamp IS OF (TIMESTAMP)`, `'34h'::interval IS OF (INTERVAL)`, `1 IS OF (STRING)`, `1 IS OF (BOOL, INT)`, `1 IS NOT OF (INT)`, `1 IS NOT OF (STRING)`, `1 IS NOT OF (BOOL, INT)`, // Range conditions. `2 BETWEEN 1 AND 3`, `1 NOT BETWEEN 2 AND 3`, `'foo' BETWEEN 'a' AND 'z'`, // Case operator. `CASE WHEN true THEN 1 END`, `CASE WHEN false THEN 1 END`, `CASE WHEN false THEN 1 ELSE 2 END`, `CASE WHEN false THEN 1 WHEN false THEN 2 END`, `CASE 1+1 WHEN 1 THEN 1 WHEN 2 THEN 2 END`, `CASE 1+2 WHEN 1 THEN 1 WHEN 2 THEN 2 ELSE 5 END`, // Row (tuple) comparisons. `ROW(1) = ROW(1)`, `ROW(1, true) = (1, NOT false)`, `(1, 'a') = (1, 'a')`, `(1, 'a' || 1::char) = (1, 'a1')`, `(1+1, (2+2, (3+3))) = (2, (4, (6)))`, `(1, 'a') != (1, 'a')`, `(1, 'a') != (1, 'b')`, // IN and NOT IN expressions. `1 NOT IN (2, 3, 4)`, `1+1 IN (2, 3, 4)`, `'a0' IN ('a'||0::char, 'b'||1::char, 'c'||2::char)`, `'2012-09-21'::date IN ('2012-09-21'::date)`, `'2010-09-28 12:00:00.1'::timestamp IN ('2010-09-28 12:00:00.1'::timestamp)`, `'34h'::interval IN ('34h'::interval)`, `(1,2) IN ((0+1,1+1), (3,4), (5,6))`, `(1, 2) IN ((2, 1), (3, 4))`, // Func expressions. `length('hel'||'lo')`, `lower('HELLO')`, `UPPER('hello')`, // Cast expressions. `true::boolean`, `true::int`, `true::float`, `length(true::text)`, `false::boolean`, `false::int`, `false::float`, `true::decimal`, `false::decimal`, `length(false::text)`, `1::boolean`, `0::boolean`, `1::int`, `1::float`, `1::decimal`, `length(123::text)`, `1.1::boolean`, `0.0::boolean`, `(1.1::decimal)::int`, `(1.9::decimal)::int`, `(1.1::decimal)::float`, `(1.1::decimal)::boolean`, `(0.0::decimal)::boolean`, `1.1::int`, `1.5::int`, `1.9::int`, `2.5::int`, `-1.5::int`, `-2.5::int`, `1.1::float`, `-1e+06`, `-9.99999e+05`, `999999.0`, `1000000.0`, `-1e+06::decimal`, `-9.99999e+05::decimal`, `999999.0::decimal`, `1000000.0::decimal`, `length(1.23::text)`, `'t'::boolean`, `'T'::boolean`, `'true'::boolean`, `'True'::boolean`, `'TRUE'::boolean`, `'1'::boolean`, `'f'::boolean`, `'F'::boolean`, `'false'::boolean`, `'False'::boolean`, `'FALSE'::boolean`, `'0'::boolean`, `'123'::int + 1`, `NULL::int`, `'0x123'::int + 1`, `'0123'::int + 1`, `'1.23'::float + 1.0`, `'hello'::text`, `CAST('123' AS int) + 1`, `CAST(NULL AS int)`, `'hello'::char(2)`, `'hello'::bytes`, `b'hello'::string`, `b'\xff'`, `123::text`, `'2010-09-28'::date`, `'2010-09-28'::timestamp`, `('2010-09-28 12:00:00.1'::timestamp)::date`, `'2010-09-28 12:00:00.1'::timestamp`, `'2010-09-28 12:00:00.1+02:00'::timestamp`, `'2010-09-28 12:00:00.1-07:00'::timestamp`, `('2010-09-28'::date)::timestamp`, `'12h2m1s23ms'::interval`, `1::interval`, `'2010-09-28'::date + 3`, `3 + '2010-09-28'::date`, `'2010-09-28'::date - 3`, `'2010-09-28'::date - '2010-10-21'::date`, `'2010-09-28 12:00:00.1-04:00'::timestamp + '12h2m'::interval`, `'12h2m'::interval + '2010-09-28 12:00:00.1-04:00'::timestamp`, `'2010-09-28 12:00:00.1-04:00'::timestamp - '12h2m'::interval`, `'2010-09-28 12:00:00.1-04:00'::timestamp - '2010-09-28 12:00:00.1+00:00'::timestamp`, `'12h2m1s23ms'::interval + '1h'::interval`, `'12h2m1s23ms'::interval - '1h'::interval`, `'1h'::interval - '12h2m1s23ms'::interval`, `3 * '1h2m'::interval * 3`, `'3h'::interval / 2`, // Conditional expressions. `IF(true, 1, 2/0)`, `IF(false, 1/0, 2)`, `IF(NULL, 1/0, 2)`, `NULLIF(1, 1)`, `NULLIF(1, 2)`, `NULLIF(2, 1)`, `IFNULL(1, 2/0)`, `IFNULL(NULL, 2)`, `IFNULL(1, NULL)`, `IFNULL(NULL, NULL)`, `COALESCE(1, 2, 3, 4/0)`, `COALESCE(NULL, 2, 3, 4/0)`, `COALESCE(NULL, NULL, NULL, 4)`, `COALESCE(NULL, NULL, NULL, NULL)`, } for _, exprStr := range testExprs { expr, err := ParseExprTraditional(exprStr) if err != nil { t.Fatalf("%s: %v", exprStr, err) } exprCopy := expr.DeepCopy() if !reflect.DeepEqual(expr, exprCopy) { t.Fatalf("`%s`: copy not equal: `%s`\n%#v\nvs.%#v\n", expr, exprCopy, expr, exprCopy) } fields := util.EqualPtrFields(reflect.ValueOf(expr), reflect.ValueOf(exprCopy), "") if len(fields) > 0 { t.Fatalf("equal pointer field(s) %s", strings.Join(fields, ",")) } } }