1 /** 2 * HibernateD - Object-Relation Mapping for D programming language, with interface similar to Hibernate. 3 * 4 * Source file hibernated/dialects/sqlitedialect.d. 5 * 6 * This module contains implementation of PGSQLDialect 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 hibernated.dialects.pgsqldialect; 13 14 import std.conv; 15 16 import hibernated.dialect; 17 import hibernated.metadata; 18 import hibernated.type; 19 import ddbc.core; 20 21 22 string[] PGSQL_RESERVED_WORDS = 23 [ 24 "ABORT", 25 "ACTION", 26 "ADD", 27 "AFTER", 28 "ALL", 29 "ALTER", 30 "ANALYZE", 31 "AND", 32 "AS", 33 "ASC", 34 "ATTACH", 35 "AUTOINCREMENT", 36 "BEFORE", 37 "BEGIN", 38 "BETWEEN", 39 "BY", 40 "CASCADE", 41 "CASE", 42 "CAST", 43 "CHECK", 44 "COLLATE", 45 "COLUMN", 46 "COMMIT", 47 "CONFLICT", 48 "CONSTRAINT", 49 "CREATE", 50 "CROSS", 51 "CURRENT_DATE", 52 "CURRENT_TIME", 53 "CURRENT_TIMESTAMP", 54 "DATABASE", 55 "DEFAULT", 56 "DEFERRABLE", 57 "DEFERRED", 58 "DELETE", 59 "DESC", 60 "DETACH", 61 "DISTINCT", 62 "DROP", 63 "EACH", 64 "ELSE", 65 "END", 66 "ESCAPE", 67 "EXCEPT", 68 "EXCLUSIVE", 69 "EXISTS", 70 "EXPLAIN", 71 "FAIL", 72 "FOR", 73 "FOREIGN", 74 "FROM", 75 "FULL", 76 "GLOB", 77 "GROUP", 78 "HAVING", 79 "IF", 80 "IGNORE", 81 "IMMEDIATE", 82 "IN", 83 "INDEX", 84 "INDEXED", 85 "INITIALLY", 86 "INNER", 87 "INSERT", 88 "INSTEAD", 89 "INTERSECT", 90 "INTO", 91 "IS", 92 "ISNULL", 93 "JOIN", 94 "KEY", 95 "LEFT", 96 "LIKE", 97 "LIMIT", 98 "MATCH", 99 "NATURAL", 100 "NO", 101 "NOT", 102 "NOTNULL", 103 "NULL", 104 "OF", 105 "OFFSET", 106 "ON", 107 "OR", 108 "ORDER", 109 "OUTER", 110 "PLAN", 111 "PRAGMA", 112 "PRIMARY", 113 "QUERY", 114 "RAISE", 115 "REFERENCES", 116 "REGEXP", 117 "REINDEX", 118 "RELEASE", 119 "RENAME", 120 "REPLACE", 121 "RESTRICT", 122 "RIGHT", 123 "ROLLBACK", 124 "ROW", 125 "SAVEPOINT", 126 "SELECT", 127 "SET", 128 "TABLE", 129 "TEMP", 130 "TEMPORARY", 131 "THEN", 132 "TO", 133 "TRANSACTION", 134 "TRIGGER", 135 "UNION", 136 "UNIQUE", 137 "UPDATE", 138 "USING", 139 "VACUUM", 140 "VALUES", 141 "VIEW", 142 "VIRTUAL", 143 "WHEN", 144 "WHERE", 145 ]; 146 147 148 class PGSQLDialect : Dialect { 149 ///The character specific to this dialect used to close a quoted identifier. 150 override char closeQuote() const { return '`'; } 151 ///The character specific to this dialect used to begin a quoted identifier. 152 override char openQuote() const { return '`'; } 153 154 // returns string like "BIGINT(20) NOT NULL" or "VARCHAR(255) NULL" 155 override string getColumnTypeDefinition(const PropertyInfo pi, const PropertyInfo overrideTypeFrom = null) { 156 immutable Type type = overrideTypeFrom !is null ? overrideTypeFrom.columnType : pi.columnType; 157 immutable SqlType sqlType = type.getSqlType(); 158 bool fk = pi is null; 159 string nullablility = !fk && pi.nullable ? " NULL" : " NOT NULL"; 160 string pk = !fk && pi.key ? " PRIMARY KEY" : ""; 161 if (!fk && pi.generated) { 162 if (sqlType == SqlType.SMALLINT || sqlType == SqlType.TINYINT) 163 return "SERIAL PRIMARY KEY"; 164 if (sqlType == SqlType.INTEGER) 165 return "SERIAL PRIMARY KEY"; 166 return "BIGSERIAL PRIMARY KEY"; 167 } 168 string def = ""; 169 int len = 0; 170 if (cast(NumberType)type !is null) { 171 len = (cast(NumberType)type).length; 172 } 173 if (cast(StringType)type !is null) { 174 len = (cast(StringType)type).length; 175 } 176 string modifiers = nullablility ~ def ~ pk; 177 string lenmodifiers = "(" ~ to!string(len > 0 ? len : 255) ~ ")" ~ modifiers; 178 switch (sqlType) { 179 case SqlType.BIGINT: 180 return "BIGINT" ~ modifiers; 181 case SqlType.BIT: 182 case SqlType.BOOLEAN: 183 return "BOOLEAN" ~ modifiers; 184 case SqlType.INTEGER: 185 return "INT" ~ modifiers; 186 case SqlType.NUMERIC: 187 return "INT" ~ modifiers; 188 case SqlType.SMALLINT: 189 return "SMALLINT" ~ modifiers; 190 case SqlType.TINYINT: 191 return "SMALLINT" ~ modifiers; 192 case SqlType.FLOAT: 193 return "FLOAT(24)" ~ modifiers; 194 case SqlType.DOUBLE: 195 return "FLOAT(53)" ~ modifiers; 196 case SqlType.DECIMAL: 197 return "REAL" ~ modifiers; 198 case SqlType.DATE: 199 return "DATE" ~ modifiers; 200 case SqlType.DATETIME: 201 return "TIMESTAMP" ~ modifiers; 202 case SqlType.TIME: 203 return "TIME" ~ modifiers; 204 case SqlType.CHAR: 205 case SqlType.CLOB: 206 case SqlType.LONGNVARCHAR: 207 case SqlType.LONGVARBINARY: 208 case SqlType.LONGVARCHAR: 209 case SqlType.NCHAR: 210 case SqlType.NCLOB: 211 case SqlType.VARBINARY: 212 case SqlType.VARCHAR: 213 case SqlType.NVARCHAR: 214 return "TEXT" ~ modifiers; 215 case SqlType.BLOB: 216 return "BYTEA"; 217 default: 218 return "TEXT"; 219 } 220 } 221 222 override string getCheckTableExistsSQL(string tableName) { 223 return "select relname from pg_class where relname = " ~ quoteSqlString(tableName) ~ " and relkind='r'"; 224 } 225 226 override string getUniqueIndexItemSQL(string indexName, string[] columnNames) { 227 return "UNIQUE " ~ createFieldListSQL(columnNames); 228 } 229 230 /// for some of RDBMS it's necessary to pass additional clauses in query to get generated value (e.g. in Postgres - " returing id" 231 override string appendInsertToFetchGeneratedKey(string query, const EntityInfo entity) { 232 return query ~ " RETURNING " ~ quoteIfNeeded(entity.getKeyProperty().columnName); 233 } 234 235 this() { 236 addKeywords(PGSQL_RESERVED_WORDS); 237 } 238 } 239