Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit 2d0adb6

Browse files
committed
Merge pull request #191 from AkosLukacs/postgres_bytea
Problem with PostgreSQL byte[] serialization/deserialization
2 parents 03500a4 + 851cb9e commit 2d0adb6

File tree

2 files changed

+149
-3
lines changed

2 files changed

+149
-3
lines changed

src/ServiceStack.OrmLite.PostgreSQL.Tests/TypeWithByteArrayFieldTests.cs

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
namespace ServiceStack.OrmLite.PostgreSQL.Tests
55
{
66
public class TypeWithByteArrayFieldTests : OrmLiteTestBase
7-
{
7+
{
8+
TypeWithByteArrayField getSampleObject()
9+
{
10+
var testByteArray = new byte[256];
11+
for(int i = 0; i < 256; i++) { testByteArray[i] = (byte)i; }
12+
13+
return new TypeWithByteArrayField { Id = 1, Content = testByteArray };
14+
}
15+
816
[Test]
917
public void CanInsertAndSelectByteArray()
1018
{
11-
var orig = new TypeWithByteArrayField { Id = 1, Content = new byte[] { 0, 17, 0, 17, 0, 7 } };
19+
var orig = getSampleObject();
1220

1321
using (var db = ConnectionString.OpenDbConnection())
1422
{
@@ -21,6 +29,116 @@ public void CanInsertAndSelectByteArray()
2129
Assert.AreEqual(orig.Id, target.Id);
2230
Assert.AreEqual(orig.Content, target.Content);
2331
}
32+
}
33+
34+
[Test]
35+
public void CanInsertAndSelectByteArray__manual_insert__manual_select()
36+
{
37+
var orig = getSampleObject();
38+
39+
using(var db = ConnectionString.OpenDbConnection()) {
40+
//insert and select manually - ok
41+
db.CreateTable<TypeWithByteArrayField>(true);
42+
_insertManually(orig, db);
43+
44+
_selectAndVerifyManually(orig, db);
45+
}
46+
}
47+
48+
[Test]
49+
public void CanInsertAndSelectByteArray__InsertParam_insert__manual_select()
50+
{
51+
var orig = getSampleObject();
52+
53+
using(var db = ConnectionString.OpenDbConnection()) {
54+
//insert using InsertParam, and select manually - ok
55+
db.CreateTable<TypeWithByteArrayField>(true);
56+
db.InsertParam(orig);
57+
58+
_selectAndVerifyManually(orig, db);
59+
}
60+
}
61+
62+
[Test]
63+
public void CanInsertAndSelectByteArray__InsertParam_insert__GetById_select()
64+
{
65+
var orig = getSampleObject();
66+
67+
using(var db = ConnectionString.OpenDbConnection()) {
68+
//InsertParam + GetByID - fails
69+
db.CreateTable<TypeWithByteArrayField>(true);
70+
db.InsertParam(orig);
71+
72+
var target = db.GetById<TypeWithByteArrayField>(orig.Id);
73+
74+
Assert.AreEqual(orig.Id, target.Id);
75+
Assert.AreEqual(orig.Content, target.Content);
76+
}
77+
}
78+
79+
[Test]
80+
public void CanInsertAndSelectByteArray__Insert_insert__GetById_select()
81+
{
82+
var orig = getSampleObject();
83+
84+
using(var db = ConnectionString.OpenDbConnection()) {
85+
//InsertParam + GetByID - fails
86+
db.CreateTable<TypeWithByteArrayField>(true);
87+
db.Insert(orig);
88+
89+
var target = db.GetById<TypeWithByteArrayField>(orig.Id);
90+
91+
Assert.AreEqual(orig.Id, target.Id);
92+
Assert.AreEqual(orig.Content, target.Content);
93+
}
94+
}
95+
96+
[Test]
97+
public void CanInsertAndSelectByteArray__Insert_insert__manual_select()
98+
{
99+
var orig = getSampleObject();
100+
101+
using(var db = ConnectionString.OpenDbConnection()) {
102+
//InsertParam + GetByID - fails
103+
db.CreateTable<TypeWithByteArrayField>(true);
104+
db.Insert(orig);
105+
106+
_selectAndVerifyManually(orig, db);
107+
}
108+
}
109+
110+
private static void _selectAndVerifyManually(TypeWithByteArrayField orig, System.Data.IDbConnection db)
111+
{
112+
using(var cmd = db.CreateCommand()) {
113+
cmd.CommandText = @"select ""Content"" from ""TypeWithByteArrayField"" where ""Id"" = 1 --manual select";
114+
using(var reader = cmd.ExecuteReader()) {
115+
reader.Read();
116+
var ba = reader["Content"] as byte[];
117+
Assert.AreEqual(orig.Content.Length, ba.Length);
118+
Assert.AreEqual(orig.Content, ba);
119+
}
120+
}
121+
}
122+
123+
private static void _insertManually(TypeWithByteArrayField orig, System.Data.IDbConnection db)
124+
{
125+
using(var cmd = db.CreateCommand()) {
126+
cmd.CommandText = @"INSERT INTO ""TypeWithByteArrayField"" (""Id"",""Content"") VALUES (@Id, @Content) --manual parameterized insert";
127+
128+
var p_id = cmd.CreateParameter();
129+
p_id.ParameterName = "@Id";
130+
p_id.Value = orig.Id;
131+
132+
cmd.Parameters.Add(p_id);
133+
134+
var p_content = cmd.CreateParameter();
135+
p_content.ParameterName = "@Content";
136+
p_content.Value = orig.Content;
137+
138+
cmd.Parameters.Add(p_content);
139+
140+
cmd.ExecuteNonQuery();
141+
}
24142
}
25143
}
26144

src/ServiceStack.OrmLite.PostgreSQL/PostgreSQLDialectProvider.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,14 +120,20 @@ public override string GetQuotedValue(object value, Type fieldType)
120120
var guidValue = (Guid)value;
121121
return base.GetQuotedValue(guidValue.ToString("N"), typeof(string));
122122
}
123+
if(fieldType == typeof(byte[]))
124+
{
125+
return "E'" + ToBinary(value) + "'";
126+
}
123127

124128
return base.GetQuotedValue(value, fieldType);
125129
}
126130

