blob: c8060be4a4b9b4a5e78edde14a61c76e8d9f3561 [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.
*/
/*
* Direct Field Access Optimizations Test
*
* Tests for optimizations that directly access agtype fields without
* using the full iterator machinery or binary search:
*
* 1. fill_agtype_value_no_copy() - Read-only access without memory allocation
* 2. compare_agtype_scalar_containers() - Fast path for scalar comparisons
* 3. Direct pairs[0] access for vertex/edge id comparison
* 4. Fast path in get_one_agtype_from_variadic_args()
*/
LOAD 'age';
SET search_path TO ag_catalog;
SELECT create_graph('direct_access');
--
-- Section 1: Scalar Comparison Fast Path Tests
--
-- These tests exercise the compare_agtype_scalar_containers() fast path
-- which uses fill_agtype_value_no_copy() for read-only comparisons.
--
-- Integer comparisons
SELECT * FROM cypher('direct_access', $$
RETURN 1 < 2, 2 > 1, 1 = 1, 1 <> 2
$$) AS (lt agtype, gt agtype, eq agtype, ne agtype);
SELECT * FROM cypher('direct_access', $$
RETURN 100 < 50, 100 > 50, 100 = 100, 100 <> 100
$$) AS (lt agtype, gt agtype, eq agtype, ne agtype);
-- Float comparisons
SELECT * FROM cypher('direct_access', $$
RETURN 1.5 < 2.5, 2.5 > 1.5, 1.5 = 1.5, 1.5 <> 2.5
$$) AS (lt agtype, gt agtype, eq agtype, ne agtype);
-- String comparisons (tests no-copy string pointer)
SELECT * FROM cypher('direct_access', $$
RETURN 'abc' < 'abd', 'abd' > 'abc', 'abc' = 'abc', 'abc' <> 'abd'
$$) AS (lt agtype, gt agtype, eq agtype, ne agtype);
SELECT * FROM cypher('direct_access', $$
RETURN 'hello world' < 'hello worlds', 'test' > 'TEST'
$$) AS (lt agtype, gt agtype);
-- Boolean comparisons
SELECT * FROM cypher('direct_access', $$
RETURN false < true, true > false, true = true, false <> true
$$) AS (lt agtype, gt agtype, eq agtype, ne agtype);
-- Null comparisons
SELECT * FROM cypher('direct_access', $$
RETURN null = null, null <> null
$$) AS (eq agtype, ne agtype);
-- Mixed numeric type comparisons (integer vs float)
SELECT * FROM cypher('direct_access', $$
RETURN 1 < 1.5, 2.0 > 1, 1.0 = 1
$$) AS (lt agtype, gt agtype, eq agtype);
-- Numeric type comparisons
SELECT * FROM cypher('direct_access', $$
RETURN 1.234::numeric < 1.235::numeric,
1.235::numeric > 1.234::numeric,
1.234::numeric = 1.234::numeric
$$) AS (lt agtype, gt agtype, eq agtype);
--
-- Section 2: ORDER BY Tests (exercises comparison fast path)
--
-- ORDER BY uses compare_agtype_containers_orderability which now has
-- a fast path for scalar comparisons.
--
-- Integer ORDER BY
SELECT * FROM cypher('direct_access', $$
UNWIND [5, 3, 8, 1, 9, 2, 7, 4, 6] AS n
RETURN n ORDER BY n
$$) AS (n agtype);
SELECT * FROM cypher('direct_access', $$
UNWIND [5, 3, 8, 1, 9, 2, 7, 4, 6] AS n
RETURN n ORDER BY n DESC
$$) AS (n agtype);
-- String ORDER BY
SELECT * FROM cypher('direct_access', $$
UNWIND ['banana', 'apple', 'cherry', 'date'] AS s
RETURN s ORDER BY s
$$) AS (s agtype);
-- Float ORDER BY
SELECT * FROM cypher('direct_access', $$
UNWIND [3.14, 2.71, 1.41, 1.73] AS f
RETURN f ORDER BY f
$$) AS (f agtype);
-- Boolean ORDER BY
SELECT * FROM cypher('direct_access', $$
UNWIND [true, false, true, false] AS b
RETURN b ORDER BY b
$$) AS (b agtype);
--
-- Section 3: Vertex/Edge Direct ID Access Tests
--
-- These tests exercise the direct pairs[0] access optimization for
-- extracting graphid from vertices and edges during comparison.
--
-- Create test data
SELECT * FROM cypher('direct_access', $$
CREATE (a:Person {name: 'Alice', age: 30}),
(b:Person {name: 'Bob', age: 25}),
(c:Person {name: 'Charlie', age: 35}),
(d:Person {name: 'Diana', age: 28}),
(e:Person {name: 'Eve', age: 32}),
(a)-[:KNOWS {since: 2020}]->(b),
(b)-[:KNOWS {since: 2019}]->(c),
(c)-[:KNOWS {since: 2021}]->(d),
(d)-[:KNOWS {since: 2018}]->(e),
(e)-[:KNOWS {since: 2022}]->(a)
$$) AS (result agtype);
-- Test max() on vertices (uses compare_agtype_scalar_values with AGTV_VERTEX)
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person)
RETURN max(p)
$$) AS (max_vertex agtype);
-- Test min() on vertices
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person)
RETURN min(p)
$$) AS (min_vertex agtype);
-- Test max() on edges (uses compare_agtype_scalar_values with AGTV_EDGE)
SELECT * FROM cypher('direct_access', $$
MATCH ()-[r:KNOWS]->()
RETURN max(r)
$$) AS (max_edge agtype);
-- Test min() on edges
SELECT * FROM cypher('direct_access', $$
MATCH ()-[r:KNOWS]->()
RETURN min(r)
$$) AS (min_edge agtype);
-- ORDER BY on vertices (uses direct id comparison)
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person)
RETURN p.name ORDER BY p
$$) AS (name agtype);
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person)
RETURN p.name ORDER BY p DESC
$$) AS (name agtype);
-- ORDER BY on edges
SELECT * FROM cypher('direct_access', $$
MATCH ()-[r:KNOWS]->()
RETURN r.since ORDER BY r
$$) AS (since agtype);
-- Vertex comparison in WHERE
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person), (b:Person)
WHERE a < b
RETURN a.name, b.name
$$) AS (a_name agtype, b_name agtype);
--
-- Section 4: Fast Path for get_one_agtype_from_variadic_args
--
-- These tests exercise the fast path that bypasses extract_variadic_args
-- when the argument is already agtype.
--
-- Direct agtype comparison operators (use the fast path)
SELECT * FROM cypher('direct_access', $$
RETURN 42 = 42, 42 <> 43, 42 < 100, 42 > 10
$$) AS (eq agtype, ne agtype, lt agtype, gt agtype);
-- Arithmetic operators (also use the fast path)
SELECT * FROM cypher('direct_access', $$
RETURN 10 + 5, 10 - 5, 10 * 5, 10 / 5
$$) AS (add agtype, sub agtype, mul agtype, div agtype);
-- String functions that take agtype args
SELECT * FROM cypher('direct_access', $$
RETURN toUpper('hello'), toLower('WORLD'), size('test')
$$) AS (upper agtype, lower agtype, sz agtype);
-- Type checking functions
SELECT * FROM cypher('direct_access', $$
RETURN toInteger('42'), toFloat('3.14'), toString(42)
$$) AS (int_val agtype, float_val agtype, str_val agtype);
--
-- Section 5: Direct Field Access for Accessor Functions
--
-- These tests exercise the direct field access macros in id(), start_id(),
-- end_id(), label(), and properties() functions.
--
-- Test id() on vertices (uses AGTYPE_VERTEX_GET_ID macro - index 0)
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person {name: 'Alice'})
RETURN id(p)
$$) AS (vertex_id agtype);
-- Test id() on edges (uses AGTYPE_EDGE_GET_ID macro - index 0)
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
RETURN id(r)
$$) AS (edge_id agtype);
-- Test start_id() on edges (uses AGTYPE_EDGE_GET_START_ID macro - index 3)
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
RETURN start_id(r), id(a)
$$) AS (start_id agtype, alice_id agtype);
-- Test end_id() on edges (uses AGTYPE_EDGE_GET_END_ID macro - index 2)
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
RETURN end_id(r), id(b)
$$) AS (end_id agtype, bob_id agtype);
-- Test label() on vertices (uses AGTYPE_VERTEX_GET_LABEL macro - index 1)
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person {name: 'Alice'})
RETURN label(p)
$$) AS (vertex_label agtype);
-- Test label() on edges (uses AGTYPE_EDGE_GET_LABEL macro - index 1)
SELECT * FROM cypher('direct_access', $$
MATCH ()-[r:KNOWS]->()
RETURN DISTINCT label(r)
$$) AS (edge_label agtype);
-- Test properties() on vertices (uses AGTYPE_VERTEX_GET_PROPERTIES macro - index 2)
SELECT * FROM cypher('direct_access', $$
MATCH (p:Person {name: 'Alice'})
RETURN properties(p)
$$) AS (vertex_props agtype);
-- Test properties() on edges (uses AGTYPE_EDGE_GET_PROPERTIES macro - index 4)
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person {name: 'Bob'})
RETURN properties(r)
$$) AS (edge_props agtype);
-- Combined accessor test - verify all fields are accessible
SELECT * FROM cypher('direct_access', $$
MATCH (a:Person {name: 'Alice'})-[r:KNOWS]->(b:Person)
RETURN id(a), label(a), properties(a).name,
id(r), start_id(r), end_id(r), label(r), properties(r).since,
id(b), label(b), properties(b).name
$$) AS (a_id agtype, a_label agtype, a_name agtype,
r_id agtype, r_start agtype, r_end agtype, r_label agtype, r_since agtype,
b_id agtype, b_label agtype, b_name agtype);
--
-- Section 6: Mixed Comparisons and Edge Cases
--
-- Array comparisons (should NOT use scalar fast path)
SELECT * FROM cypher('direct_access', $$
RETURN [1,2,3] = [1,2,3], [1,2,3] < [1,2,4]
$$) AS (eq agtype, lt agtype);
-- Object comparisons (should NOT use scalar fast path)
SELECT * FROM cypher('direct_access', $$
RETURN {a:1, b:2} = {a:1, b:2}
$$) AS (eq agtype);
-- Large integer comparisons
SELECT * FROM cypher('direct_access', $$
RETURN 9223372036854775807 > 9223372036854775806,
-9223372036854775808 < -9223372036854775807
$$) AS (big_gt agtype, neg_lt agtype);
-- Empty string comparison
SELECT * FROM cypher('direct_access', $$
RETURN '' < 'a', '' = ''
$$) AS (lt agtype, eq agtype);
-- Special float values
SELECT * FROM cypher('direct_access', $$
RETURN 0.0 = -0.0
$$) AS (zero_eq agtype);
--
-- Cleanup
--
SELECT drop_graph('direct_access', true);