1 /** 2 * DStruct - Object-Relation Mapping for D programming language, with interface similar to Hibernate. 3 * 4 * Source file dstruct/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 dstruct.dialects.pgsqldialect; 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 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 "USER", 139 "USING", 140 "VACUUM", 141 "VALUES", 142 "VIEW", 143 "VIRTUAL", 144 "WHEN", 145 "WHERE", 146 ]; 147 148 149 class PGSQLDialect : Dialect { 150 ///The character specific to this dialect used to close a quoted identifier. 151 override char closeQuote() const { return '"'; } 152 ///The character specific to this dialect used to begin a quoted identifier. 153 override char openQuote() const { return '"'; } 154 155 // returns string like "BIGINT(20) NOT NULL" or "VARCHAR(255) NULL" 156 override string getColumnTypeDefinition(const PropertyInfo pi, const PropertyInfo overrideTypeFrom = null) { 157 immutable Type type = overrideTypeFrom !is null ? overrideTypeFrom.columnType : pi.columnType; 158 immutable SqlType sqlType = type.getSqlType(); 159 bool fk = pi is null; 160 string nullablility = !fk && pi.nullable ? " NULL" : " NOT NULL"; 161 string pk = !fk && pi.key ? " PRIMARY KEY" : ""; 162 if (!fk && pi.generated) { 163 if (sqlType == SqlType.SMALLINT || sqlType == SqlType.TINYINT) 164 return "SERIAL PRIMARY KEY"; 165 if (sqlType == SqlType.INTEGER) 166 return "SERIAL PRIMARY KEY"; 167 return "BIGSERIAL PRIMARY KEY"; 168 } 169 string def = ""; 170 int len = 0; 171 if (cast(NumberType)type !is null) { 172 len = (cast(NumberType)type).length; 173 } 174 if (cast(StringType)type !is null) { 175 len = (cast(StringType)type).length; 176 } 177 string modifiers = nullablility ~ def ~ pk; 178 string lenmodifiers = "(" ~ to!string(len > 0 ? len : 255) ~ ")" ~ modifiers; 179 switch (sqlType) { 180 case SqlType.BIGINT: 181 return "BIGINT" ~ modifiers; 182 case SqlType.BIT: 183 case SqlType.BOOLEAN: 184 return "BOOLEAN" ~ modifiers; 185 case SqlType.INTEGER: 186 return "INT" ~ modifiers; 187 case SqlType.NUMERIC: 188 return "INT" ~ modifiers; 189 case SqlType.SMALLINT: 190 return "SMALLINT" ~ modifiers; 191 case SqlType.TINYINT: 192 return "SMALLINT" ~ modifiers; 193 case SqlType.FLOAT: 194 return "FLOAT(24)" ~ modifiers; 195 case SqlType.DOUBLE: 196 return "FLOAT(53)" ~ modifiers; 197 case SqlType.DECIMAL: 198 return "REAL" ~ modifiers; 199 case SqlType.DATE: 200 return "DATE" ~ modifiers; 201 case SqlType.DATETIME: 202 return "TIMESTAMP" ~ modifiers; 203 case SqlType.TIME: 204 return "TIME" ~ modifiers; 205 case SqlType.CHAR: 206 case SqlType.CLOB: 207 case SqlType.LONGNVARCHAR: 208 case SqlType.LONGVARBINARY: 209 case SqlType.LONGVARCHAR: 210 case SqlType.NCHAR: 211 case SqlType.NCLOB: 212 case SqlType.VARBINARY: 213 case SqlType.VARCHAR: 214 case SqlType.NVARCHAR: 215 return "TEXT" ~ modifiers; 216 case SqlType.BLOB: 217 return "BYTEA"; 218 default: 219 return "TEXT"; 220 } 221 } 222 223 override string getCheckTableExistsSQL(string tableName) { 224 return "select relname from pg_class where relname = " ~ quoteSqlString(tableName) ~ " and relkind='r'"; 225 } 226 227 override string getUniqueIndexItemSQL(string indexName, string[] columnNames) { 228 return "UNIQUE " ~ createFieldListSQL(columnNames); 229 } 230 231 /// for some of RDBMS it's necessary to pass additional clauses in query to get generated value (e.g. in Postgres - " returing id" 232 override string appendInsertToFetchGeneratedKey(string query, const EntityInfo entity) { 233 return query ~ " RETURNING " ~ quoteIfNeeded(entity.getKeyProperty().columnName); 234 } 235 236 this() { 237 addKeywords(PGSQL_RESERVED_WORDS); 238 } 239 } 240