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  }