2014-08-18 08:41:43 +00:00
// Copyright 2014 beego Author. All Rights Reserved.
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// http://www.apache.org/licenses/LICENSE-2.0
2014-07-03 15:40:21 +00:00
//
2014-08-18 08:41:43 +00:00
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
2013-07-30 12:32:38 +00:00
package orm
2013-08-10 16:15:26 +00:00
import (
2013-08-11 14:27:45 +00:00
"fmt"
2013-08-10 16:15:26 +00:00
"strconv"
)
2014-01-17 09:25:17 +00:00
// postgresql operators.
2013-08-10 16:15:26 +00:00
var postgresOperators = map [ string ] string {
"exact" : "= ?" ,
"iexact" : "= UPPER(?)" ,
"contains" : "LIKE ?" ,
"icontains" : "LIKE UPPER(?)" ,
"gt" : "> ?" ,
"gte" : ">= ?" ,
"lt" : "< ?" ,
"lte" : "<= ?" ,
2015-06-09 02:18:21 +00:00
"eq" : "= ?" ,
"ne" : "!= ?" ,
2013-08-10 16:15:26 +00:00
"startswith" : "LIKE ?" ,
"endswith" : "LIKE ?" ,
"istartswith" : "LIKE UPPER(?)" ,
"iendswith" : "LIKE UPPER(?)" ,
}
2014-01-17 09:25:17 +00:00
// postgresql column field types.
2013-08-19 14:37:39 +00:00
var postgresTypes = map [ string ] string {
"auto" : "serial NOT NULL PRIMARY KEY" ,
"pk" : "NOT NULL PRIMARY KEY" ,
"bool" : "bool" ,
"string" : "varchar(%d)" ,
"string-text" : "text" ,
"time.Time-date" : "date" ,
"time.Time" : "timestamp with time zone" ,
"int8" : ` smallint CHECK("%COL%" >= -127 AND "%COL%" <= 128) ` ,
"int16" : "smallint" ,
"int32" : "integer" ,
"int64" : "bigint" ,
"uint8" : ` smallint CHECK("%COL%" >= 0 AND "%COL%" <= 255) ` ,
"uint16" : ` integer CHECK("%COL%" >= 0) ` ,
"uint32" : ` bigint CHECK("%COL%" >= 0) ` ,
"uint64" : ` bigint CHECK("%COL%" >= 0) ` ,
"float64" : "double precision" ,
"float64-decimal" : "numeric(%d, %d)" ,
}
2014-01-17 09:25:17 +00:00
// postgresql dbBaser.
2013-07-30 12:32:38 +00:00
type dbBasePostgres struct {
dbBase
}
2013-08-10 16:15:26 +00:00
var _ dbBaser = new ( dbBasePostgres )
2014-01-17 09:25:17 +00:00
// get postgresql operator.
2015-09-12 13:46:43 +00:00
func ( d * dbBasePostgres ) OperatorSQL ( operator string ) string {
2013-08-10 16:15:26 +00:00
return postgresOperators [ operator ]
}
2014-01-17 09:25:17 +00:00
// generate functioned sql string, such as contains(text).
2013-08-13 09:16:12 +00:00
func ( d * dbBasePostgres ) GenerateOperatorLeftCol ( fi * fieldInfo , operator string , leftCol * string ) {
2013-08-11 14:27:45 +00:00
switch operator {
case "contains" , "startswith" , "endswith" :
* leftCol = fmt . Sprintf ( "%s::text" , * leftCol )
case "iexact" , "icontains" , "istartswith" , "iendswith" :
* leftCol = fmt . Sprintf ( "UPPER(%s::text)" , * leftCol )
}
}
2014-01-17 09:25:17 +00:00
// postgresql unsupports updating joined record.
2013-08-11 14:27:45 +00:00
func ( d * dbBasePostgres ) SupportUpdateJoin ( ) bool {
return false
}
func ( d * dbBasePostgres ) MaxLimit ( ) uint64 {
return 0
}
2014-01-17 09:25:17 +00:00
// postgresql quote is ".
2013-08-10 16:15:26 +00:00
func ( d * dbBasePostgres ) TableQuote ( ) string {
return ` " `
}
2014-01-17 09:25:17 +00:00
// postgresql value placeholder is $n.
// replace default ? to $n.
2013-08-10 16:15:26 +00:00
func ( d * dbBasePostgres ) ReplaceMarks ( query * string ) {
q := * query
num := 0
for _ , c := range q {
if c == '?' {
2015-09-12 13:46:43 +00:00
num ++
2013-08-10 16:15:26 +00:00
}
}
if num == 0 {
return
}
data := make ( [ ] byte , 0 , len ( q ) + num )
num = 1
for i := 0 ; i < len ( q ) ; i ++ {
c := q [ i ]
if c == '?' {
data = append ( data , '$' )
data = append ( data , [ ] byte ( strconv . Itoa ( num ) ) ... )
2015-09-12 13:46:43 +00:00
num ++
2013-08-10 16:15:26 +00:00
} else {
data = append ( data , c )
}
}
* query = string ( data )
}
2014-01-17 09:25:17 +00:00
// make returning sql support for postgresql.
2016-03-24 12:03:45 +00:00
func ( d * dbBasePostgres ) HasReturningID ( mi * modelInfo , query * string ) bool {
fi := mi . fields . pk
if fi . fieldType & IsPositiveIntegerField == 0 && fi . fieldType & IsIntegerField == 0 {
return false
}
if query != nil {
* query = fmt . Sprintf ( ` %s RETURNING "%s" ` , * query , fi . column )
2013-08-11 14:27:45 +00:00
}
2016-03-24 12:03:45 +00:00
return true
2013-08-11 14:27:45 +00:00
}
2013-08-10 16:15:26 +00:00
2016-03-27 07:06:57 +00:00
// sync auto key
func ( d * dbBasePostgres ) setval ( db dbQuerier , mi * modelInfo , autoFields [ ] string ) error {
if len ( autoFields ) == 0 {
return nil
}
Q := d . ins . TableQuote ( )
for _ , name := range autoFields {
query := fmt . Sprintf ( "SELECT setval(pg_get_serial_sequence('%s', '%s'), (SELECT MAX(%s%s%s) FROM %s%s%s));" ,
mi . table , name ,
Q , name , Q ,
Q , mi . table , Q )
if _ , err := db . Exec ( query ) ; err != nil {
return err
}
}
return nil
}
2014-01-17 09:25:17 +00:00
// show table sql for postgresql.
2013-08-27 04:33:27 +00:00
func ( d * dbBasePostgres ) ShowTablesQuery ( ) string {
return "SELECT table_name FROM information_schema.tables WHERE table_type = 'BASE TABLE' AND table_schema NOT IN ('pg_catalog', 'information_schema')"
}
2014-01-17 09:25:17 +00:00
// show table columns sql for postgresql.
2013-08-27 04:33:27 +00:00
func ( d * dbBasePostgres ) ShowColumnsQuery ( table string ) string {
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 )
}
2014-01-17 09:25:17 +00:00
// get column types of postgresql.
2013-08-19 14:37:39 +00:00
func ( d * dbBasePostgres ) DbTypes ( ) map [ string ] string {
return postgresTypes
}
2014-01-17 09:25:17 +00:00
// check index exist in postgresql.
2013-08-27 04:33:27 +00:00
func ( d * dbBasePostgres ) IndexExists ( db dbQuerier , table string , name string ) bool {
query := fmt . Sprintf ( "SELECT COUNT(*) FROM pg_indexes WHERE tablename = '%s' AND indexname = '%s'" , table , name )
row := db . QueryRow ( query )
var cnt int
row . Scan ( & cnt )
return cnt > 0
}
2014-01-17 09:25:17 +00:00
// create new postgresql dbBaser.
2013-07-30 12:32:38 +00:00
func newdbBasePostgres ( ) dbBaser {
b := new ( dbBasePostgres )
b . ins = b
return b
}