@@ -88,23 +88,125 @@ fn amhandler(_fcinfo: pg_sys::FunctionCallInfo) -> PgBox<pg_sys::IndexAmRoutine>
88
88
amroutine. into_pg_boxed ( )
89
89
}
90
90
91
+ // Background on system catalog state needed to understand the SQL for idempotent install/upgrade
92
+ // ----------------------------------------------------------------------------------------------
93
+ //
94
+ // When installing from scratch, we execute:
95
+ //
96
+ // CREATE OPERATOR CLASS vector_cosine_ops
97
+ // DEFAULT FOR TYPE vector USING diskann AS
98
+ // OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
99
+ // FUNCTION 1 distance_type_cosine();
100
+ //
101
+ // This creates the following system catalog state:
102
+ //
103
+ // (1) A row in pg_opclass for vector_l2_ops and diskann:
104
+ //
105
+ // oid | opcmethod | opcname | opcnamespace | opcowner | opcfamily | opcintype | opcdefault | opckeytype
106
+ // -------+-----------+-------------------+--------------+----------+-----------+-----------+------------+------------
107
+ // 17722 | 17718 | vector_cosine_ops | 2200 | 10 | 17721 | 17389 | t | 0
108
+ //
109
+ // Note: opcmethod is the oid of the access method (diskann) already in pg_am.
110
+ // Also: note that opcdefault is t, which means that this is the default operator class for the type.
111
+ //
112
+ // (2) A row in pg_amop for the <=> operator:
113
+ // oid | amopfamily | amoplefttype | amoprighttype | amopstrategy | amoppurpose | amopopr | amopmethod | amopsortfamily
114
+ // -------+------------+--------------+---------------+--------------+-------------+---------+------------+----------------
115
+ // 17723 | 17721 | 17389 | 17389 | 1 | o | 17438 | 17718 | 1970
116
+ //
117
+ // (3) A row in pg_amproc for the distance_type_cosine function:
118
+ //
119
+ // oid | amprocfamily | amproclefttype | amprocrighttype | amprocnum | amproc
120
+ // -------+--------------+----------------+-----------------+-----------+----------------------
121
+ // 17724 | 17721 | 17389 | 17389 | 1 | distance_type_cosine
122
+ //
123
+ // Version 0.4.0 contained the same SQL as above, but without the FUNCTION 1 part:
124
+ //
125
+ // CREATE OPERATOR CLASS vector_cosine_ops
126
+ // DEFAULT FOR TYPE vector USING diskann AS
127
+ // OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops;
128
+ //
129
+ // Thus, when upgrading from 0.4.0 to 0.5.0, we need to add the appropriate entry in `pg_amproc`.
130
+ //
131
+ // Similarly, here is the sample system catalog state created by:
132
+ //
133
+ // CREATE OPERATOR CLASS vector_l2_ops
134
+ // FOR TYPE vector USING diskann AS
135
+ // OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
136
+ // FUNCTION 1 distance_type_l2();
137
+ //
138
+ // (1) A row in pg_opclass for vector_l2_ops and diskann:
139
+ //
140
+ // oid | opcmethod | opcname | opcnamespace | opcowner | opcfamily | opcintype | opcdefault | opckeytype
141
+ // -------+-----------+---------------+--------------+----------+-----------+-----------+------------+------------
142
+ // 17726 | 17718 | vector_l2_ops | 2200 | 10 | 17725 | 17389 | f | 0
143
+ //
144
+ // Note: opcmethod is the oid of the access method (diskann) already in pg_am.
145
+ // Also: note that opcdefault is f, which means that this is not the default operator class for the type.
146
+ //
147
+ // (2) A row in pg_amop for the <-> operator:
148
+ //
149
+ // oid | amopfamily | amoplefttype | amoprighttype | amopstrategy | amoppurpose | amopopr | amopmethod | amopsortfamily
150
+ // -------+------------+--------------+---------------+--------------+-------------+---------+------------+----------------
151
+ // 17727 | 17725 | 17389 | 17389 | 1 | o | 17436 | 17718 | 1970
152
+ //
153
+ // (3) A row in pg_amproc for the distance_type_l2 function:
154
+ //
155
+ // oid | amprocfamily | amproclefttype | amprocrighttype | amprocnum | amproc
156
+ // -------+--------------+----------------+-----------------+-----------+------------------
157
+ // 17728 | 17725 | 17389 | 17389 | 1 | distance_type_l2
158
+ //
159
+ // However, the situation is easier for upgrade. Version 0.4.0 did not contain support for the L2 distance, so we can
160
+ // just run the CREATE OPERATOR CLASS statement above to add the L2 distance support.
161
+
91
162
// This SQL is made idempotent so that we can use the same script for the installation and the upgrade.
92
163
extension_sql ! (
93
164
r#"
94
- DROP OPERATOR CLASS IF EXISTS vector_cosine_ops USING diskann;
95
-
96
- CREATE OPERATOR CLASS vector_cosine_ops
97
- DEFAULT FOR TYPE vector USING diskann AS
98
- OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
99
- FUNCTION 1 distance_type_cosine();
100
-
101
-
102
- DROP OPERATOR CLASS IF EXISTS vector_l2_ops USING diskann;
103
-
104
- CREATE OPERATOR CLASS vector_l2_ops
105
- FOR TYPE vector USING diskann AS
106
- OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
107
- FUNCTION 1 distance_type_l2();
165
+ DO $$
166
+ DECLARE
167
+ c int;
168
+ d int;
169
+ BEGIN
170
+ -- Has cosine operator class been installed previously?
171
+ SELECT count(*)
172
+ INTO c
173
+ FROM pg_catalog.pg_opclass c
174
+ WHERE c.opcname = 'vector_cosine_ops'
175
+ AND c.opcmethod = (SELECT oid FROM pg_catalog.pg_am am WHERE am.amname = 'diskann');
176
+
177
+ -- Has L2 operator class been installed previously?
178
+ SELECT count(*)
179
+ INTO d
180
+ FROM pg_catalog.pg_opclass c
181
+ WHERE c.opcname = 'vector_l2_ops'
182
+ AND c.opcmethod = (SELECT oid FROM pg_catalog.pg_am am WHERE am.amname = 'diskann');
183
+
184
+ IF c = 0 THEN
185
+ -- Fresh install from scratch
186
+ CREATE OPERATOR CLASS vector_cosine_ops DEFAULT
187
+ FOR TYPE vector USING diskann AS
188
+ OPERATOR 1 <=> (vector, vector) FOR ORDER BY float_ops,
189
+ FUNCTION 1 distance_type_cosine();
190
+
191
+ CREATE OPERATOR CLASS vector_l2_ops
192
+ FOR TYPE vector USING diskann AS
193
+ OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
194
+ FUNCTION 1 distance_type_l2();
195
+ ELSIF d = 0 THEN
196
+ -- Upgrade to add L2 distance support and update cosine opclass to
197
+ -- include the distance_type_cosine function
198
+ INSERT INTO pg_amproc (amprocfamily, amproclefttype, amprocrighttype, amprocnum, amproc)
199
+ SELECT c.opcfamily, c.opcintype, c.opcintype, 1, 'distance_type_l2'
200
+ FROM pg_opclass c, pg_am a
201
+ WHERE a.oid = c.opcmethod AND c.opcname = 'vector_l2_ops' AND a.amname = 'diskann';
202
+
203
+ CREATE OPERATOR CLASS vector_l2_ops
204
+ FOR TYPE vector USING diskann AS
205
+ OPERATOR 1 <-> (vector, vector) FOR ORDER BY float_ops,
206
+ FUNCTION 1 distance_type_l2();
207
+ END IF;
208
+ END;
209
+ $$;
108
210
"# ,
109
211
name = "diskann_ops_operator" ,
110
212
requires = [ amhandler, distance_type_cosine, distance_type_l2]
0 commit comments