1 /**
2  * DStruct - Object-Relation Mapping for D programming language, with interface similar to Hibernate. 
3  * 
4  * Source file dstruct/dialects/mysqldialect.d.
5  *
6  * This module contains implementation of MySQLDialect class which provides implementation specific SQL syntax information.
7  * 
8  * Copyright: Copyright 2013
9  * License:   $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
10  * Author:   Vadim Lopatin
11  */
12 module dstruct.dialects.mysqldialect;
13 
14 import std.conv;
15 
16 import dstruct.dialect;
17 import dstruct.metadata;
18 import dstruct.type;
19 import dstruct.ddbc.core;
20 
21 string[] MYSQL_RESERVED_WORDS = 
22 	[
23 	"ACCESSIBLE", "ADD", "ALL",
24 	"ALTER", "ANALYZE", "AND",
25 	"AS", "ASC", "ASENSITIVE",
26 	"BEFORE", "BETWEEN", "BIGINT",
27 	"BINARY", "BLOB", "BOTH",
28 	"BY", "CALL", "CASCADE",
29 	"CASE", "CHANGE", "CHAR",
30 	"CHARACTER", "CHECK", "COLLATE",
31 	"COLUMN", "CONDITION", "CONSTRAINT",
32 	"CONTINUE", "CONVERT", "CREATE",
33 	"CROSS", "CURRENT_DATE", "CURRENT_TIME",
34 	"CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR",
35 	"DATABASE", "DATABASES", "DAY_HOUR",
36 	"DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND",
37 	"DEC", "DECIMAL", "DECLARE",
38 	"DEFAULT", "DELAYED", "DELETE",
39 	"DESC", "DESCRIBE", "DETERMINISTIC",
40 	"DISTINCT", "DISTINCTROW", "DIV",
41 	"DOUBLE", "DROP", "DUAL",
42 	"EACH", "ELSE", "ELSEIF",
43 	"ENCLOSED", "ESCAPED", "EXISTS",
44 	"EXIT", "EXPLAIN", "FALSE",
45 	"FETCH", "FLOAT", "FLOAT4",
46 	"FLOAT8", "FOR", "FORCE",
47 	"FOREIGN", "FROM", "FULLTEXT",
48 	"GET", "GRANT", "GROUP",
49 	"HAVING", "HIGH_PRIORITY", "HOUR_MICROSECOND",
50 	"HOUR_MINUTE", "HOUR_SECOND", "IF",
51 	"IGNORE", "IN", "INDEX",
52 	"INFILE", "INNER", "INOUT",
53 	"INSENSITIVE", "INSERT", "INT",
54 	"INT1", "INT2", "INT3",
55 	"INT4", "INT8", "INTEGER",
56 	"INTERVAL", "INTO", "IO_AFTER_GTIDS",
57 	"IO_BEFORE_GTIDS", "IS", "ITERATE",
58 	"JOIN", "KEY", "KEYS",
59 	"KILL", "LEADING", "LEAVE",
60 	"LEFT", "LIKE", "LIMIT",
61 	"LINEAR", "LINES", "LOAD",
62 	"LOCALTIME", "LOCALTIMESTAMP", "LOCK",
63 	"LONG", "LONGBLOB", "LONGTEXT",
64 	"LOOP", "LOW_PRIORITY", "MASTER_BIND",
65 	"MASTER_SSL_VERIFY_SERVER_CERT", "MATCH", "MAXVALUE",
66 	"MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT",
67 	"MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND",
68 	"MOD", "MODIFIES", "NATURAL",
69 	"NOT", "NO_WRITE_TO_BINLOG", "NULL",
70 	"NUMERIC", "ON", "OPTIMIZE",
71 	"OPTION", "OPTIONALLY", "OR",
72 	"ORDER", "OUT", "OUTER",
73 	"OUTFILE", "PARTITION", "PRECISION",
74 	"PRIMARY", "PROCEDURE", "PURGE",
75 	"RANGE", "READ", "READS",
76 	"READ_WRITE", "REAL", "REFERENCES",
77 	"REGEXP", "RELEASE", "RENAME",
78 	"REPEAT", "REPLACE", "REQUIRE",
79 	"RESIGNAL", "RESTRICT", "RETURN",
80 	"REVOKE", "RIGHT", "RLIKE",
81 	"SCHEMA", "SCHEMAS", "SECOND_MICROSECOND",
82 	"SELECT", "SENSITIVE", "SEPARATOR",
83 	"SET", "SHOW", "SIGNAL",
84 	"SMALLINT", "SPATIAL", "SPECIFIC",
85 	"SQL", "SQLEXCEPTION", "SQLSTATE",
86 	"SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS",
87 	"SQL_SMALL_RESULT", "SSL", "STARTING",
88 	"STRAIGHT_JOIN", "TABLE", "TERMINATED",
89 	"THEN", "TINYBLOB", "TINYINT",
90 	"TINYTEXT", "TO", "TRAILING",
91 	"TRIGGER", "TRUE", "UNDO",
92 	"UNION", "UNIQUE", "UNLOCK",
93 	"UNSIGNED", "UPDATE", "USAGE",
94 	"USE", "USING", "UTC_DATE",
95 	"UTC_TIME", "UTC_TIMESTAMP", "VALUES",
96 	"VARBINARY", "VARCHAR", "VARCHARACTER",
97 	"VARYING", "WHEN", "WHERE",
98 	"WHILE", "WITH", "WRITE",
99 	"XOR", "YEAR_MONTH", "ZEROFILL",
100 	"GET", "IO_AFTER_GTIDS", "IO_BEFORE_GTIDS",
101 	"MASTER_BIND", "ONE_SHOT", "PARTITION",
102 	"SQL_AFTER_GTIDS", "SQL_BEFORE_GTIDS",
103 ];
104 
105 class MySQLDialect : Dialect {
106     ///The character specific to this dialect used to close a quoted identifier.
107     override char closeQuote() const { return '`'; }
108     ///The character specific to this dialect used to begin a quoted identifier.
109     override char  openQuote() const { return '`'; }
110 
111     // returns string like "BIGINT(20) NOT NULL" or "VARCHAR(255) NULL"
112     override string getColumnTypeDefinition(const PropertyInfo pi, const PropertyInfo overrideTypeFrom = null) {
113         immutable Type type = overrideTypeFrom !is null ? overrideTypeFrom.columnType : pi.columnType;
114         immutable SqlType sqlType = type.getSqlType();
115         bool fk = pi is null;
116         string nullablility = !fk && pi.nullable ? " NULL" : " NOT NULL";
117         string pk = !fk && pi.key ? " PRIMARY KEY" : "";
118         string autoinc = !fk && pi.generated ? " AUTO_INCREMENT" : "";
119         string def = "";
120         int len = 0;
121         string unsigned = "";
122         if (cast(NumberType)type !is null) {
123             len = (cast(NumberType)type).length;
124             unsigned = (cast(NumberType)type).unsigned ? " UNSIGNED" : "";
125         }
126         if (cast(StringType)type !is null) {
127             len = (cast(StringType)type).length;
128         }
129         string modifiers = unsigned ~ nullablility ~ def ~ pk ~ autoinc;
130         string lenmodifiers = "(" ~ to!string(len > 0 ? len : 255) ~ ")" ~ modifiers;
131         switch (sqlType) {
132             case SqlType.BIGINT:
133                 return "BIGINT" ~ modifiers;
134                 ///sometimes referred to as a type code, that identifies the generic SQL type BINARY.
135                 //BINARY,
136                 //sometimes referred to as a type code, that identifies the generic SQL type BIT.
137             case SqlType.BIT:
138                 return "TINYINT" ~ modifiers;
139                 ///sometimes referred to as a type code, that identifies the generic SQL type BLOB.
140             case SqlType.BLOB:
141                 return "BLOB";
142                 ///somtimes referred to as a type code, that identifies the generic SQL type BOOLEAN.
143             case SqlType.BOOLEAN:
144                 return "TINYINT" ~ modifiers;
145                 ///sometimes referred to as a type code, that identifies the generic SQL type CHAR.
146             case SqlType.CHAR:
147                 return "CHAR" ~ lenmodifiers;
148                 ///sometimes referred to as a type code, that identifies the generic SQL type CLOB.
149             case SqlType.CLOB:
150                 return "MEDIUMTEXT";
151                 //somtimes referred to as a type code, that identifies the generic SQL type DATALINK.
152                     //DATALINK,
153                     ///sometimes referred to as a type code, that identifies the generic SQL type DATE.
154             case SqlType.DATE:
155                 return "DATE" ~ modifiers;
156                 ///sometimes referred to as a type code, that identifies the generic SQL type DATETIME.
157             case SqlType.DATETIME:
158                 return "DATETIME" ~ modifiers;
159                 ///sometimes referred to as a type code, that identifies the generic SQL type DECIMAL.
160             case SqlType.DECIMAL:
161                 return "DOUBLE" ~ modifiers;
162                 //sometimes referred to as a type code, that identifies the generic SQL type DISTINCT.
163                     //DISTINCT,
164                     ///sometimes referred to as a type code, that identifies the generic SQL type DOUBLE.
165             case SqlType.DOUBLE:
166                 return "DOUBLE" ~ modifiers;
167                 ///sometimes referred to as a type code, that identifies the generic SQL type FLOAT.
168             case SqlType.FLOAT:
169                 return "FLOAT" ~ modifiers;
170                 ///sometimes referred to as a type code, that identifies the generic SQL type INTEGER.
171             case SqlType.INTEGER:
172                 return "INT" ~ modifiers;
173                 //sometimes referred to as a type code, that identifies the generic SQL type JAVA_OBJECT.
174                     //JAVA_OBJECT,
175                     ///sometimes referred to as a type code, that identifies the generic SQL type LONGNVARCHAR.
176             case SqlType.LONGNVARCHAR:
177                 return "VARCHAR" ~ lenmodifiers;
178                 ///sometimes referred to as a type code, that identifies the generic SQL type LONGVARBINARY.
179             case SqlType.LONGVARBINARY:
180                 return "VARCHAR" ~ lenmodifiers;
181                 ///sometimes referred to as a type code, that identifies the generic SQL type LONGVARCHAR.
182             case SqlType.LONGVARCHAR:
183                 return "VARCHAR" ~ lenmodifiers;
184                 ///sometimes referred to as a type code, that identifies the generic SQL type NCHAR
185             case SqlType.NCHAR:
186                 return "NCHAR" ~ lenmodifiers;
187                 ///sometimes referred to as a type code, that identifies the generic SQL type NCLOB.
188             case SqlType.NCLOB:
189                 return "MEDIUMTEXT";
190                 ///sometimes referred to as a type code, that identifies the generic SQL type NUMERIC.
191             case SqlType.NUMERIC:
192                 return "DOUBLE" ~ modifiers;
193                 ///sometimes referred to as a type code, that identifies the generic SQL type NVARCHAR.
194             case SqlType.NVARCHAR:
195                 return "NVARCHAR" ~ lenmodifiers;
196                 ///sometimes referred to as a type code, that identifies the generic SQL type SMALLINT.
197             case SqlType.SMALLINT:
198                 return "SMALLINT" ~ modifiers;
199                 //sometimes referred to as a type code, that identifies the generic SQL type XML.
200                     //SQLXML,
201                     //sometimes referred to as a type code, that identifies the generic SQL type STRUCT.
202                     //STRUCT,
203                     ///sometimes referred to as a type code, that identifies the generic SQL type TIME.
204             case SqlType.TIME:
205                 return "TIME" ~ modifiers;
206                 //sometimes referred to as a type code, that identifies the generic SQL type TIMESTAMP.
207                     //TIMESTAMP,
208                     ///sometimes referred to as a type code, that identifies the generic SQL type TINYINT.
209             case SqlType.TINYINT:
210                 return "TINYINT" ~ modifiers;
211                 ///sometimes referred to as a type code, that identifies the generic SQL type VARBINARY.
212             case SqlType.VARBINARY:
213                 return "VARCHAR" ~ lenmodifiers;
214                 ///sometimes referred to as a type code, that identifies the generic SQL type VARCHAR.
215             case SqlType.VARCHAR:
216                 return "VARCHAR" ~ lenmodifiers;
217             default:
218                 return "VARCHAR(255)";
219         }
220     }
221 
222 
223 	this() {
224 		addKeywords(MYSQL_RESERVED_WORDS);
225 	}
226 }
227 
228 
229 unittest {
230 	Dialect dialect = new MySQLDialect();
231 	assert(dialect.quoteSqlString("abc") == "'abc'");
232 	assert(dialect.quoteSqlString("a'b'c") == "'a\\'b\\'c'");
233 	assert(dialect.quoteSqlString("a\nc") == "'a\\nc'");
234 	assert(dialect.quoteIfNeeded("blabla") == "blabla");
235 	assert(dialect.quoteIfNeeded("true") == "`true`");
236 }