Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix zeros stripped in conversion from numeric #111

Merged
merged 8 commits into from
Nov 6, 2018
19 changes: 14 additions & 5 deletions Sources/PostgreSQL/Data/PostgreSQLData+String.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ extension String: PostgreSQLDataConvertible {
var ndigits: Int16
/// How many of the digits are before the decimal point (always add 1)
var weight: Int16
/// If 1, this number is negative. Otherwise, positive.
/// If 0x4000, this number is negative. See NUMERIC_NEG in
/// https://github.com/postgres/postgres/blob/master/src/backend/utils/adt/numeric.c
var sign: Int16
/// The number of sig digits after the decimal place (get rid of trailing 0s)
var dscale: Int16
Expand All @@ -41,7 +42,7 @@ extension String: PostgreSQLDataConvertible {
value = value.advanced(by: 2)
}

/// conver the current char to its string form
/// convert the current char to its string form
let string: String
if char == 0 {
/// 0 means 4 zeros
Expand All @@ -52,12 +53,20 @@ extension String: PostgreSQLDataConvertible {

/// depending on our offset, append the string to before or after the decimal point
if offset < metadata.weight.bigEndian + 1 {
// insert zeros (skip leading)
if offset > 0 {
integer += String(repeating: "0", count: 4 - string.count)
}
integer += string
} else {
// Leading zeros matter with fractional
fractional += fractional.count == 0 ? String(repeating: "0", count: 4 - string.count) + string : string
// leading zeros matter with fractional
fractional += String(repeating: "0", count: 4 - string.count) + string
}
}

if integer.count == 0 {
integer = "0"
}

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

/// use sign to determine adding a leading `-`
if metadata.sign.bigEndian == 1 {
if (metadata.sign.bigEndian & 0x4000) != 0 {
return "-" + numeric
} else {
return numeric
Expand Down
31 changes: 31 additions & 0 deletions Tests/PostgreSQLTests/PostgreSQLConnectionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,36 @@ class PostgreSQLConnectionTests: XCTestCase {
}
}

// https://github.com/vapor/postgresql/pull/111
func testNumericDecode() throws {
let conn = try PostgreSQLConnection.makeTest()

let expression = { (value: String) -> PostgreSQLSelectExpression in
.expression(.literal(.numeric(value)), alias: .identifier("value"))
}

var testValues = ["0.543201203", "1000.1", "10000.1", "42.0001", "42.00001", "10234.543201", "102340567.8"]
testValues += testValues.map { "-\($0)" }

struct NumericString: PostgreSQLTable {
let value: String
}

for value in testValues {
let result = try conn.select().column(expression(value)).first(decoding: NumericString.self).wait()?.value
XCTAssert(result == value)
}

struct NumericDouble: PostgreSQLTable {
let value: Double
}

for value in testValues {
let result = try conn.select().column(expression(value)).first(decoding: NumericDouble.self).wait()?.value
XCTAssert(result == Double(value))
}
}

static var allTests = [
("testBenchmark", testBenchmark),
("testVersion", testVersion),
Expand All @@ -579,6 +609,7 @@ class PostgreSQLConnectionTests: XCTestCase {
("testInvalidDate", testInvalidDate),
("testEmptyArray", testEmptyArray),
("testZeroNumeric", testZeroNumeric),
("testNumericDecode", testNumericDecode),
]
}

Expand Down