github.com/astaxie/beego@v1.12.3/orm/db_postgres.go (about) 1 // Copyright 2014 beego Author. All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package orm 16 17 import ( 18 "fmt" 19 "strconv" 20 ) 21 22 // postgresql operators. 23 var postgresOperators = map[string]string{ 24 "exact": "= ?", 25 "iexact": "= UPPER(?)", 26 "contains": "LIKE ?", 27 "icontains": "LIKE UPPER(?)", 28 "gt": "> ?", 29 "gte": ">= ?", 30 "lt": "< ?", 31 "lte": "<= ?", 32 "eq": "= ?", 33 "ne": "!= ?", 34 "startswith": "LIKE ?", 35 "endswith": "LIKE ?", 36 "istartswith": "LIKE UPPER(?)", 37 "iendswith": "LIKE UPPER(?)", 38 } 39 40 // postgresql column field types. 41 var postgresTypes = map[string]string{ 42 "auto": "serial NOT NULL PRIMARY KEY", 43 "pk": "NOT NULL PRIMARY KEY", 44 "bool": "bool", 45 "string": "varchar(%d)", 46 "string-char": "char(%d)", 47 "string-text": "text", 48 "time.Time-date": "date", 49 "time.Time": "timestamp with time zone", 50 "int8": `smallint CHECK("%COL%" >= -127 AND "%COL%" <= 128)`, 51 "int16": "smallint", 52 "int32": "integer", 53 "int64": "bigint", 54 "uint8": `smallint CHECK("%COL%" >= 0 AND "%COL%" <= 255)`, 55 "uint16": `integer CHECK("%COL%" >= 0)`, 56 "uint32": `bigint CHECK("%COL%" >= 0)`, 57 "uint64": `bigint CHECK("%COL%" >= 0)`, 58 "float64": "double precision", 59 "float64-decimal": "numeric(%d, %d)", 60 "json": "json", 61 "jsonb": "jsonb", 62 } 63 64 // postgresql dbBaser. 65 type dbBasePostgres struct { 66 dbBase 67 } 68 69 var _ dbBaser = new(dbBasePostgres) 70 71 // get postgresql operator. 72 func (d *dbBasePostgres) OperatorSQL(operator string) string { 73 return postgresOperators[operator] 74 } 75 76 // generate functioned sql string, such as contains(text). 77 func (d *dbBasePostgres) GenerateOperatorLeftCol(fi *fieldInfo, operator string, leftCol *string) { 78 switch operator { 79 case "contains", "startswith", "endswith": 80 *leftCol = fmt.Sprintf("%s::text", *leftCol) 81 case "iexact", "icontains", "istartswith", "iendswith": 82 *leftCol = fmt.Sprintf("UPPER(%s::text)", *leftCol) 83 } 84 } 85 86 // postgresql unsupports updating joined record. 87 func (d *dbBasePostgres) SupportUpdateJoin() bool { 88 return false 89 } 90 91 func (d *dbBasePostgres) MaxLimit() uint64 { 92 return 0 93 } 94 95 // postgresql quote is ". 96 func (d *dbBasePostgres) TableQuote() string { 97 return `"` 98 } 99 100 // postgresql value placeholder is $n. 101 // replace default ? to $n. 102 func (d *dbBasePostgres) ReplaceMarks(query *string) { 103 q := *query 104 num := 0 105 for _, c := range q { 106 if c == '?' { 107 num++ 108 } 109 } 110 if num == 0 { 111 return 112 } 113 data := make([]byte, 0, len(q)+num) 114 num = 1 115 for i := 0; i < len(q); i++ { 116 c := q[i] 117 if c == '?' { 118 data = append(data, '$') 119 data = append(data, []byte(strconv.Itoa(num))...) 120 num++ 121 } else { 122 data = append(data, c) 123 } 124 } 125 *query = string(data) 126 } 127 128 // make returning sql support for postgresql. 129 func (d *dbBasePostgres) HasReturningID(mi *modelInfo, query *string) bool { 130 fi := mi.fields.pk 131 if fi.fieldType&IsPositiveIntegerField == 0 && fi.fieldType&IsIntegerField == 0 { 132 return false 133 } 134 135 if query != nil { 136 *query = fmt.Sprintf(`%s RETURNING "%s"`, *query, fi.column) 137 } 138 return true 139 } 140 141 // sync auto key 142 func (d *dbBasePostgres) setval(db dbQuerier, mi *modelInfo, autoFields []string) error { 143 if len(autoFields) == 0 { 144 return nil 145 } 146 147 Q := d.ins.TableQuote() 148 for _, name := range autoFields { 149 query := fmt.Sprintf("SELECT setval(pg_get_serial_sequence('%s', '%s'), (SELECT MAX(%s%s%s) FROM %s%s%s));", 150 mi.table, name, 151 Q, name, Q, 152 Q, mi.table, Q) 153 if _, err := db.Exec(query); err != nil { 154 return err 155 } 156 } 157 return nil 158 } 159 160 // show table sql for postgresql. 161 func (d *dbBasePostgres) ShowTablesQuery() string { 162 return "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')" 163 } 164 165 // show table columns sql for postgresql. 166 func (d *dbBasePostgres) ShowColumnsQuery(table string) string { 167 return fmt.Sprintf("SELECT column_name, data_type, is_nullable FROM information_schema.columns where table_schema NOT IN ('pg_catalog', 'information_schema') and table_name = '%s'", table) 168 } 169 170 // get column types of postgresql. 171 func (d *dbBasePostgres) DbTypes() map[string]string { 172 return postgresTypes 173 } 174 175 // check index exist in postgresql. 176 func (d *dbBasePostgres) IndexExists(db dbQuerier, table string, name string) bool { 177 query := fmt.Sprintf("SELECT COUNT(*) FROM pg_indexes WHERE tablename = '%s' AND indexname = '%s'", table, name) 178 row := db.QueryRow(query) 179 var cnt int 180 row.Scan(&cnt) 181 return cnt > 0 182 } 183 184 // create new postgresql dbBaser. 185 func newdbBasePostgres() dbBaser { 186 b := new(dbBasePostgres) 187 b.ins = b 188 return b 189 }