@@ -522,6 +522,35 @@ private async Task InternalCreateCollectionAsync(bool ifNotExists, CancellationT
522522 // Prepare the SQL commands.
523523 using var batch = connection . CreateBatch ( ) ;
524524
525+ // First, check if the pgvector extension is already installed in PostgreSQL, and then install it if not.
526+ // Note that we do a separate check before doing CREATE EXTENSION IF EXISTS in order to know if it was actually created,
527+ // since in that case we must also must call ReloadTypesAsync() at the Npgsql level
528+ batch . BatchCommands . Add ( new NpgsqlBatchCommand ( "SELECT EXISTS(SELECT * FROM pg_extension WHERE extname='vector')" ) ) ;
529+ batch . BatchCommands . Add ( new NpgsqlBatchCommand ( "CREATE EXTENSION IF NOT EXISTS vector" ) ) ;
530+
531+ bool extensionAlreadyExisted ;
532+
533+ try
534+ {
535+ extensionAlreadyExisted = ( bool ) ( await batch . ExecuteScalarAsync ( cancellationToken ) . ConfigureAwait ( false ) ) ! ;
536+ }
537+ catch ( PostgresException e ) when ( e . SqlState == PostgresErrorCodes . UniqueViolation )
538+ {
539+ // CREATE EXTENSION IF NOT EXISTS is not atomic in PG, so concurrent sessions doing this at the same time
540+ // may trigger a unique constraint violation. We ignore it and interpret it to mean that the extension
541+ // already exists.
542+ extensionAlreadyExisted = true ;
543+ }
544+
545+ if ( ! extensionAlreadyExisted )
546+ {
547+ await connection . ReloadTypesAsync ( ) . ConfigureAwait ( false ) ;
548+ }
549+
550+ batch . BatchCommands . Clear ( ) ;
551+
552+ // Now create the table and any indexes.
553+ // Note that this must be done in a separate batch/transaction as the creation of the extension above.
525554 batch . BatchCommands . Add (
526555 new NpgsqlBatchCommand ( PostgresSqlBuilder . BuildCreateTableSql ( this . _schema , this . Name , this . _model , pgVersion , ifNotExists ) ) ) ;
527556
0 commit comments