From cb25f0bdd93e7012110cf86dd8903886ab05a047 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Fri, 31 Jul 2020 10:32:16 +0930 Subject: [PATCH 1/7] Added NULL support to textarray The textarray type needs to be able to have elements that are 'NULL' amongst the other text elements. --- .../PostgresNIO/Data/PostgresData+Array.swift | 82 +++++++++++++++---- Sources/PostgresNIO/Data/PostgresData.swift | 26 +++++- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/Sources/PostgresNIO/Data/PostgresData+Array.swift b/Sources/PostgresNIO/Data/PostgresData+Array.swift index 4febed36..816ff366 100644 --- a/Sources/PostgresNIO/Data/PostgresData+Array.swift +++ b/Sources/PostgresNIO/Data/PostgresData+Array.swift @@ -11,9 +11,25 @@ extension PostgresData { var buffer = ByteBufferAllocator().buffer(capacity: 0) // 0 if empty, 1 if not buffer.writeInteger(array.isEmpty ? 0 : 1, as: UInt32.self) + + var nilEntry = false + for item in array { + if (item == nil || item!.value == nil) { + nilEntry = true + break + } + } + // b - buffer.writeInteger(0, as: UInt32.self) - // array element type + // if we have ANY elements that have are nil then b == 1 + if(nilEntry){ + buffer.writeInteger(1, as: UInt32.self) + } else { + buffer.writeInteger(0, as: UInt32.self) + } + + + // array element type buffer.writeInteger(elementType.rawValue) // continue if the array is not empty @@ -28,7 +44,8 @@ extension PostgresData { buffer.writeInteger(numericCast(value.readableBytes), as: UInt32.self) buffer.writeBuffer(&value) } else { - buffer.writeInteger(0, as: UInt32.self) + // This is called if the value is nil! + buffer.writeInteger(UInt32.max, as: UInt32.self) } } } @@ -78,7 +95,7 @@ extension PostgresData { guard let b = value.readInteger(as: UInt32.self) else { return nil } - assert(b == 0, "Array b field did not equal zero") + //assert(b == 0, "Array b field did not equal zero") guard let type = value.readInteger(as: PostgresDataType.self) else { return nil } @@ -96,17 +113,52 @@ extension PostgresData { assert(dimensions == 1, "Multi-dimensional arrays not yet supported") var array: [PostgresData] = [] - while - let itemLength = value.readInteger(as: UInt32.self), - let itemValue = value.readSlice(length: numericCast(itemLength)) - { - let data = PostgresData( - type: type, - typeModifier: nil, - formatCode: self.formatCode, - value: itemValue - ) - array.append(data) + if( b == 0) { + while + let itemLength = value.readInteger(as: UInt32.self), + let itemValue = value.readSlice(length: numericCast(itemLength)) + { + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: itemValue + ) + array.append(data) + } + } else if (b == 1){ + for _ in 1...length { + let iLength = value.readInteger(as: UInt32.self) + if(iLength == 4294967295) + { + let iValue = ByteBuffer(staticString: "|NULL|") // This is a shit way to do this, but the LEAF module would need changing too + + if (type == 25) { // text + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: iValue) + array.append(data) + } else { + assert(1 == 2, "Unhandled Data type, expecting TEXT field") + } + } else { + + let iValue = value.readSlice(length: numericCast(iLength ?? 0)) + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: iValue) + + array.append(data) + } + } + } + else { + assert(b <= 1, "Array b field did not equal zero") + assert(b >= 0, "Array b field did not equal zero") } return array } diff --git a/Sources/PostgresNIO/Data/PostgresData.swift b/Sources/PostgresNIO/Data/PostgresData.swift index 86686556..be1fb37b 100644 --- a/Sources/PostgresNIO/Data/PostgresData.swift +++ b/Sources/PostgresNIO/Data/PostgresData.swift @@ -67,7 +67,31 @@ public struct PostgresData: CustomStringConvertible, CustomDebugStringConvertibl case .float4Array: description = self.array(of: Float.self)?.description case .textArray: - description = self.array(of: String.self)?.description + // description = self.array(of: String.self)?.description + var stringBuilder: String + stringBuilder = "[" + // textArray needs to allow NULLABLE values + if let array = self.array { + for data in array { + if stringBuilder.count > 1 { + stringBuilder += "," + } + + if let item = String(postgresData: data) { + if item == "|NULL|" { + stringBuilder += "NULL" + } else { + stringBuilder += "\"\(item)\"" + } + } else { + stringBuilder += "NULL" + } + } + description = stringBuilder + "]" + } else { + description = nil + } + case .jsonbArray: description = self.array?.description default: From d810e12bd5d47ef08cf081851363dd76e6efe689 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Wed, 19 Aug 2020 10:07:47 +0930 Subject: [PATCH 2/7] Updated Readme to indicate we have the correct tag info Updated tag info in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9f16691..a332104d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The table below shows a list of PostgresNIO major releases alongside their compa Use the SPM string to easily include the dependendency in your `Package.swift` file. ```swift -.package(url: "https://github.com/vapor/postgres-nio.git", from: ...) +.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.3.2) ``` ### Supported Platforms From deecf0e153ec99a8df2f00f0bc04ba8c95418165 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Fri, 31 Jul 2020 10:32:16 +0930 Subject: [PATCH 3/7] Added NULL support to textarray The textarray type needs to be able to have elements that are 'NULL' amongst the other text elements. --- .../PostgresNIO/Data/PostgresData+Array.swift | 82 +++++++++++++++---- Sources/PostgresNIO/Data/PostgresData.swift | 26 +++++- 2 files changed, 92 insertions(+), 16 deletions(-) diff --git a/Sources/PostgresNIO/Data/PostgresData+Array.swift b/Sources/PostgresNIO/Data/PostgresData+Array.swift index 4febed36..816ff366 100644 --- a/Sources/PostgresNIO/Data/PostgresData+Array.swift +++ b/Sources/PostgresNIO/Data/PostgresData+Array.swift @@ -11,9 +11,25 @@ extension PostgresData { var buffer = ByteBufferAllocator().buffer(capacity: 0) // 0 if empty, 1 if not buffer.writeInteger(array.isEmpty ? 0 : 1, as: UInt32.self) + + var nilEntry = false + for item in array { + if (item == nil || item!.value == nil) { + nilEntry = true + break + } + } + // b - buffer.writeInteger(0, as: UInt32.self) - // array element type + // if we have ANY elements that have are nil then b == 1 + if(nilEntry){ + buffer.writeInteger(1, as: UInt32.self) + } else { + buffer.writeInteger(0, as: UInt32.self) + } + + + // array element type buffer.writeInteger(elementType.rawValue) // continue if the array is not empty @@ -28,7 +44,8 @@ extension PostgresData { buffer.writeInteger(numericCast(value.readableBytes), as: UInt32.self) buffer.writeBuffer(&value) } else { - buffer.writeInteger(0, as: UInt32.self) + // This is called if the value is nil! + buffer.writeInteger(UInt32.max, as: UInt32.self) } } } @@ -78,7 +95,7 @@ extension PostgresData { guard let b = value.readInteger(as: UInt32.self) else { return nil } - assert(b == 0, "Array b field did not equal zero") + //assert(b == 0, "Array b field did not equal zero") guard let type = value.readInteger(as: PostgresDataType.self) else { return nil } @@ -96,17 +113,52 @@ extension PostgresData { assert(dimensions == 1, "Multi-dimensional arrays not yet supported") var array: [PostgresData] = [] - while - let itemLength = value.readInteger(as: UInt32.self), - let itemValue = value.readSlice(length: numericCast(itemLength)) - { - let data = PostgresData( - type: type, - typeModifier: nil, - formatCode: self.formatCode, - value: itemValue - ) - array.append(data) + if( b == 0) { + while + let itemLength = value.readInteger(as: UInt32.self), + let itemValue = value.readSlice(length: numericCast(itemLength)) + { + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: itemValue + ) + array.append(data) + } + } else if (b == 1){ + for _ in 1...length { + let iLength = value.readInteger(as: UInt32.self) + if(iLength == 4294967295) + { + let iValue = ByteBuffer(staticString: "|NULL|") // This is a shit way to do this, but the LEAF module would need changing too + + if (type == 25) { // text + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: iValue) + array.append(data) + } else { + assert(1 == 2, "Unhandled Data type, expecting TEXT field") + } + } else { + + let iValue = value.readSlice(length: numericCast(iLength ?? 0)) + let data = PostgresData( + type: type, + typeModifier: nil, + formatCode: self.formatCode, + value: iValue) + + array.append(data) + } + } + } + else { + assert(b <= 1, "Array b field did not equal zero") + assert(b >= 0, "Array b field did not equal zero") } return array } diff --git a/Sources/PostgresNIO/Data/PostgresData.swift b/Sources/PostgresNIO/Data/PostgresData.swift index 86686556..be1fb37b 100644 --- a/Sources/PostgresNIO/Data/PostgresData.swift +++ b/Sources/PostgresNIO/Data/PostgresData.swift @@ -67,7 +67,31 @@ public struct PostgresData: CustomStringConvertible, CustomDebugStringConvertibl case .float4Array: description = self.array(of: Float.self)?.description case .textArray: - description = self.array(of: String.self)?.description + // description = self.array(of: String.self)?.description + var stringBuilder: String + stringBuilder = "[" + // textArray needs to allow NULLABLE values + if let array = self.array { + for data in array { + if stringBuilder.count > 1 { + stringBuilder += "," + } + + if let item = String(postgresData: data) { + if item == "|NULL|" { + stringBuilder += "NULL" + } else { + stringBuilder += "\"\(item)\"" + } + } else { + stringBuilder += "NULL" + } + } + description = stringBuilder + "]" + } else { + description = nil + } + case .jsonbArray: description = self.array?.description default: From edee38b69d448ea0eebcb5f205866643f04707e4 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Wed, 19 Aug 2020 10:07:47 +0930 Subject: [PATCH 4/7] Updated Readme to indicate we have the correct tag info Updated tag info in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a9f16691..a332104d 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The table below shows a list of PostgresNIO major releases alongside their compa Use the SPM string to easily include the dependendency in your `Package.swift` file. ```swift -.package(url: "https://github.com/vapor/postgres-nio.git", from: ...) +.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.3.2) ``` ### Supported Platforms From 3de1c38f25f106ab229867c78c96c82515107e16 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Thu, 17 Sep 2020 13:54:39 +0930 Subject: [PATCH 5/7] Update README.md Update readme with latest tag --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a332104d..29ec4bc0 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The table below shows a list of PostgresNIO major releases alongside their compa Use the SPM string to easily include the dependendency in your `Package.swift` file. ```swift -.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.3.2) +.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.4.0-bq.1) ``` ### Supported Platforms From 89f5084cc27170705fe9f9ece74dc75c3a40135d Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Mon, 21 Sep 2020 10:13:56 +0930 Subject: [PATCH 6/7] Update README.md Updated README to latest release --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 29ec4bc0..b9d6111c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ The table below shows a list of PostgresNIO major releases alongside their compa Use the SPM string to easily include the dependendency in your `Package.swift` file. ```swift -.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.4.0-bq.1) +.package(url: "https://github.com/zanoroy/postgres-nio.git", from: 1.4.1) ``` ### Supported Platforms From 119cedb8e075b4c88568b530ffda9951d5d7c7e8 Mon Sep 17 00:00:00 2001 From: Zanoroy Date: Thu, 4 Aug 2022 12:04:25 +0930 Subject: [PATCH 7/7] Extended Array Type handler to include Int as well as the existing Text type --- .../PostgresNIO/Data/PostgresData+Array.swift | 17 ++++----- Sources/PostgresNIO/Data/PostgresData.swift | 38 ++++--------------- 2 files changed, 14 insertions(+), 41 deletions(-) diff --git a/Sources/PostgresNIO/Data/PostgresData+Array.swift b/Sources/PostgresNIO/Data/PostgresData+Array.swift index 913c8fc3..4412accd 100644 --- a/Sources/PostgresNIO/Data/PostgresData+Array.swift +++ b/Sources/PostgresNIO/Data/PostgresData+Array.swift @@ -13,7 +13,7 @@ extension PostgresData { var buffer = ByteBufferAllocator().buffer(capacity: 0) // 0 if empty, 1 if not buffer.writeInteger(array.isEmpty ? 0 : 1, as: UInt32.self) - + var nilEntry = false for item in array { if (item == nil || item!.value == nil) { @@ -21,7 +21,7 @@ extension PostgresData { break } } - + // b // if we have ANY elements that have are nil then b == 1 if(nilEntry){ @@ -30,7 +30,7 @@ extension PostgresData { buffer.writeInteger(0, as: UInt32.self) } - + // array element type buffer.writeInteger(elementType.rawValue) @@ -133,27 +133,24 @@ extension PostgresData { let iLength = value.readInteger(as: UInt32.self) if(iLength == 4294967295) { - let iValue = ByteBuffer(staticString: "|NULL|") // This is a shit way to do this, but the LEAF module would need changing too - - if (type == 25) { // text + if (type == .text || type == .int2 || type == .int4 || type == .int8) { let data = PostgresData( type: type, typeModifier: nil, formatCode: self.formatCode, - value: iValue) + value: nil) array.append(data) } else { - assert(1 == 2, "Unhandled Data type, expecting TEXT field") + assert(1 == 2, "Unhandled Data type, expecting TEXT or INT field type") } } else { - let iValue = value.readSlice(length: numericCast(iLength ?? 0)) let data = PostgresData( type: type, typeModifier: nil, formatCode: self.formatCode, value: iValue) - + array.append(data) } } diff --git a/Sources/PostgresNIO/Data/PostgresData.swift b/Sources/PostgresNIO/Data/PostgresData.swift index 87f42739..9b15370f 100644 --- a/Sources/PostgresNIO/Data/PostgresData.swift +++ b/Sources/PostgresNIO/Data/PostgresData.swift @@ -9,28 +9,28 @@ public struct PostgresData: CustomStringConvertible, CustomDebugStringConvertibl public static var null: PostgresData { return .init(type: .null) } - + /// The object ID of the field's data type. public var type: PostgresDataType - + /// The type modifier (see pg_attribute.atttypmod). The meaning of the modifier is type-specific. public var typeModifier: Int32? - + /// The format code being used for the field. /// Currently will be zero (text) or one (binary). /// In a RowDescription returned from the statement variant of Describe, /// the format code is not yet known and will always be zero. public var formatCode: PostgresFormat - + public var value: ByteBuffer? - + public init(type: PostgresDataType, typeModifier: Int32? = nil, formatCode: PostgresFormat = .binary, value: ByteBuffer? = nil) { self.type = type self.typeModifier = typeModifier self.formatCode = formatCode self.value = value } - + public var description: String { guard var value = self.value else { return "" @@ -71,31 +71,7 @@ public struct PostgresData: CustomStringConvertible, CustomDebugStringConvertibl case .float4Array: description = self.array(of: Float.self)?.description case .textArray: - // description = self.array(of: String.self)?.description - var stringBuilder: String - stringBuilder = "[" - // textArray needs to allow NULLABLE values - if let array = self.array { - for data in array { - if stringBuilder.count > 1 { - stringBuilder += "," - } - - if let item = String(postgresData: data) { - if item == "|NULL|" { - stringBuilder += "NULL" - } else { - stringBuilder += "\"\(item)\"" - } - } else { - stringBuilder += "NULL" - } - } - description = stringBuilder + "]" - } else { - description = nil - } - + description = self.array(of: String.self)?.description case .jsonbArray: description = self.array?.description default: