Skip to content

Commit

Permalink
Merge pull request #275 from schveiguy/fix272
Browse files Browse the repository at this point in the history
Fix #272. Blob types should be accessible via byte[]
  • Loading branch information
schveiguy authored Feb 11, 2023
2 parents 0ea6cb3 + a6bed51 commit fa4d3fb
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 16 deletions.
8 changes: 8 additions & 0 deletions integration-tests/source/mysql/test/common.d
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,16 @@ version(DoCoreTests)

// Timestamp is a bit special as it's converted to a DateTime when
// returning from MySQL to avoid having to use a mysql specific type.
//
// byte[] is also special (for now) because it's supported with the
// unsafe portion of prepared statements. However, it's always ubyte[]
// underneath.
//
// TODO: remove this hack for byte[] when unsafe mysql-native is removed.
static if(is(T == DateTime) && is(U == Timestamp))
assert(result.get.get!DateTime == expected.toDateTime());
else static if(is(T == byte[]))
assert(cast(byte[])result.get.get!(ubyte[]) == expected);
else
assert(result.get.get!T == expected);
}
Expand Down
19 changes: 13 additions & 6 deletions integration-tests/source/mysql/test/integration.d
Original file line number Diff line number Diff line change
Expand Up @@ -982,13 +982,20 @@ debug(MYSQLN_TESTS)
assertBasicTests!string("TEXT", "", "aoeu");
assertBasicTests!string("LONGTEXT", "", "aoeu");

assertBasicTests!(ubyte[])("TINYBLOB", "", "aoeu");
assertBasicTests!(ubyte[])("MEDIUMBLOB", "", "aoeu");
assertBasicTests!(ubyte[])("BLOB", "", "aoeu");
assertBasicTests!(ubyte[])("LONGBLOB", "", "aoeu");
import std.meta : AliasSeq;
static if(doSafe) alias blobTypes = AliasSeq!(ubyte[]);
else alias blobTypes = AliasSeq!(ubyte[], byte[]);

assertBasicTests!(ubyte[])("TINYBLOB", cast(ubyte[])"".dup, cast(ubyte[])"aoeu".dup);
assertBasicTests!(ubyte[])("TINYBLOB", "".dup, "aoeu".dup);
static foreach(BT; blobTypes)
{
assertBasicTests!(BT)("TINYBLOB", "", "aoeu");
assertBasicTests!(BT)("MEDIUMBLOB", "", "aoeu");
assertBasicTests!(BT)("BLOB", "", "aoeu");
assertBasicTests!(BT)("LONGBLOB", "", "aoeu");

assertBasicTests!(BT)("TINYBLOB", cast(BT)"".dup, cast(BT)"aoeu".dup);
assertBasicTests!(BT)("TINYBLOB", "".dup, "aoeu".dup);
}

assertBasicTests!Date("DATE", Date(2013, 10, 03));
assertBasicTests!DateTime("DATETIME", DateTime(2013, 10, 03, 12, 55, 35));
Expand Down
16 changes: 13 additions & 3 deletions source/mysql/impl/prepared.d
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,13 @@ struct UnsafePrepared
void setArg(T)(size_t index, T val, UnsafeParameterSpecialization psn = UPSN.init) @system
if(!is(T == Variant))
{
_safe.setArg(index, val, cast(SPSN)psn);
// forward to the safe API, but if not, fall back on what the unsafe
// version did.
static if(__traits(compiles, _safe.setArg(index, val, cast(SPSN)psn)))
_safe.setArg(index, val, cast(SPSN)psn);
else
// convert to variant first, then rely on the runtime to catch it.
setArg(index, Variant(val), psn);
}

/// ditto
Expand All @@ -342,8 +348,13 @@ struct UnsafePrepared
auto translateArg(alias arg)() {
static if(is(typeof(arg) == Variant))
return _toVal(arg);
else
else static if(__traits(compiles, setArg(0, arg)))
return arg;
else
// not settable using the safe API, convert to variant first,
// and then use the variant conversion routine to flesh out any
// cases.
return _toVal(Variant(arg));
}
_safe.setArgs(staticMap!(translateArg, args));
}
Expand Down Expand Up @@ -581,4 +592,3 @@ package(mysql) struct PreparedRegistrations(Payload)
return info;
}
}

42 changes: 35 additions & 7 deletions source/mysql/types.d
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ $(SAFE_MIGRATION)
alias MySQLVal = TaggedAlgebraic!_MYTYPE;

// helper to convert variants to MySQLVal. Used wherever variant is still used.
import std.variant : Variant;
private import std.variant : Variant;
package MySQLVal _toVal(Variant v)
{
int x;
Expand All @@ -197,18 +197,36 @@ package MySQLVal _toVal(Variant v)
}

import std.meta;
import std.traits;
import mysql.exceptions;
import std.traits : Unqual;
// much simpler/focused fullyqualifiedname template
template FQN(T) {
static if(is(T == DateTime) || is(T == Date) || is(T == TimeOfDay))
enum FQN = "std.datetime.date." ~ T.stringof;
else static if(is(T == Timestamp))
enum FQN = "mysql.types.Timestamp";
else
enum FQN = T.stringof;
}

alias BasicTypes = AliasSeq!(bool, byte, ubyte, short, ushort, int, uint, long, ulong, float, double, DateTime, TimeOfDay, Date, Timestamp);
alias ArrayTypes = AliasSeq!(char[], const(char)[], ubyte[], const(ubyte)[], immutable(ubyte)[]);
alias ArrayTypes = AliasSeq!(char[], const(char)[],
ubyte[], const(ubyte)[], immutable(ubyte)[]);

// types that worked with the old system via Variant, but have to be
// converted to work with MySQLVal
alias ConvertibleTypes = AliasSeq!(byte[], const(byte)[], immutable(byte)[]);
alias ConvertedTypes = AliasSeq!(const(ubyte[]), const(ubyte[]), const(ubyte[]) );
static assert(ConvertibleTypes.length == ConvertedTypes.length);

switch (ts)
{
static foreach(Type; BasicTypes)
{
case fullyQualifiedName!Type:
case "const(" ~ fullyQualifiedName!Type ~ ")":
case "immutable(" ~ fullyQualifiedName!Type ~ ")":
case "shared(immutable(" ~ fullyQualifiedName!Type ~ "))":
case FQN!Type:
case "const(" ~ FQN!Type ~ ")":
case "immutable(" ~ FQN!Type ~ ")":
case "shared(immutable(" ~ FQN!Type ~ "))":
if(isRef)
return MySQLVal(v.get!(const(Type*)));
else
Expand All @@ -225,6 +243,16 @@ package MySQLVal _toVal(Variant v)
return MySQLVal(v.get!(Type));
}
}
static foreach(i; 0 .. ConvertibleTypes.length)
{
case ConvertibleTypes[i].stringof:
{
if(isRef)
return MySQLVal(cast(ConvertedTypes[i]*)v.get!(ConvertibleTypes[i]*));
else
return MySQLVal(cast(ConvertedTypes[i])v.get!(ConvertibleTypes[i]));
}
}
case "immutable(char)[]":
// have to do this separately, because everything says "string" but
// Variant says "immutable(char)[]"
Expand Down

0 comments on commit fa4d3fb

Please sign in to comment.