@@ -172,6 +172,108 @@ func TestCreateConstraint(t *testing.T) {
172
172
}, testutils .CheckViolationErrorCode )
173
173
},
174
174
},
175
+ {
176
+ name : "create unique constraint on single column where nulls not distinct" ,
177
+ minPgMajorVersion : 15 ,
178
+ migrations : []migrations.Migration {
179
+ {
180
+ Name : "01_add_table" ,
181
+ Operations : migrations.Operations {
182
+ & migrations.OpCreateTable {
183
+ Name : "users" ,
184
+ Columns : []migrations.Column {
185
+ {
186
+ Name : "id" ,
187
+ Type : "serial" ,
188
+ Pk : true ,
189
+ },
190
+ {
191
+ Name : "name" ,
192
+ Type : "varchar(255)" ,
193
+ Nullable : true ,
194
+ },
195
+ },
196
+ },
197
+ },
198
+ },
199
+ {
200
+ Name : "02_create_constraint" ,
201
+ Operations : migrations.Operations {
202
+ & migrations.OpCreateConstraint {
203
+ Name : "unique_name" ,
204
+ Table : "users" ,
205
+ Type : "unique" ,
206
+ Columns : []string {"name" },
207
+ Up : map [string ]string {
208
+ "name" : "random()" ,
209
+ },
210
+ Down : map [string ]string {
211
+ "name" : "name" ,
212
+ },
213
+ NullsNotDistinct : true ,
214
+ },
215
+ },
216
+ },
217
+ },
218
+ afterStart : func (t * testing.T , db * sql.DB , schema string ) {
219
+ // The index has been created on the underlying table.
220
+ IndexUniqueNullsNotDistinctMustExist (t , db , schema , "users" , "unique_name" )
221
+
222
+ // Inserting values into the old schema that violate uniqueness should succeed.
223
+ MustInsert (t , db , schema , "01_add_table" , "users" , map [string ]string {
224
+ "name" : "alice" ,
225
+ })
226
+ MustInsert (t , db , schema , "01_add_table" , "users" , map [string ]string {
227
+ "name" : "alice" ,
228
+ })
229
+ // NULLs are considered distinct, so this succeeds.
230
+ MustInsert (t , db , schema , "01_add_table" , "users" , map [string ]string {
231
+ "id" : "300" ,
232
+ })
233
+ MustInsert (t , db , schema , "01_add_table" , "users" , map [string ]string {
234
+ "id" : "301" ,
235
+ })
236
+
237
+ // Inserting values into the new schema that violate uniqueness should fail.
238
+ MustInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
239
+ "id" : "102" ,
240
+ })
241
+ MustNotInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
242
+ "id" : "103" ,
243
+ }, testutils .UniqueViolationErrorCode )
244
+ },
245
+ afterRollback : func (t * testing.T , db * sql.DB , schema string ) {
246
+ // The index has been dropped from the the underlying table.
247
+ IndexMustNotExist (t , db , schema , "users" , "uniue_name" )
248
+
249
+ // Functions, triggers and temporary columns are dropped.
250
+ TableMustBeCleanedUp (t , db , schema , "users" , "name" )
251
+ },
252
+ afterComplete : func (t * testing.T , db * sql.DB , schema string ) {
253
+ // Functions, triggers and temporary columns are dropped.
254
+ TableMustBeCleanedUp (t , db , schema , "users" , "name" )
255
+
256
+ // The index is transferred to a constraint.
257
+ UniqueNullsNotDistinctConstraintMustExist (t , db , schema , "users" , "unique_name" )
258
+
259
+ // Inserting values into the new schema that violate uniqueness should fail.
260
+ MustInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
261
+ "name" : "carol" ,
262
+ })
263
+ MustNotInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
264
+ "name" : "carol" ,
265
+ }, testutils .UniqueViolationErrorCode )
266
+
267
+ // Inserting values into the new schema that violate uniqueness should fail.
268
+ // Uniqueness violated because NULLs are not distinct.
269
+ MustInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
270
+ "id" : "200" ,
271
+ })
272
+ MustNotInsert (t , db , schema , "02_create_constraint" , "users" , map [string ]string {
273
+ "id" : "201" ,
274
+ }, testutils .UniqueViolationErrorCode )
275
+ },
276
+ },
175
277
{
176
278
name : "create unique constraint on multiple columns" ,
177
279
migrations : []migrations.Migration {
0 commit comments