Skip to content

Commit d0f02c7

Browse files
committed
Ensure prepared statement is freed when lookupPrimaryKeyColumnNames throws
1 parent 9307ebb commit d0f02c7

1 file changed

Lines changed: 28 additions & 23 deletions

File tree

Sources/CassandraClient/Session.swift

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -812,18 +812,7 @@ extension CassandraClient {
812812
logger.debug("preparing: \(query)")
813813
let future = self.underlying.prepare(query: query)
814814
return future.asNIOFuture(eventLoop: eventLoop).flatMapThrowing { rawPointer in
815-
let pkColumns: [String]
816-
if let tableName = encryptionTable {
817-
pkColumns = try self.lookupPrimaryKeyColumnNames(tableName: tableName)
818-
} else {
819-
pkColumns = []
820-
}
821-
let prepared = CassandraClient.PreparedStatement(
822-
rawPointer: rawPointer,
823-
encryptionTable: encryptionTable,
824-
primaryKeyColumnNames: pkColumns
825-
)
826-
return prepared
815+
try self.makePreparedStatement(rawPointer: rawPointer, encryptionTable: encryptionTable)
827816
}
828817
}
829818
}
@@ -892,6 +881,32 @@ extension CassandraClient {
892881
return names
893882
}
894883

884+
/// Builds a `PreparedStatement` taking ownership of `rawPointer`.
885+
///
886+
/// If primary-key lookup throws, it does so before the `PreparedStatement` takes
887+
/// ownership of the prepared pointer, so we free it here to avoid leaking it.
888+
private func makePreparedStatement(
889+
rawPointer: OpaquePointer,
890+
encryptionTable: String?
891+
) throws -> CassandraClient.PreparedStatement {
892+
let pkColumns: [String]
893+
if let tableName = encryptionTable {
894+
do {
895+
pkColumns = try self.lookupPrimaryKeyColumnNames(tableName: tableName)
896+
} catch {
897+
cass_prepared_free(rawPointer)
898+
throw error
899+
}
900+
} else {
901+
pkColumns = []
902+
}
903+
return CassandraClient.PreparedStatement(
904+
rawPointer: rawPointer,
905+
encryptionTable: encryptionTable,
906+
primaryKeyColumnNames: pkColumns
907+
)
908+
}
909+
895910
/// Resolve encryption contexts for parameters that have `context: nil` using driver schema metadata.
896911
/// Discovers PK columns from Cassandra's metadata cache rather than requiring EncryptionSchema registration.
897912
@available(macOS 15.0, iOS 18.0, visionOS 2.0, *)
@@ -1428,17 +1443,7 @@ extension CassandraClient.Session {
14281443
logger.debug("preparing: \(query)")
14291444
return try await self.underlying.prepare(query: query).await()
14301445
}
1431-
let pkColumns: [String]
1432-
if let tableName = encryptionTable {
1433-
pkColumns = try self.lookupPrimaryKeyColumnNames(tableName: tableName)
1434-
} else {
1435-
pkColumns = []
1436-
}
1437-
return CassandraClient.PreparedStatement(
1438-
rawPointer: preparedRawPointer,
1439-
encryptionTable: encryptionTable,
1440-
primaryKeyColumnNames: pkColumns
1441-
)
1446+
return try self.makePreparedStatement(rawPointer: preparedRawPointer, encryptionTable: encryptionTable)
14421447
}
14431448

14441449
@available(macOS 12, iOS 15, tvOS 15, watchOS 8, *)

0 commit comments

Comments
 (0)