Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
helje5 committed Nov 8, 2024
2 parents f821b84 + cbf5eda commit 2387f15
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 12 deletions.
48 changes: 40 additions & 8 deletions Sources/PostgreSQLAdaptor/PostgreSQLAdaptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// ZeeQL
//
// Created by Helge Hess on 03/03/17.
// Copyright © 2017-2019 ZeeZide GmbH. All rights reserved.
// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved.
//

import Foundation
Expand All @@ -22,7 +22,9 @@ open class PostgreSQLAdaptor : Adaptor, SmartDescription {

/// The connectString the adaptor was configured with.
open var connectString : String


private let pool : AdaptorChannelPool?

/**
* Configure the adaptor with the given connect string.
*
Expand All @@ -48,9 +50,10 @@ open class PostgreSQLAdaptor : Adaptor, SmartDescription {
* Note: The init doesn't validate the connect string, if it is malformed,
* channel creation will fail.
*/
public init(_ connectString: String) {
public init(_ connectString: String, pool: AdaptorChannelPool? = nil) {
// TODO: could call PQconninfoParse(constr, &error) to validate
self.connectString = connectString
self.pool = pool
}

/**
Expand All @@ -63,15 +66,16 @@ open class PostgreSQLAdaptor : Adaptor, SmartDescription {
*/
public convenience init(host: String = "127.0.0.1", port: Int = 5432,
database: String = "postgres",
user: String = "postgres", password: String = "")
user: String = "postgres", password: String = "",
pool: AdaptorChannelPool? = nil)
{
var s = ""
if !host.isEmpty { s += " host=\(host)" }
if port > 0 { s += " port=\(port)" }
if !database.isEmpty { s += " dbname=\(database)" }
if !user.isEmpty { s += " user=\(user)" }
if !password.isEmpty { s += " password=\(password)" }
self.init(s)
self.init(s, pool: pool)
}

private func parseConnectionString(_ s: String) -> [ String : String ] {
Expand Down Expand Up @@ -147,10 +151,37 @@ open class PostgreSQLAdaptor : Adaptor, SmartDescription {
return PostgreSQLAdaptorChannel(adaptor: self, handle: handle)
}

public func releaseChannel(_ channel: AdaptorChannel) {
// not maintaing a pool
public func openChannelFromPool() throws -> AdaptorChannel {
if let channel = pool?.grab() {
log.info("reusing pooled channel:", channel)
return channel
}
do {
let channel = try openChannel()
if pool != nil {
log.info("opened new channel:", channel)
}
return channel
}
catch {
throw error
}
}

public func releaseChannel(_ channel: AdaptorChannel) {
guard let pool = pool else {
return
}
if let channel = channel as? PostgreSQLAdaptorChannel {
log.info("releasing channel:", ObjectIdentifier(channel))
pool.add(channel)
}
else {
log.info("invalid channel type:", channel)
assert(channel is PostgreSQLAdaptorChannel)
}
}


// MARK: - Model

Expand All @@ -172,8 +203,9 @@ open class PostgreSQLAdaptor : Adaptor, SmartDescription {

public func appendToDescription(_ ms: inout String) {
ms += " " + connectString
if model != nil {
if let model = model {
ms += " has-model"
if model.isPattern { ms += "(pattern)" }
}
}
}
30 changes: 26 additions & 4 deletions Sources/PostgreSQLAdaptor/PostgreSQLAdaptorChannel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// ZeeQL
//
// Created by Helge Hess on 03/03/17.
// Copyright © 2017 ZeeZide GmbH. All rights reserved.
// Copyright © 2017-2024 ZeeZide GmbH. All rights reserved.
//

#if os(Windows)
Expand All @@ -13,7 +13,7 @@
#else
import Darwin
#endif
import struct Foundation.Data
import Foundation
import ZeeQL
import CLibPQ

Expand All @@ -34,11 +34,12 @@ open class PostgreSQLAdaptorChannel : AdaptorChannel, SmartDescription {

public let expressionFactory : SQLExpressionFactory
public var handle : OpaquePointer?
final let logSQL = true
final let logSQL : Bool

init(adaptor: Adaptor, handle: OpaquePointer) {
self.expressionFactory = adaptor.expressionFactory
self.handle = handle
self.logSQL = UserDefaults.standard.bool(forKey: "PGDebugEnabled")
}

deinit {
Expand Down Expand Up @@ -317,6 +318,7 @@ open class PostgreSQLAdaptorChannel : AdaptorChannel, SmartDescription {
// TODO: consider attribute! (e.g. for date, valueType in attr, if set)

// TODO: decode actual types :-)
// TODO: do not crash on force unwrap

switch type {
case OIDs.INT2: return Int16(bigEndian: cast(value.baseAddress!))
Expand All @@ -335,11 +337,25 @@ open class PostgreSQLAdaptorChannel : AdaptorChannel, SmartDescription {
case OIDs.NAME: // e.g. SELECT datname FROM pg_database
return String(cString: value.baseAddress!)

case OIDs.TIMESTAMPTZ:
case OIDs.TIMESTAMPTZ: // 1184
// TODO: I think it is better to fix this during the query, that is,
// to a SELECT unix_time(startDate) like thing.
// hm. How to parse this? We used to have the format in the attribute?
// http://www.linuxtopia.org/online_books/database_guides/Practical_PostgreSQL_database/PostgreSQL_x2632_005.htm
// 2024-11-08(hh): this seems to be 8 bytes aka UInt64 and the above
// for String representations
// https://postgrespro.com/list/thread-id/1482672
// https://materialize.com/docs/sql/types/timestamp/
// - Min value 4713 BC
// - Max value 294276 AD
// - Max resolution 1 microsecond
if value.count == 8 {
// 1_000_000
let msecs = Double(UInt64(bigEndian: cast(value.baseAddress!)))
let date = Date(timeInterval: TimeInterval(msecs) / 1000000.0,
since: Date.pgReferenceDate)
return date
}
return String(cString: value.baseAddress!)
case OIDs.TIMESTAMP:
return String(cString: value.baseAddress!)
Expand Down Expand Up @@ -527,3 +543,9 @@ fileprivate func tdup<T>(_ value: T) -> UnsafeBufferPointer<Int8> {
ptr.pointee = value
return UnsafeBufferPointer(start: UnsafePointer(raw), count: len)
}

fileprivate extension Date {

// 2000-01-01
static let pgReferenceDate = Date(timeIntervalSince1970: 946684800)
}

0 comments on commit 2387f15

Please sign in to comment.