|
1 | 1 | using System.Buffers; |
| 2 | +using System.Globalization; |
2 | 3 | using System.Text; |
3 | 4 | using Cosmo.Transport.Pipelines; |
4 | 5 | using CosmoSQLClient.Core; |
@@ -43,16 +44,17 @@ public static SqlRow ParseDataRow(ReadOnlySequence<byte> body, IReadOnlyList<Sql |
43 | 44 | { |
44 | 45 | var valSeq = body.Slice(reader.Consumed, len); |
45 | 46 | reader.Advance(len); |
| 47 | + var typeName = i < columns.Count ? columns[i].TypeName : string.Empty; |
46 | 48 | #if NETSTANDARD2_0 |
47 | | - values[i] = SqlValue.From(Encoding.UTF8.GetString(valSeq.ToArray())); |
| 49 | + values[i] = ParseValue(typeName, Encoding.UTF8.GetString(valSeq.ToArray())); |
48 | 50 | #else |
49 | 51 | if (valSeq.IsSingleSegment) |
50 | 52 | { |
51 | | - values[i] = SqlValue.From(Encoding.UTF8.GetString(valSeq.First.Span)); |
| 53 | + values[i] = ParseValue(typeName, Encoding.UTF8.GetString(valSeq.First.Span)); |
52 | 54 | } |
53 | 55 | else |
54 | 56 | { |
55 | | - values[i] = SqlValue.From(Encoding.UTF8.GetString(valSeq.ToArray())); |
| 57 | + values[i] = ParseValue(typeName, Encoding.UTF8.GetString(valSeq.ToArray())); |
56 | 58 | } |
57 | 59 | #endif |
58 | 60 | } |
@@ -107,6 +109,74 @@ private static string ReadNullTerminatedString(ref SequenceReader<byte> reader) |
107 | 109 | 1082 => "date", 1114 => "timestamp", 1184 => "timestamptz", |
108 | 110 | 1700 => "numeric", 2950 => "uuid", _ => oid.ToString() |
109 | 111 | }; |
| 112 | + |
| 113 | + private static SqlValue ParseValue(string typeName, string text) |
| 114 | + { |
| 115 | + switch (typeName.ToLowerInvariant()) |
| 116 | + { |
| 117 | + case "bool": |
| 118 | + return bool.TryParse(text, out var b) ? SqlValue.From(b) : SqlValue.From(text == "1" || text.Equals("t", StringComparison.OrdinalIgnoreCase)); |
| 119 | + case "int2": |
| 120 | + case "int4": |
| 121 | + case "int8": |
| 122 | + return long.TryParse(text, NumberStyles.Integer, CultureInfo.InvariantCulture, out var l) |
| 123 | + ? SqlValue.From(l) |
| 124 | + : SqlValue.From(text); |
| 125 | + case "float4": |
| 126 | + case "float8": |
| 127 | + return double.TryParse(text, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var d) |
| 128 | + ? SqlValue.From(d) |
| 129 | + : SqlValue.From(text); |
| 130 | + case "numeric": |
| 131 | + return decimal.TryParse(text, NumberStyles.Number, CultureInfo.InvariantCulture, out var dec) |
| 132 | + ? SqlValue.From(dec) |
| 133 | + : SqlValue.From(text); |
| 134 | + case "uuid": |
| 135 | + return Guid.TryParse(text, out var g) ? SqlValue.From(g) : SqlValue.From(text); |
| 136 | + case "date": |
| 137 | + case "timestamp": |
| 138 | + return DateTime.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dt) |
| 139 | + ? SqlValue.From(dt) |
| 140 | + : SqlValue.From(text); |
| 141 | + case "timestamptz": |
| 142 | + return DateTimeOffset.TryParse(text, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var dto) |
| 143 | + ? SqlValue.From(dto) |
| 144 | + : SqlValue.From(text); |
| 145 | + case "bytea": |
| 146 | + return ParseBytea(text); |
| 147 | + default: |
| 148 | + return SqlValue.From(text); |
| 149 | + } |
| 150 | + } |
| 151 | + |
| 152 | + private static SqlValue ParseBytea(string text) |
| 153 | + { |
| 154 | + if (string.IsNullOrEmpty(text)) |
| 155 | + return SqlValue.EmptyString_; |
| 156 | + |
| 157 | + if (text.StartsWith("\\x", StringComparison.OrdinalIgnoreCase)) |
| 158 | + { |
| 159 | + int hexLen = text.Length - 2; |
| 160 | + if (hexLen % 2 == 0) |
| 161 | + { |
| 162 | + var bytes = new byte[hexLen / 2]; |
| 163 | + for (int i = 0; i < bytes.Length; i++) |
| 164 | + { |
| 165 | +#if NETSTANDARD2_0 |
| 166 | + if (!byte.TryParse(text.Substring(2 + i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b)) |
| 167 | + return SqlValue.From(text); |
| 168 | +#else |
| 169 | + if (!byte.TryParse(text.AsSpan(2 + i * 2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var b)) |
| 170 | + return SqlValue.From(text); |
| 171 | +#endif |
| 172 | + bytes[i] = b; |
| 173 | + } |
| 174 | + return SqlValue.From(bytes); |
| 175 | + } |
| 176 | + } |
| 177 | + |
| 178 | + return SqlValue.From(text); |
| 179 | + } |
110 | 180 | } |
111 | 181 |
|
112 | 182 | internal interface IPostgresTokenHandler |
|
0 commit comments