github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/go-xorm/xorm/mssql_dialect.go (about) 1 // Copyright 2015 The Xorm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xorm 6 7 import ( 8 "fmt" 9 "strconv" 10 "strings" 11 12 "github.com/insionng/yougam/libraries/go-xorm/core" 13 ) 14 15 var ( 16 mssqlReservedWords = map[string]bool{ 17 "ADD": true, 18 "EXTERNAL": true, 19 "PROCEDURE": true, 20 "ALL": true, 21 "FETCH": true, 22 "PUBLIC": true, 23 "ALTER": true, 24 "FILE": true, 25 "RAISERROR": true, 26 "AND": true, 27 "FILLFACTOR": true, 28 "READ": true, 29 "ANY": true, 30 "FOR": true, 31 "READTEXT": true, 32 "AS": true, 33 "FOREIGN": true, 34 "RECONFIGURE": true, 35 "ASC": true, 36 "FREETEXT": true, 37 "REFERENCES": true, 38 "AUTHORIZATION": true, 39 "FREETEXTTABLE": true, 40 "REPLICATION": true, 41 "BACKUP": true, 42 "FROM": true, 43 "RESTORE": true, 44 "BEGIN": true, 45 "FULL": true, 46 "RESTRICT": true, 47 "BETWEEN": true, 48 "FUNCTION": true, 49 "RETURN": true, 50 "BREAK": true, 51 "GOTO": true, 52 "REVERT": true, 53 "BROWSE": true, 54 "GRANT": true, 55 "REVOKE": true, 56 "BULK": true, 57 "GROUP": true, 58 "RIGHT": true, 59 "BY": true, 60 "HAVING": true, 61 "ROLLBACK": true, 62 "CASCADE": true, 63 "HOLDLOCK": true, 64 "ROWCOUNT": true, 65 "CASE": true, 66 "IDENTITY": true, 67 "ROWGUIDCOL": true, 68 "CHECK": true, 69 "IDENTITY_INSERT": true, 70 "RULE": true, 71 "CHECKPOINT": true, 72 "IDENTITYCOL": true, 73 "SAVE": true, 74 "CLOSE": true, 75 "IF": true, 76 "SCHEMA": true, 77 "CLUSTERED": true, 78 "IN": true, 79 "SECURITYAUDIT": true, 80 "COALESCE": true, 81 "INDEX": true, 82 "SELECT": true, 83 "COLLATE": true, 84 "INNER": true, 85 "SEMANTICKEYPHRASETABLE": true, 86 "COLUMN": true, 87 "INSERT": true, 88 "SEMANTICSIMILARITYDETAILSTABLE": true, 89 "COMMIT": true, 90 "INTERSECT": true, 91 "SEMANTICSIMILARITYTABLE": true, 92 "COMPUTE": true, 93 "INTO": true, 94 "SESSION_USER": true, 95 "CONSTRAINT": true, 96 "IS": true, 97 "SET": true, 98 "CONTAINS": true, 99 "JOIN": true, 100 "SETUSER": true, 101 "CONTAINSTABLE": true, 102 "KEY": true, 103 "SHUTDOWN": true, 104 "CONTINUE": true, 105 "KILL": true, 106 "SOME": true, 107 "CONVERT": true, 108 "LEFT": true, 109 "STATISTICS": true, 110 "CREATE": true, 111 "LIKE": true, 112 "SYSTEM_USER": true, 113 "CROSS": true, 114 "LINENO": true, 115 "TABLE": true, 116 "CURRENT": true, 117 "LOAD": true, 118 "TABLESAMPLE": true, 119 "CURRENT_DATE": true, 120 "MERGE": true, 121 "TEXTSIZE": true, 122 "CURRENT_TIME": true, 123 "NATIONAL": true, 124 "THEN": true, 125 "CURRENT_TIMESTAMP": true, 126 "NOCHECK": true, 127 "TO": true, 128 "CURRENT_USER": true, 129 "NONCLUSTERED": true, 130 "TOP": true, 131 "CURSOR": true, 132 "NOT": true, 133 "TRAN": true, 134 "DATABASE": true, 135 "NULL": true, 136 "TRANSACTION": true, 137 "DBCC": true, 138 "NULLIF": true, 139 "TRIGGER": true, 140 "DEALLOCATE": true, 141 "OF": true, 142 "TRUNCATE": true, 143 "DECLARE": true, 144 "OFF": true, 145 "TRY_CONVERT": true, 146 "DEFAULT": true, 147 "OFFSETS": true, 148 "TSEQUAL": true, 149 "DELETE": true, 150 "ON": true, 151 "UNION": true, 152 "DENY": true, 153 "OPEN": true, 154 "UNIQUE": true, 155 "DESC": true, 156 "OPENDATASOURCE": true, 157 "UNPIVOT": true, 158 "DISK": true, 159 "OPENQUERY": true, 160 "UPDATE": true, 161 "DISTINCT": true, 162 "OPENROWSET": true, 163 "UPDATETEXT": true, 164 "DISTRIBUTED": true, 165 "OPENXML": true, 166 "USE": true, 167 "DOUBLE": true, 168 "OPTION": true, 169 "USER": true, 170 "DROP": true, 171 "OR": true, 172 "VALUES": true, 173 "DUMP": true, 174 "ORDER": true, 175 "VARYING": true, 176 "ELSE": true, 177 "OUTER": true, 178 "VIEW": true, 179 "END": true, 180 "OVER": true, 181 "WAITFOR": true, 182 "ERRLVL": true, 183 "PERCENT": true, 184 "WHEN": true, 185 "ESCAPE": true, 186 "PIVOT": true, 187 "WHERE": true, 188 "EXCEPT": true, 189 "PLAN": true, 190 "WHILE": true, 191 "EXEC": true, 192 "PRECISION": true, 193 "WITH": true, 194 "EXECUTE": true, 195 "PRIMARY": true, 196 "WITHIN": true, 197 "EXISTS": true, 198 "PRINT": true, 199 "WRITETEXT": true, 200 "EXIT": true, 201 "PROC": true, 202 } 203 ) 204 205 type mssql struct { 206 core.Base 207 } 208 209 func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { 210 return db.Base.Init(d, db, uri, drivername, dataSourceName) 211 } 212 213 func (db *mssql) SqlType(c *core.Column) string { 214 var res string 215 switch t := c.SQLType.Name; t { 216 case core.Bool: 217 res = core.TinyInt 218 if c.Default == "true" { 219 c.Default = "1" 220 } else if c.Default == "false" { 221 c.Default = "0" 222 } 223 case core.Serial: 224 c.IsAutoIncrement = true 225 c.IsPrimaryKey = true 226 c.Nullable = false 227 res = core.Int 228 case core.BigSerial: 229 c.IsAutoIncrement = true 230 c.IsPrimaryKey = true 231 c.Nullable = false 232 res = core.BigInt 233 case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob: 234 res = core.VarBinary 235 if c.Length == 0 { 236 c.Length = 50 237 } 238 case core.TimeStamp: 239 res = core.DateTime 240 case core.TimeStampz: 241 res = "DATETIMEOFFSET" 242 c.Length = 7 243 case core.MediumInt: 244 res = core.Int 245 case core.MediumText, core.TinyText, core.LongText, core.Json: 246 res = core.Text 247 case core.Double: 248 res = core.Real 249 case core.Uuid: 250 res = core.Varchar 251 c.Length = 40 252 default: 253 res = t 254 } 255 256 if res == core.Int { 257 return core.Int 258 } 259 260 hasLen1 := (c.Length > 0) 261 hasLen2 := (c.Length2 > 0) 262 263 if hasLen2 { 264 res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" 265 } else if hasLen1 { 266 res += "(" + strconv.Itoa(c.Length) + ")" 267 } 268 return res 269 } 270 271 func (db *mssql) SupportInsertMany() bool { 272 return true 273 } 274 275 func (db *mssql) IsReserved(name string) bool { 276 _, ok := mssqlReservedWords[name] 277 return ok 278 } 279 280 func (db *mssql) Quote(name string) string { 281 return "\"" + name + "\"" 282 } 283 284 func (db *mssql) QuoteStr() string { 285 return "\"" 286 } 287 288 func (db *mssql) SupportEngine() bool { 289 return false 290 } 291 292 func (db *mssql) AutoIncrStr() string { 293 return "IDENTITY" 294 } 295 296 func (db *mssql) DropTableSql(tableName string) string { 297 return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+ 298 "object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+ 299 "DROP TABLE \"%s\"", tableName, tableName) 300 } 301 302 func (db *mssql) SupportCharset() bool { 303 return false 304 } 305 306 func (db *mssql) IndexOnTable() bool { 307 return true 308 } 309 310 func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { 311 args := []interface{}{idxName} 312 sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?" 313 return sql, args 314 } 315 316 /*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { 317 args := []interface{}{tableName, colName} 318 sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?` 319 return sql, args 320 }*/ 321 322 func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) { 323 query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?` 324 325 return db.HasRecords(query, tableName, colName) 326 } 327 328 func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { 329 args := []interface{}{} 330 sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1" 331 return sql, args 332 } 333 334 func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { 335 args := []interface{}{} 336 s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable, 337 replace(replace(isnull(c.text,''),'(',''),')','') as vdefault 338 from sys.columns a left join sys.types b on a.user_type_id=b.user_type_id 339 left join sys.syscomments c on a.default_object_id=c.id 340 where a.object_id=object_id('` + tableName + `')` 341 db.LogSQL(s, args) 342 343 rows, err := db.DB().Query(s, args...) 344 if err != nil { 345 return nil, nil, err 346 } 347 defer rows.Close() 348 349 cols := make(map[string]*core.Column) 350 colSeq := make([]string, 0) 351 for rows.Next() { 352 var name, ctype, vdefault string 353 var maxLen, precision, scale int 354 var nullable bool 355 err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &vdefault) 356 if err != nil { 357 return nil, nil, err 358 } 359 360 col := new(core.Column) 361 col.Indexes = make(map[string]int) 362 col.Name = strings.Trim(name, "` ") 363 col.Nullable = nullable 364 col.Default = vdefault 365 ct := strings.ToUpper(ctype) 366 if ct == "DECIMAL" { 367 col.Length = precision 368 col.Length2 = scale 369 } else { 370 col.Length = maxLen 371 } 372 switch ct { 373 case "DATETIMEOFFSET": 374 col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0} 375 case "NVARCHAR": 376 col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0} 377 case "IMAGE": 378 col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0} 379 default: 380 if _, ok := core.SqlTypes[ct]; ok { 381 col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0} 382 } else { 383 return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name) 384 } 385 } 386 387 if col.SQLType.IsText() || col.SQLType.IsTime() { 388 if col.Default != "" { 389 col.Default = "'" + col.Default + "'" 390 } else { 391 if col.DefaultIsEmpty { 392 col.Default = "''" 393 } 394 } 395 } 396 cols[col.Name] = col 397 colSeq = append(colSeq, col.Name) 398 } 399 return colSeq, cols, nil 400 } 401 402 func (db *mssql) GetTables() ([]*core.Table, error) { 403 args := []interface{}{} 404 s := `select name from sysobjects where xtype ='U'` 405 db.LogSQL(s, args) 406 407 rows, err := db.DB().Query(s, args...) 408 if err != nil { 409 return nil, err 410 } 411 defer rows.Close() 412 413 tables := make([]*core.Table, 0) 414 for rows.Next() { 415 table := core.NewEmptyTable() 416 var name string 417 err = rows.Scan(&name) 418 if err != nil { 419 return nil, err 420 } 421 table.Name = strings.Trim(name, "` ") 422 tables = append(tables, table) 423 } 424 return tables, nil 425 } 426 427 func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) { 428 args := []interface{}{tableName} 429 s := `SELECT 430 IXS.NAME AS [INDEX_NAME], 431 C.NAME AS [COLUMN_NAME], 432 IXS.is_unique AS [IS_UNIQUE] 433 FROM SYS.INDEXES IXS 434 INNER JOIN SYS.INDEX_COLUMNS IXCS 435 ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID 436 INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID 437 AND IXCS.COLUMN_ID=C.COLUMN_ID 438 WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? 439 ` 440 db.LogSQL(s, args) 441 442 rows, err := db.DB().Query(s, args...) 443 if err != nil { 444 return nil, err 445 } 446 defer rows.Close() 447 448 indexes := make(map[string]*core.Index, 0) 449 for rows.Next() { 450 var indexType int 451 var indexName, colName, isUnique string 452 453 err = rows.Scan(&indexName, &colName, &isUnique) 454 if err != nil { 455 return nil, err 456 } 457 458 i, err := strconv.ParseBool(isUnique) 459 if err != nil { 460 return nil, err 461 } 462 463 if i { 464 indexType = core.UniqueType 465 } else { 466 indexType = core.IndexType 467 } 468 469 colName = strings.Trim(colName, "` ") 470 471 if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { 472 indexName = indexName[5+len(tableName):] 473 } 474 475 var index *core.Index 476 var ok bool 477 if index, ok = indexes[indexName]; !ok { 478 index = new(core.Index) 479 index.Type = indexType 480 index.Name = indexName 481 indexes[indexName] = index 482 } 483 index.AddColumn(colName) 484 } 485 return indexes, nil 486 } 487 488 func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string { 489 var sql string 490 if tableName == "" { 491 tableName = table.Name 492 } 493 494 sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE " 495 496 sql += db.QuoteStr() + tableName + db.QuoteStr() + " (" 497 498 pkList := table.PrimaryKeys 499 500 for _, colName := range table.ColumnsSeq() { 501 col := table.GetColumn(colName) 502 if col.IsPrimaryKey && len(pkList) == 1 { 503 sql += col.String(db) 504 } else { 505 sql += col.StringNoPk(db) 506 } 507 sql = strings.TrimSpace(sql) 508 sql += ", " 509 } 510 511 if len(pkList) > 1 { 512 sql += "PRIMARY KEY ( " 513 sql += strings.Join(pkList, ",") 514 sql += " ), " 515 } 516 517 sql = sql[:len(sql)-2] + ")" 518 sql += ";" 519 return sql 520 } 521 522 func (db *mssql) ForUpdateSql(query string) string { 523 return query 524 } 525 526 func (db *mssql) Filters() []core.Filter { 527 return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}} 528 }