Skip to content

Commit 3247728

Browse files
Add support for external extensions (#2088)
- This commit allows the functions from external extensions to be called from the Cypher queries, provided that typecast is available for args and return type of that function. The extension should be installed and the function should be in the search path. - Added cypher typecast for pgvector datatypes, its not a direct cast. It casts agtype to text and then text to vector. - Added regression tests for pg_trgm, fuzzystrmatch and pgvector extensions. pg_trgm is another extension that is used for fuzzy string matching. These regression test are extra tests that need to be explicitly added to the regression suite. Following command can be used to do so: make installcheck EXTRA_TESTS="pg_trgm pgvector fuzzystrmatch" - Updated CI to run the extra tests for the extensions.
1 parent bd7dd4c commit 3247728

File tree

11 files changed

+1191
-272
lines changed

11 files changed

+1191
-272
lines changed

.github/workflows/installcheck.yaml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,37 @@ jobs:
2222
path: ~/pg16
2323
key: ${{ runner.os }}-v1-pg16-${{ env.PG_COMMIT_HASH }}
2424

25-
- name: Install PostgreSQL 16
25+
- name: Install PostgreSQL 16 and some extensions
2626
if: steps.pg16cache.outputs.cache-hit != 'true'
2727
run: |
2828
git clone --depth 1 --branch REL_16_STABLE git://git.postgresql.org/git/postgresql.git ~/pg16source
2929
cd ~/pg16source
3030
./configure --prefix=$HOME/pg16 CFLAGS="-std=gnu99 -ggdb -O0" --enable-cassert
3131
make install -j$(nproc) > /dev/null
32+
cd contrib
33+
cd fuzzystrmatch
34+
make PG_CONFIG=$HOME/pg16/bin/pg_config install -j$(nproc) > /dev/null
35+
cd ../pg_trgm
36+
make PG_CONFIG=$HOME/pg16/bin/pg_config install -j$(nproc) > /dev/null
3237
3338
- uses: actions/checkout@v3
3439

35-
- name: Build
40+
- name: Build AGE
3641
id: build
3742
run: |
3843
make PG_CONFIG=$HOME/pg16/bin/pg_config install -j$(nproc)
44+
45+
- name: Pull and build pgvector
46+
id: pgvector
47+
run: |
48+
git clone https://github.com/pgvector/pgvector.git
49+
cd pgvector
50+
make PG_CONFIG=$HOME/pg16/bin/pg_config install -j$(nproc) > /dev/null
3951
4052
- name: Regression tests
4153
id: regression_tests
4254
run: |
43-
make PG_CONFIG=$HOME/pg16/bin/pg_config installcheck
55+
make PG_CONFIG=$HOME/pg16/bin/pg_config installcheck EXTRA_TESTS="pgvector fuzzystrmatch pg_trgm"
4456
continue-on-error: true
4557

4658
- name: Dump regression test errors

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,13 @@ REGRESS = scan \
112112
name_validation \
113113
jsonb_operators \
114114
list_comprehension \
115-
map_projection \
116-
drop
115+
map_projection
116+
117+
ifneq ($(EXTRA_TESTS),)
118+
REGRESS += $(EXTRA_TESTS)
119+
endif
120+
121+
REGRESS += drop
117122

118123
srcdir=`pwd`
119124

regress/expected/expr.out

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8767,25 +8767,6 @@ SELECT * FROM cypher('issue_1988', $$
87678767
{"id": 844424930131969, "label": "Part", "properties": {"set": "set", "match": "match", "merge": "merge", "create": "create", "delete": "delete", "part_num": 123}}::vertex
87688768
(4 rows)
87698769

8770-
--
8771-
-- Test external extension function logic for fuzzystrmatch
8772-
--
8773-
SELECT * FROM create_graph('fuzzystrmatch');
8774-
NOTICE: graph "fuzzystrmatch" has been created
8775-
create_graph
8776-
--------------
8777-
8778-
(1 row)
8779-
8780-
-- These should fail with extension not installed
8781-
SELECT * FROM cypher('fuzzystrmatch', $$ RETURN soundex("hello world!") $$) AS (result agtype);
8782-
ERROR: extension fuzzystrmatch is not installed for function soundex
8783-
LINE 1: SELECT * FROM cypher('fuzzystrmatch', $$ RETURN soundex("hel...
8784-
^
8785-
SELECT * FROM cypher('fuzzystrmatch', $$ RETURN difference("hello world!", "hello world!") $$) AS (result agtype);
8786-
ERROR: extension fuzzystrmatch is not installed for function difference
8787-
LINE 1: SELECT * FROM cypher('fuzzystrmatch', $$ RETURN difference("...
8788-
^
87898770
--
87908771
-- Issue 2093: Server crashes when executing SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]'));
87918772
--
@@ -8804,16 +8785,6 @@ SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]'));
88048785
--
88058786
-- Cleanup
88068787
--
8807-
SELECT * FROM drop_graph('fuzzystrmatch', true);
8808-
NOTICE: drop cascades to 2 other objects
8809-
DETAIL: drop cascades to table fuzzystrmatch._ag_label_vertex
8810-
drop cascades to table fuzzystrmatch._ag_label_edge
8811-
NOTICE: graph "fuzzystrmatch" has been dropped
8812-
drop_graph
8813-
------------
8814-
8815-
(1 row)
8816-
88178788
SELECT * FROM drop_graph('issue_1988', true);
88188789
NOTICE: drop cascades to 4 other objects
88198790
DETAIL: drop cascades to table issue_1988._ag_label_vertex

regress/expected/fuzzystrmatch.out

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
LOAD 'age';
20+
SET search_path=ag_catalog;
21+
SELECT create_graph('graph');
22+
NOTICE: graph "graph" has been created
23+
create_graph
24+
--------------
25+
26+
(1 row)
27+
28+
-- Should error out
29+
SELECT * FROM cypher('graph', $$ RETURN soundex("hello") $$) AS (n agtype);
30+
ERROR: function soundex does not exist
31+
LINE 1: SELECT * FROM cypher('graph', $$ RETURN soundex("hello") $$)...
32+
^
33+
HINT: If the function is from an external extension, make sure the extension is installed and the function is in the search path.
34+
-- Create the extension in the public schema
35+
CREATE EXTENSION fuzzystrmatch SCHEMA public;
36+
-- Should error out
37+
SELECT * FROM cypher('graph', $$ RETURN soundex("hello") $$) AS (n agtype);
38+
ERROR: function soundex does not exist
39+
LINE 1: SELECT * FROM cypher('graph', $$ RETURN soundex("hello") $$)...
40+
^
41+
HINT: If the function is from an external extension, make sure the extension is installed and the function is in the search path.
42+
-- Should work
43+
SET search_path=ag_catalog, public;
44+
SELECT * FROM cypher('graph', $$ CREATE (:Person {name: "Jane"}),
45+
(:Person {name: "John"}),
46+
(:Person {name: "Jone"}),
47+
(:Person {name: "Jack"}),
48+
(:Person {name: "Jax"}),
49+
(:Person {name: "Jake"}),
50+
(:Person {name: "Julie"}),
51+
(:Person {name: "Julius"}),
52+
(:Person {name: "Jill"}),
53+
(:Person {name: "Jillie"}),
54+
(:Person {name: "Julian"})
55+
$$) AS (n agtype);
56+
n
57+
---
58+
(0 rows)
59+
60+
SELECT * FROM cypher('graph', $$ MATCH (p) return soundex(p.name) $$) AS (n agtype);
61+
n
62+
--------
63+
"J500"
64+
"J500"
65+
"J500"
66+
"J200"
67+
"J200"
68+
"J200"
69+
"J400"
70+
"J420"
71+
"J400"
72+
"J400"
73+
"J450"
74+
(11 rows)
75+
76+
SELECT * FROM cypher('graph', $$ MATCH (p) return levenshtein(p.name, "John") $$) AS (n agtype);
77+
n
78+
---
79+
3
80+
0
81+
2
82+
3
83+
3
84+
3
85+
4
86+
5
87+
3
88+
5
89+
4
90+
(11 rows)
91+
92+
SELECT * FROM cypher('graph', $$ MATCH (p) return difference(p.name, "John") $$) AS (n agtype);
93+
n
94+
---
95+
4
96+
4
97+
4
98+
3
99+
3
100+
3
101+
3
102+
2
103+
3
104+
3
105+
2
106+
(11 rows)
107+
108+
SELECT * FROM cypher('graph', $$ MATCH (p) return metaphone(p.name, 4) $$) AS (n agtype);
109+
n
110+
-------
111+
"JN"
112+
"JN"
113+
"JN"
114+
"JK"
115+
"JKS"
116+
"JK"
117+
"JL"
118+
"JLS"
119+
"JL"
120+
"JL"
121+
"JLN"
122+
(11 rows)
123+
124+
SELECT * FROM cypher('graph', $$ MATCH (p) return dmetaphone(p.name) $$) AS (n agtype);
125+
n
126+
-------
127+
"JN"
128+
"JN"
129+
"JN"
130+
"JK"
131+
"JKS"
132+
"JK"
133+
"JL"
134+
"JLS"
135+
"JL"
136+
"JL"
137+
"JLN"
138+
(11 rows)
139+
140+
-- Difference is basically similarity using soundex, https://www.postgresql.org/docs/current/fuzzystrmatch.html
141+
SELECT * FROM cypher('graph', $$ MATCH (p) return p ORDER BY difference(p.name, "Jon") DESC LIMIT 3$$) AS (n agtype);
142+
n
143+
------------------------------------------------------------------------------------
144+
{"id": 844424930131970, "label": "Person", "properties": {"name": "John"}}::vertex
145+
{"id": 844424930131971, "label": "Person", "properties": {"name": "Jone"}}::vertex
146+
{"id": 844424930131969, "label": "Person", "properties": {"name": "Jane"}}::vertex
147+
(3 rows)
148+
149+
SELECT * FROM cypher('graph', $$ MATCH (p) return p ORDER BY difference(p.name, "Jak") DESC LIMIT 3$$) AS (n agtype);
150+
n
151+
------------------------------------------------------------------------------------
152+
{"id": 844424930131972, "label": "Person", "properties": {"name": "Jack"}}::vertex
153+
{"id": 844424930131973, "label": "Person", "properties": {"name": "Jax"}}::vertex
154+
{"id": 844424930131974, "label": "Person", "properties": {"name": "Jake"}}::vertex
155+
(3 rows)
156+
157+
SELECT * FROM cypher('graph', $$ MATCH (p) return p ORDER BY difference(p.name, "Jil") DESC LIMIT 3$$) AS (n agtype);
158+
n
159+
--------------------------------------------------------------------------------------
160+
{"id": 844424930131975, "label": "Person", "properties": {"name": "Julie"}}::vertex
161+
{"id": 844424930131977, "label": "Person", "properties": {"name": "Jill"}}::vertex
162+
{"id": 844424930131978, "label": "Person", "properties": {"name": "Jillie"}}::vertex
163+
(3 rows)
164+
165+
-- Clean up
166+
SELECT drop_graph('graph', true);
167+
NOTICE: drop cascades to 3 other objects
168+
DETAIL: drop cascades to table graph._ag_label_vertex
169+
drop cascades to table graph._ag_label_edge
170+
drop cascades to table graph."Person"
171+
NOTICE: graph "graph" has been dropped
172+
drop_graph
173+
------------
174+
175+
(1 row)
176+
177+
DROP EXTENSION fuzzystrmatch CASCADE;

regress/expected/pg_trgm.out

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
LOAD 'age';
20+
SET search_path=ag_catalog;
21+
SELECT create_graph('graph');
22+
NOTICE: graph "graph" has been created
23+
create_graph
24+
--------------
25+
26+
(1 row)
27+
28+
-- Should error out
29+
SELECT * FROM cypher('graph', $$ RETURN show_trgm("hello") $$) AS (n agtype);
30+
ERROR: function show_trgm does not exist
31+
LINE 1: SELECT * FROM cypher('graph', $$ RETURN show_trgm("hello") $...
32+
^
33+
HINT: If the function is from an external extension, make sure the extension is installed and the function is in the search path.
34+
-- Create the extension in the public schema
35+
CREATE EXTENSION pg_trgm SCHEMA public;
36+
-- Should error out
37+
SELECT * FROM cypher('graph', $$ RETURN show_trgm("hello") $$) AS (n agtype);
38+
ERROR: function show_trgm does not exist
39+
LINE 1: SELECT * FROM cypher('graph', $$ RETURN show_trgm("hello") $...
40+
^
41+
HINT: If the function is from an external extension, make sure the extension is installed and the function is in the search path.
42+
-- Should work
43+
SET search_path=ag_catalog, public;
44+
SELECT * FROM cypher('graph', $$ CREATE (:Person {name: "Jane"}),
45+
(:Person {name: "John"}),
46+
(:Person {name: "Jone"}),
47+
(:Person {name: "Jack"}),
48+
(:Person {name: "Jax"}),
49+
(:Person {name: "Jake"}),
50+
(:Person {name: "Julie"}),
51+
(:Person {name: "Julius"}),
52+
(:Person {name: "Jill"}),
53+
(:Person {name: "Jillie"}),
54+
(:Person {name: "Julian"})
55+
$$) AS (n agtype);
56+
n
57+
---
58+
(0 rows)
59+
60+
SELECT * FROM cypher('graph', $$ MATCH (p) return show_trgm(p.name) $$) AS (n text[]);
61+
n
62+
-------------------------------------
63+
{" j"," ja",ane,jan,"ne "}
64+
{" j"," jo","hn ",joh,ohn}
65+
{" j"," jo",jon,"ne ",one}
66+
{" j"," ja",ack,"ck ",jac}
67+
{" j"," ja","ax ",jax}
68+
{" j"," ja",ake,jak,"ke "}
69+
{" j"," ju","ie ",jul,lie,uli}
70+
{" j"," ju",ius,jul,liu,uli,"us "}
71+
{" j"," ji",ill,jil,"ll "}
72+
{" j"," ji","ie ",ill,jil,lie,lli}
73+
{" j"," ju","an ",ian,jul,lia,uli}
74+
(11 rows)
75+
76+
SELECT * FROM cypher('graph', $$ MATCH (p) with p, similarity(p.name, "Jon") as sim return p.name, sim ORDER BY sim DESC $$) AS (n agtype, s real);
77+
n | s
78+
----------+------------
79+
"Jone" | 0.5
80+
"John" | 0.2857143
81+
"Jax" | 0.14285715
82+
"Jane" | 0.125
83+
"Jack" | 0.125
84+
"Jake" | 0.125
85+
"Jill" | 0.125
86+
"Julie" | 0.11111111
87+
"Julius" | 0.1
88+
"Julian" | 0.1
89+
"Jillie" | 0.1
90+
(11 rows)
91+
92+
SELECT * FROM cypher('graph', $$ MATCH (p) with p, word_similarity(p.name, "Jon") as sim return p.name, sim ORDER BY sim DESC $$) AS (n agtype, s real);
93+
n | s
94+
----------+------------
95+
"Jone" | 0.6
96+
"John" | 0.4
97+
"Jax" | 0.25
98+
"Jane" | 0.2
99+
"Jack" | 0.2
100+
"Jake" | 0.2
101+
"Jill" | 0.2
102+
"Julie" | 0.16666667
103+
"Julius" | 0.14285715
104+
"Julian" | 0.14285715
105+
"Jillie" | 0.14285715
106+
(11 rows)
107+
108+
-- Clean up
109+
SELECT drop_graph('graph', true);
110+
NOTICE: drop cascades to 3 other objects
111+
DETAIL: drop cascades to table graph._ag_label_vertex
112+
drop cascades to table graph._ag_label_edge
113+
drop cascades to table graph."Person"
114+
NOTICE: graph "graph" has been dropped
115+
drop_graph
116+
------------
117+
118+
(1 row)
119+
120+
DROP EXTENSION pg_trgm CASCADE;

0 commit comments

Comments
 (0)