1 /++
2 Escape special characters in MySQL strings.
3 
4 Note, it is strongly recommended to use prepared statements instead of relying
5 on manual escaping, as prepared statements are always safer, better and more
6 reliable (see `mysql.prepared`). But if you absolutely must escape manually,
7 the functionality is provided here.
8 +/
9 module mysql.escape;
10 
11 
12 /++
13 Simple escape function for dangerous SQL characters
14 
15 Params:
16 	input = string to escape
17 	output = output range to write to
18 +/
19 void mysql_escape ( Output, Input ) ( Input input, Output output )
20 {
21 	import std.string : translate;
22 
23 	immutable string[dchar] transTable = [
24 		'\\' : "\\\\",
25 		'\'' : "\\'",
26 		'\0' : "\\0",
27 		'\n' : "\\n",
28 		'\r' : "\\r",
29 		'"'  : "\\\"",
30 		'\032' : "\\Z"
31 	];
32 
33 	translate(input, transTable, null, output);
34 }
35 
36 
37 /++
38 Struct to wrap around an input range so it can be passed to formattedWrite and be
39 properly escaped without allocating a temporary buffer
40 
41 Params:
42 	Input = (Template Param) Type of the input range
43 
44 Note:
45     The delegate is expected to be @safe as of version 3.2.0.
46 +/
47 struct MysqlEscape ( Input )
48 {
49 	Input input;
50 
51 	const void toString ( scope void delegate(scope const(char)[]) @safe sink )
52 	{
53 		mysql_escape(input, sink);
54 	}
55 }
56 
57 /++
58 Helper function to easily construct a escape wrapper struct
59 
60 Params:
61 	T = (Template Param) Type of the input range
62 	input = Input to escape
63 +/
64 MysqlEscape!(T) mysqlEscape ( T ) ( T input )
65 {
66 	return MysqlEscape!(T)(input);
67 }
68 
69 @("mysqlEscape")
70 debug(MYSQLN_TESTS)
71 @safe unittest
72 {
73 	import std.array : appender;
74 
75 	auto buf = appender!string();
76 
77 	import std.format : formattedWrite;
78 
79 	formattedWrite(buf, "%s, %s, %s, mkay?", 1, 2,
80 			mysqlEscape("\0, \r, \n, \", \\"));
81 
82 	assert(buf.data() == `1, 2, \0, \r, \n, \", \\, mkay?`);
83 }