age icon indicating copy to clipboard operation
age copied to clipboard

Error on relationship when source vertex in EXISTS() has alias

Open TropicalPenguin opened this issue 3 years ago • 11 comments

Describe the bug

Given the basic data set up: CREATE (:A)-[:incs]->(:C)

The following succeeds: MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-()) RETURN a,c

But simply adding an alias for the source vertex makes the query fail: MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c

With the following error: pq: attribute 1 of type test.incs has wrong type

I have confirmed that both matches succeed with identical output in Neo4j sandbox.

How are you accessing AGE (Command line, driver, etc.)?

  • Command line
  • Golang driver

What data setup do we need to do?

Either run the above commands in psql, or try the following short test golang program:

package main

import (
	"database/sql"
	"fmt"

	_ "github.com/lib/pq"
	"github.com/rhizome-ai/apache-age-go/age"
)

func main() {
	dsn := "postgres://postgres:[email protected]:5434/postgres?sslmode=disable"
	db, err := sql.Open("postgres", dsn)
	if err != nil {
		panic(err)
	}

	graphName := "test"

	_, err = age.GetReady(db, graphName)
	if err != nil {
		panic(err)
	}

	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	var row []age.Entity

	cursor, err := age.ExecCypher(tx, graphName, 0, "CREATE (:A)-[:incs]->(:C)")
	if err != nil {
		panic(err)
	}

	cursor, err = age.ExecCypher(tx, graphName, 2, "MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-()) RETURN a,c")
	if err != nil {
		panic(err)
	}

	for cursor.Next() {
		row, err = cursor.GetRow()

		for rowIdx, v := range row {
			fmt.Println(rowIdx, len(row), v)
		}
	}
	fmt.Printf("\n")

	cursor, err = age.ExecCypher(tx, graphName, 2, "MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c")
	if err != nil {
		panic(err)
	}
	for cursor.Next() {
		row, err = cursor.GetRow()

		for rowIdx, v := range row {
			fmt.Println(rowIdx, len(row), v)
		}
	}

        _, err = tx.Exec(fmt.Sprintf("SELECT drop_graph('%s', true);", graphName))
	        if err != nil {
		        panic(err)
	        }
	        tx.Commit()
        }

What is the necessary configuration info needed?

  • N/A

What is the command that caused the error?

SELECT * from cypher('test', $$
  MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c
$$) as (a agtype, c agtype);
ERROR:  attribute 1 of type test.incs has wrong type

Expected behavior The two queries should return the same result, without error.

Environment (please complete the following information):

  • Version: 1.0.0

Additional context N/A

TropicalPenguin avatar Oct 23 '22 05:10 TropicalPenguin

Yep, verified this is an issue with 1.1.0 -

psql-11.5-5432-pgsql=# drop extension age cascade; create extension age; load 'age'; set search_path TO ag_catalog;
ERROR:  extension "age" does not exist
CREATE EXTENSION
LOAD
SET
psql-11.5-5432-pgsql=# SELECT * FROM create_graph('test');
NOTICE:  graph "test" has been created
 create_graph
--------------

(1 row)

psql-11.5-5432-pgsql=# SELECT * FROM cypher('test', $$ CREATE (:A)-[:incs]->(:C) $$) AS (result agtype);
 result
--------
(0 rows)

psql-11.5-5432-pgsql=# SELECT * FROM cypher('test', $$ MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-()) RETURN a,c $$) AS (a agtype, c agtype);
                                a                                |                                c
-----------------------------------------------------------------+------------------------------------------------------------------
 {"id": 844424930131969, "label": "A", "properties": {}}::vertex | {"id": 1407374883553281, "label": "C", "properties": {}}::vertex
(1 row)

psql-11.5-5432-pgsql=# SELECT * FROM cypher('test', $$ MATCH (a:A) WITH a OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c $$) AS (a agtype, c agtype);
ERROR:  attribute 1 of type test.incs has wrong type
DETAIL:  Table has type graphid, but query expects agtype.
psql-11.5-5432-pgsql=#

We will look into this.

jrgemignani avatar Oct 25 '22 15:10 jrgemignani

This task will be a project for our interns to tackle.

jrgemignani avatar Oct 26 '22 17:10 jrgemignani

Started this task.

rafsun42 avatar Oct 26 '22 18:10 rafsun42

Update regarding the location of the error: The issue may be in the cypher_gram.y file where the EXISTS function is defined.

This query works:

SELECT * FROM cypher('test', $$ OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c $$) AS (a agtype, c agtype);

However when MATCH (a:A) WITH a is added before the cypher query and a is referenced in the parameter of EXISTS function, the query fails. The grammar is probably not defined accurately for this specific pattern.

Anyone who is also working on this issue is welcome to make a comment on this.

rafsun42 avatar Oct 27 '22 16:10 rafsun42

Started the task

PragyanD avatar Oct 28 '22 14:10 PragyanD

Update regarding the location of the error: The issue may be in the cypher_gram.y file where the EXISTS function is defined.

This query works:

SELECT * FROM cypher('test', $$ OPTIONAL MATCH (a)-[:incs]->(c) WHERE EXISTS((c)<-[:incs]-(a)) RETURN a,c $$) AS (a agtype, c agtype);

However when MATCH (a:A) WITH a is added before the cypher query and a is referenced in the parameter of EXISTS function, the query fails. The grammar is probably not defined accurately for this specific pattern.

Anyone who is also working on this issue is welcome to make a comment on this.

Nice catch Rafsun! I'll investigate this interaction further.

PragyanD avatar Oct 28 '22 15:10 PragyanD

@jrgemignani

At cypher_clause.c:3733, the following function is used to retrieve a node's expr:

...
Node *expr = colNameToVar(pstate, node->name, false,
                                          node->location);
...

At cypher_clause.c:4295, the following function is used for the same purpose:

...
transform_entity *entity = find_variable(parent_cpstate, node->name);
...

Both of them takes almost similar argument, could you tell me the difference between them?

rafsun42 avatar Nov 29 '22 00:11 rafsun42

@rafsun42 If you look at what they look through, you'll see that they are not the same.

colNameToVar is for finding a column name and creating a variable from it. foreach(l, pstate->p_namespace)

find_variable is for finding an entity and returning it. Although, it should probably have a more descriptive name. foreach (lc, cpstate->entities)

jrgemignani avatar Nov 29 '22 22:11 jrgemignani

@jrgemignani Opened PR #391 for this issue.

rafsun42 avatar Dec 15 '22 18:12 rafsun42

@rafsun42 I have reviewed the patch and added my comments. Once corrected, the patch looks good to go.

jrgemignani avatar Dec 15 '22 19:12 jrgemignani

@TropicalPenguin Can you please update us on this issue?

eyab avatar Aug 24 '23 02:08 eyab