Skip to content

Commit 975cc8b

Browse files
authored
Merge pull request #111 from michal-tomlein/numeric-zeros-bug
Fix zeros stripped in conversion from numeric
2 parents b948492 + 1259ab4 commit 975cc8b

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

Sources/PostgreSQL/Data/PostgreSQLData+String.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ extension String: PostgreSQLDataConvertible {
1414
var ndigits: Int16
1515
/// How many of the digits are before the decimal point (always add 1)
1616
var weight: Int16
17-
/// If 1, this number is negative. Otherwise, positive.
17+
/// If 0x4000, this number is negative. See NUMERIC_NEG in
18+
/// https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/numeric.c
1819
var sign: Int16
1920
/// The number of sig digits after the decimal place (get rid of trailing 0s)
2021
var dscale: Int16
@@ -41,7 +42,7 @@ extension String: PostgreSQLDataConvertible {
4142
value = value.advanced(by: 2)
4243
}
4344

44-
/// conver the current char to its string form
45+
/// convert the current char to its string form
4546
let string: String
4647
if char == 0 {
4748
/// 0 means 4 zeros
@@ -52,12 +53,20 @@ extension String: PostgreSQLDataConvertible {
5253

5354
/// depending on our offset, append the string to before or after the decimal point
5455
if offset < metadata.weight.bigEndian + 1 {
56+
// insert zeros (skip leading)
57+
if offset > 0 {
58+
integer += String(repeating: "0", count: 4 - string.count)
59+
}
5560
integer += string
5661
} else {
57-
// Leading zeros matter with fractional
58-
fractional += fractional.count == 0 ? String(repeating: "0", count: 4 - string.count) + string : string
62+
// leading zeros matter with fractional
63+
fractional += String(repeating: "0", count: 4 - string.count) + string
5964
}
6065
}
66+
67+
if integer.count == 0 {
68+
integer = "0"
69+
}
6170

6271
if fractional.count > metadata.dscale.bigEndian {
6372
/// use the dscale to remove extraneous zeroes at the end of the fractional part
@@ -74,7 +83,7 @@ extension String: PostgreSQLDataConvertible {
7483
}
7584

7685
/// use sign to determine adding a leading `-`
77-
if metadata.sign.bigEndian == 1 {
86+
if (metadata.sign.bigEndian & 0x4000) != 0 {
7887
return "-" + numeric
7988
} else {
8089
return numeric

Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,36 @@ class PostgreSQLConnectionTests: XCTestCase {
559559
}
560560
}
561561

562+
// https://github.com/vapor/postgresql/pull/111
563+
func testNumericDecode() throws {
564+
let conn = try PostgreSQLConnection.makeTest()
565+
566+
let expression = { (value: String) -> PostgreSQLSelectExpression in
567+
.expression(.literal(.numeric(value)), alias: .identifier("value"))
568+
}
569+
570+
var testValues = ["0.543201203", "1000.1", "10000.1", "42.0001", "42.00001", "10234.543201", "102340567.8"]
571+
testValues += testValues.map { "-\($0)" }
572+
573+
struct NumericString: PostgreSQLTable {
574+
let value: String
575+
}
576+
577+
for value in testValues {
578+
let result = try conn.select().column(expression(value)).first(decoding: NumericString.self).wait()?.value
579+
XCTAssert(result == value)
580+
}
581+
582+
struct NumericDouble: PostgreSQLTable {
583+
let value: Double
584+
}
585+
586+
for value in testValues {
587+
let result = try conn.select().column(expression(value)).first(decoding: NumericDouble.self).wait()?.value
588+
XCTAssert(result == Double(value))
589+
}
590+
}
591+
562592
static var allTests = [
563593
("testBenchmark", testBenchmark),
564594
("testVersion", testVersion),
@@ -579,6 +609,7 @@ class PostgreSQLConnectionTests: XCTestCase {
579609
("testInvalidDate", testInvalidDate),
580610
("testEmptyArray", testEmptyArray),
581611
("testZeroNumeric", testZeroNumeric),
612+
("testNumericDecode", testNumericDecode),
582613
]
583614
}
584615

0 commit comments

Comments
 (0)