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 }