127131
public override object ConvertDbValue(object value, Type type)
128132
{
129133
if (value == null || value is DBNull) return null;
130-
134+
135+
if(type == typeof(byte[])) { return value; }
136+
131137
return base.ConvertDbValue(value, type);
132138
}
133139

@@ -194,5 +200,27 @@ public override string GetQuotedTableName(ModelDefinition modelDef)
194200
string escapedSchema = modelDef.Schema.Replace(".", "\".\"");
195201
return string.Format("\"{0}\".\"{1}\"", escapedSchema, base.NamingStrategy.GetTableName(modelDef.ModelName));
196202
}
203+
204+
/// <summary>
205+
/// based on Npgsql2's source: Npgsql2\src\NpgsqlTypes\NpgsqlTypeConverters.cs
206+
/// </summary>
207+
/// <param name="TypeInfo"></param>
208+
/// <param name="NativeData"></param>
209+
/// <param name="ForExtendedQuery"></param>
210+
/// <returns></returns>
211+
internal static String ToBinary(Object NativeData)
212+
{
213+
Byte[] byteArray = (Byte[])NativeData;
214+
StringBuilder res = new StringBuilder(byteArray.Length * 5);
215+
foreach(byte b in byteArray)
216+
if(b >= 0x20 && b < 0x7F && b != 0x27 && b != 0x5C)
217+
res.Append((char)b);
218+
else
219+
res.Append("\\\\")
220+
.Append((char)('0' + (7 & (b >> 6))))
221+
.Append((char)('0' + (7 & (b >> 3))))
222+
.Append((char)('0' + (7 & b)));
223+
return res.ToString();
224+
}
197225
}
198226
}

0 commit comments

Comments
 (0)