xorm/dialects/postgres.go

1358 lines
48 KiB
Go
Raw Normal View History

2015-04-28 08:25:04 +00:00
// Copyright 2015 The Xorm Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package dialects
import (
"context"
2017-03-23 06:05:32 +00:00
"errors"
2013-12-18 03:31:32 +00:00
"fmt"
2017-03-23 06:05:32 +00:00
"net/url"
2013-12-18 03:31:32 +00:00
"strconv"
"strings"
"xorm.io/xorm/core"
"xorm.io/xorm/schemas"
2014-01-07 09:33:27 +00:00
)
2014-09-22 01:47:30 +00:00
// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
var (
2014-09-07 00:32:58 +00:00
postgresReservedWords = map[string]bool{
"A": true,
"ABORT": true,
"ABS": true,
"ABSENT": true,
"ABSOLUTE": true,
"ACCESS": true,
"ACCORDING": true,
"ACTION": true,
"ADA": true,
"ADD": true,
"ADMIN": true,
"AFTER": true,
"AGGREGATE": true,
"ALL": true,
"ALLOCATE": true,
"ALSO": true,
"ALTER": true,
"ALWAYS": true,
"ANALYSE": true,
"ANALYZE": true,
"AND": true,
"ANY": true,
"ARE": true,
"ARRAY": true,
"ARRAY_AGG": true,
"ARRAY_MAX_CARDINALITY": true,
2014-09-07 00:32:58 +00:00
"AS": true,
"ASC": true,
"ASENSITIVE": true,
"ASSERTION": true,
"ASSIGNMENT": true,
"ASYMMETRIC": true,
"AT": true,
"ATOMIC": true,
"ATTRIBUTE": true,
"ATTRIBUTES": true,
"AUTHORIZATION": true,
"AVG": true,
"BACKWARD": true,
"BASE64": true,
"BEFORE": true,
"BEGIN": true,
"BEGIN_FRAME": true,
"BEGIN_PARTITION": true,
"BERNOULLI": true,
"BETWEEN": true,
"BIGINT": true,
"BINARY": true,
"BIT": true,
"BIT_LENGTH": true,
"BLOB": true,
"BLOCKED": true,
"BOM": true,
"BOOLEAN": true,
"BOTH": true,
"BREADTH": true,
"BY": true,
"C": true,
"CACHE": true,
"CALL": true,
"CALLED": true,
"CARDINALITY": true,
"CASCADE": true,
"CASCADED": true,
"CASE": true,
"CAST": true,
"CATALOG": true,
"CATALOG_NAME": true,
"CEIL": true,
"CEILING": true,
"CHAIN": true,
"CHAR": true,
"CHARACTER": true,
"CHARACTERISTICS": true,
"CHARACTERS": true,
"CHARACTER_LENGTH": true,
"CHARACTER_SET_CATALOG": true,
"CHARACTER_SET_NAME": true,
"CHARACTER_SET_SCHEMA": true,
"CHAR_LENGTH": true,
"CHECK": true,
"CHECKPOINT": true,
"CLASS": true,
"CLASS_ORIGIN": true,
"CLOB": true,
"CLOSE": true,
"CLUSTER": true,
"COALESCE": true,
"COBOL": true,
"COLLATE": true,
"COLLATION": true,
"COLLATION_CATALOG": true,
"COLLATION_NAME": true,
"COLLATION_SCHEMA": true,
"COLLECT": true,
"COLUMN": true,
"COLUMNS": true,
"COLUMN_NAME": true,
"COMMAND_FUNCTION": true,
"COMMAND_FUNCTION_CODE": true,
"COMMENT": true,
"COMMENTS": true,
"COMMIT": true,
"COMMITTED": true,
"CONCURRENTLY": true,
"CONDITION": true,
"CONDITION_NUMBER": true,
"CONFIGURATION": true,
"CONNECT": true,
"CONNECTION": true,
"CONNECTION_NAME": true,
"CONSTRAINT": true,
"CONSTRAINTS": true,
"CONSTRAINT_CATALOG": true,
"CONSTRAINT_NAME": true,
"CONSTRAINT_SCHEMA": true,
"CONSTRUCTOR": true,
"CONTAINS": true,
"CONTENT": true,
"CONTINUE": true,
"CONTROL": true,
"CONVERSION": true,
"CONVERT": true,
"COPY": true,
"CORR": true,
"CORRESPONDING": true,
"COST": true,
"COUNT": true,
"COVAR_POP": true,
"COVAR_SAMP": true,
"CREATE": true,
"CROSS": true,
"CSV": true,
"CUBE": true,
"CUME_DIST": true,
"CURRENT": true,
"CURRENT_CATALOG": true,
"CURRENT_DATE": true,
"CURRENT_DEFAULT_TRANSFORM_GROUP": true,
"CURRENT_PATH": true,
"CURRENT_ROLE": true,
"CURRENT_ROW": true,
"CURRENT_SCHEMA": true,
"CURRENT_TIME": true,
"CURRENT_TIMESTAMP": true,
"CURRENT_TRANSFORM_GROUP_FOR_TYPE": true,
"CURRENT_USER": true,
"CURSOR": true,
"CURSOR_NAME": true,
"CYCLE": true,
"DATA": true,
"DATABASE": true,
"DATALINK": true,
"DATE": true,
"DATETIME_INTERVAL_CODE": true,
"DATETIME_INTERVAL_PRECISION": true,
"DAY": true,
"DB": true,
"DEALLOCATE": true,
"DEC": true,
"DECIMAL": true,
"DECLARE": true,
"DEFAULT": true,
"DEFAULTS": true,
"DEFERRABLE": true,
"DEFERRED": true,
"DEFINED": true,
"DEFINER": true,
"DEGREE": true,
"DELETE": true,
"DELIMITER": true,
"DELIMITERS": true,
"DENSE_RANK": true,
"DEPTH": true,
"DEREF": true,
"DERIVED": true,
"DESC": true,
"DESCRIBE": true,
"DESCRIPTOR": true,
"DETERMINISTIC": true,
"DIAGNOSTICS": true,
"DICTIONARY": true,
"DISABLE": true,
"DISCARD": true,
"DISCONNECT": true,
"DISPATCH": true,
"DISTINCT": true,
"DLNEWCOPY": true,
"DLPREVIOUSCOPY": true,
"DLURLCOMPLETE": true,
"DLURLCOMPLETEONLY": true,
"DLURLCOMPLETEWRITE": true,
"DLURLPATH": true,
"DLURLPATHONLY": true,
"DLURLPATHWRITE": true,
"DLURLSCHEME": true,
"DLURLSERVER": true,
"DLVALUE": true,
"DO": true,
"DOCUMENT": true,
"DOMAIN": true,
"DOUBLE": true,
"DROP": true,
"DYNAMIC": true,
"DYNAMIC_FUNCTION": true,
"DYNAMIC_FUNCTION_CODE": true,
"EACH": true,
"ELEMENT": true,
"ELSE": true,
"EMPTY": true,
"ENABLE": true,
"ENCODING": true,
"ENCRYPTED": true,
"END": true,
"END-EXEC": true,
"END_FRAME": true,
"END_PARTITION": true,
"ENFORCED": true,
"ENUM": true,
"EQUALS": true,
"ESCAPE": true,
"EVENT": true,
"EVERY": true,
"EXCEPT": true,
"EXCEPTION": true,
"EXCLUDE": true,
"EXCLUDING": true,
"EXCLUSIVE": true,
"EXEC": true,
"EXECUTE": true,
"EXISTS": true,
"EXP": true,
"EXPLAIN": true,
"EXPRESSION": true,
"EXTENSION": true,
"EXTERNAL": true,
"EXTRACT": true,
"FALSE": true,
"FAMILY": true,
"FETCH": true,
"FILE": true,
"FILTER": true,
"FINAL": true,
"FIRST": true,
"FIRST_VALUE": true,
"FLAG": true,
"FLOAT": true,
"FLOOR": true,
"FOLLOWING": true,
"FOR": true,
"FORCE": true,
"FOREIGN": true,
"FORTRAN": true,
"FORWARD": true,
"FOUND": true,
"FRAME_ROW": true,
"FREE": true,
"FREEZE": true,
"FROM": true,
"FS": true,
"FULL": true,
"FUNCTION": true,
"FUNCTIONS": true,
"FUSION": true,
"G": true,
"GENERAL": true,
"GENERATED": true,
"GET": true,
"GLOBAL": true,
"GO": true,
"GOTO": true,
"GRANT": true,
"GRANTED": true,
"GREATEST": true,
"GROUP": true,
"GROUPING": true,
"GROUPS": true,
"HANDLER": true,
"HAVING": true,
"HEADER": true,
"HEX": true,
"HIERARCHY": true,
"HOLD": true,
"HOUR": true,
"ID": true,
"IDENTITY": true,
"IF": true,
"IGNORE": true,
"ILIKE": true,
"IMMEDIATE": true,
"IMMEDIATELY": true,
"IMMUTABLE": true,
"IMPLEMENTATION": true,
"IMPLICIT": true,
"IMPORT": true,
"IN": true,
"INCLUDING": true,
"INCREMENT": true,
"INDENT": true,
"INDEX": true,
"INDEXES": true,
"INDICATOR": true,
"INHERIT": true,
"INHERITS": true,
"INITIALLY": true,
"INLINE": true,
"INNER": true,
"INOUT": true,
"INPUT": true,
"INSENSITIVE": true,
"INSERT": true,
"INSTANCE": true,
"INSTANTIABLE": true,
"INSTEAD": true,
"INT": true,
"INTEGER": true,
"INTEGRITY": true,
"INTERSECT": true,
"INTERSECTION": true,
"INTERVAL": true,
"INTO": true,
"INVOKER": true,
"IS": true,
"ISNULL": true,
"ISOLATION": true,
"JOIN": true,
"K": true,
"KEY": true,
"KEY_MEMBER": true,
"KEY_TYPE": true,
"LABEL": true,
"LAG": true,
"LANGUAGE": true,
"LARGE": true,
"LAST": true,
"LAST_VALUE": true,
"LATERAL": true,
"LC_COLLATE": true,
"LC_CTYPE": true,
"LEAD": true,
"LEADING": true,
"LEAKPROOF": true,
"LEAST": true,
"LEFT": true,
"LENGTH": true,
"LEVEL": true,
"LIBRARY": true,
"LIKE": true,
"LIKE_REGEX": true,
"LIMIT": true,
"LINK": true,
"LISTEN": true,
"LN": true,
"LOAD": true,
"LOCAL": true,
"LOCALTIME": true,
"LOCALTIMESTAMP": true,
"LOCATION": true,
"LOCATOR": true,
"LOCK": true,
"LOWER": true,
"M": true,
"MAP": true,
"MAPPING": true,
"MATCH": true,
"MATCHED": true,
"MATERIALIZED": true,
"MAX": true,
"MAXVALUE": true,
"MAX_CARDINALITY": true,
"MEMBER": true,
"MERGE": true,
"MESSAGE_LENGTH": true,
"MESSAGE_OCTET_LENGTH": true,
"MESSAGE_TEXT": true,
"METHOD": true,
"MIN": true,
"MINUTE": true,
"MINVALUE": true,
"MOD": true,
"MODE": true,
"MODIFIES": true,
"MODULE": true,
"MONTH": true,
"MORE": true,
"MOVE": true,
"MULTISET": true,
"MUMPS": true,
"NAME": true,
"NAMES": true,
"NAMESPACE": true,
"NATIONAL": true,
"NATURAL": true,
"NCHAR": true,
"NCLOB": true,
"NESTING": true,
"NEW": true,
"NEXT": true,
"NFC": true,
"NFD": true,
"NFKC": true,
"NFKD": true,
"NIL": true,
"NO": true,
"NONE": true,
"NORMALIZE": true,
"NORMALIZED": true,
"NOT": true,
"NOTHING": true,
"NOTIFY": true,
"NOTNULL": true,
"NOWAIT": true,
"NTH_VALUE": true,
"NTILE": true,
"NULL": true,
"NULLABLE": true,
"NULLIF": true,
"NULLS": true,
"NUMBER": true,
"NUMERIC": true,
"OBJECT": true,
"OCCURRENCES_REGEX": true,
"OCTETS": true,
"OCTET_LENGTH": true,
"OF": true,
"OFF": true,
"OFFSET": true,
"OIDS": true,
"OLD": true,
"ON": true,
"ONLY": true,
"OPEN": true,
"OPERATOR": true,
"OPTION": true,
"OPTIONS": true,
"OR": true,
"ORDER": true,
"ORDERING": true,
"ORDINALITY": true,
"OTHERS": true,
"OUT": true,
"OUTER": true,
"OUTPUT": true,
"OVER": true,
"OVERLAPS": true,
"OVERLAY": true,
"OVERRIDING": true,
"OWNED": true,
"OWNER": true,
"P": true,
"PAD": true,
"PARAMETER": true,
"PARAMETER_MODE": true,
"PARAMETER_NAME": true,
"PARAMETER_ORDINAL_POSITION": true,
"PARAMETER_SPECIFIC_CATALOG": true,
"PARAMETER_SPECIFIC_NAME": true,
"PARAMETER_SPECIFIC_SCHEMA": true,
"PARSER": true,
"PARTIAL": true,
"PARTITION": true,
"PASCAL": true,
"PASSING": true,
"PASSTHROUGH": true,
"PASSWORD": true,
"PATH": true,
"PERCENT": true,
"PERCENTILE_CONT": true,
"PERCENTILE_DISC": true,
"PERCENT_RANK": true,
"PERIOD": true,
"PERMISSION": true,
"PLACING": true,
"PLANS": true,
"PLI": true,
"PORTION": true,
"POSITION": true,
"POSITION_REGEX": true,
"POWER": true,
"PRECEDES": true,
"PRECEDING": true,
"PRECISION": true,
"PREPARE": true,
"PREPARED": true,
"PRESERVE": true,
"PRIMARY": true,
"PRIOR": true,
"PRIVILEGES": true,
"PROCEDURAL": true,
"PROCEDURE": true,
"PROGRAM": true,
"PUBLIC": true,
"QUOTE": true,
"RANGE": true,
"RANK": true,
"READ": true,
"READS": true,
"REAL": true,
"REASSIGN": true,
"RECHECK": true,
"RECOVERY": true,
"RECURSIVE": true,
"REF": true,
"REFERENCES": true,
"REFERENCING": true,
"REFRESH": true,
"REGR_AVGX": true,
"REGR_AVGY": true,
"REGR_COUNT": true,
"REGR_INTERCEPT": true,
"REGR_R2": true,
"REGR_SLOPE": true,
"REGR_SXX": true,
"REGR_SXY": true,
"REGR_SYY": true,
"REINDEX": true,
"RELATIVE": true,
"RELEASE": true,
"RENAME": true,
"REPEATABLE": true,
"REPLACE": true,
"REPLICA": true,
"REQUIRING": true,
"RESET": true,
"RESPECT": true,
"RESTART": true,
"RESTORE": true,
"RESTRICT": true,
"RESULT": true,
"RETURN": true,
"RETURNED_CARDINALITY": true,
"RETURNED_LENGTH": true,
"RETURNED_OCTET_LENGTH": true,
"RETURNED_SQLSTATE": true,
"RETURNING": true,
"RETURNS": true,
"REVOKE": true,
"RIGHT": true,
"ROLE": true,
"ROLLBACK": true,
"ROLLUP": true,
"ROUTINE": true,
"ROUTINE_CATALOG": true,
"ROUTINE_NAME": true,
"ROUTINE_SCHEMA": true,
"ROW": true,
"ROWS": true,
"ROW_COUNT": true,
"ROW_NUMBER": true,
"RULE": true,
"SAVEPOINT": true,
"SCALE": true,
"SCHEMA": true,
"SCHEMA_NAME": true,
"SCOPE": true,
"SCOPE_CATALOG": true,
"SCOPE_NAME": true,
"SCOPE_SCHEMA": true,
"SCROLL": true,
"SEARCH": true,
"SECOND": true,
"SECTION": true,
"SECURITY": true,
"SELECT": true,
"SELECTIVE": true,
"SELF": true,
"SENSITIVE": true,
"SEQUENCE": true,
"SEQUENCES": true,
"SERIALIZABLE": true,
"SERVER": true,
"SERVER_NAME": true,
"SESSION": true,
"SESSION_USER": true,
"SET": true,
"SETOF": true,
"SETS": true,
"SHARE": true,
"SHOW": true,
"SIMILAR": true,
"SIMPLE": true,
"SIZE": true,
"SMALLINT": true,
"SNAPSHOT": true,
"SOME": true,
"SOURCE": true,
"SPACE": true,
"SPECIFIC": true,
"SPECIFICTYPE": true,
"SPECIFIC_NAME": true,
"SQL": true,
"SQLCODE": true,
"SQLERROR": true,
"SQLEXCEPTION": true,
"SQLSTATE": true,
"SQLWARNING": true,
"SQRT": true,
"STABLE": true,
"STANDALONE": true,
"START": true,
"STATE": true,
"STATEMENT": true,
"STATIC": true,
"STATISTICS": true,
"STDDEV_POP": true,
"STDDEV_SAMP": true,
"STDIN": true,
"STDOUT": true,
"STORAGE": true,
"STRICT": true,
"STRIP": true,
"STRUCTURE": true,
"STYLE": true,
"SUBCLASS_ORIGIN": true,
"SUBMULTISET": true,
"SUBSTRING": true,
"SUBSTRING_REGEX": true,
"SUCCEEDS": true,
"SUM": true,
"SYMMETRIC": true,
"SYSID": true,
"SYSTEM": true,
"SYSTEM_TIME": true,
"SYSTEM_USER": true,
"T": true,
"TABLE": true,
"TABLES": true,
"TABLESAMPLE": true,
"TABLESPACE": true,
"TABLE_NAME": true,
"TEMP": true,
"TEMPLATE": true,
"TEMPORARY": true,
"TEXT": true,
"THEN": true,
"TIES": true,
"TIME": true,
"TIMESTAMP": true,
"TIMEZONE_HOUR": true,
"TIMEZONE_MINUTE": true,
"TO": true,
"TOKEN": true,
"TOP_LEVEL_COUNT": true,
"TRAILING": true,
"TRANSACTION": true,
"TRANSACTIONS_COMMITTED": true,
"TRANSACTIONS_ROLLED_BACK": true,
"TRANSACTION_ACTIVE": true,
"TRANSFORM": true,
"TRANSFORMS": true,
"TRANSLATE": true,
"TRANSLATE_REGEX": true,
"TRANSLATION": true,
"TREAT": true,
"TRIGGER": true,
"TRIGGER_CATALOG": true,
"TRIGGER_NAME": true,
"TRIGGER_SCHEMA": true,
"TRIM": true,
"TRIM_ARRAY": true,
"TRUE": true,
"TRUNCATE": true,
"TRUSTED": true,
"TYPE": true,
"TYPES": true,
"UESCAPE": true,
"UNBOUNDED": true,
"UNCOMMITTED": true,
"UNDER": true,
"UNENCRYPTED": true,
"UNION": true,
"UNIQUE": true,
"UNKNOWN": true,
"UNLINK": true,
"UNLISTEN": true,
"UNLOGGED": true,
"UNNAMED": true,
"UNNEST": true,
"UNTIL": true,
"UNTYPED": true,
"UPDATE": true,
"UPPER": true,
"URI": true,
"USAGE": true,
"USER": true,
"USER_DEFINED_TYPE_CATALOG": true,
"USER_DEFINED_TYPE_CODE": true,
"USER_DEFINED_TYPE_NAME": true,
"USER_DEFINED_TYPE_SCHEMA": true,
"USING": true,
"VACUUM": true,
"VALID": true,
"VALIDATE": true,
"VALIDATOR": true,
"VALUE": true,
"VALUES": true,
"VALUE_OF": true,
"VARBINARY": true,
"VARCHAR": true,
"VARIADIC": true,
"VARYING": true,
"VAR_POP": true,
"VAR_SAMP": true,
"VERBOSE": true,
"VERSION": true,
"VERSIONING": true,
"VIEW": true,
"VOLATILE": true,
"WHEN": true,
"WHENEVER": true,
"WHERE": true,
"WHITESPACE": true,
"WIDTH_BUCKET": true,
"WINDOW": true,
"WITH": true,
"WITHIN": true,
"WITHOUT": true,
"WORK": true,
"WRAPPER": true,
"WRITE": true,
"XML": true,
"XMLAGG": true,
"XMLATTRIBUTES": true,
"XMLBINARY": true,
"XMLCAST": true,
"XMLCOMMENT": true,
"XMLCONCAT": true,
"XMLDECLARATION": true,
"XMLDOCUMENT": true,
"XMLELEMENT": true,
"XMLEXISTS": true,
"XMLFOREST": true,
"XMLITERATE": true,
"XMLNAMESPACES": true,
"XMLPARSE": true,
"XMLPI": true,
"XMLQUERY": true,
"XMLROOT": true,
"XMLSCHEMA": true,
"XMLSERIALIZE": true,
"XMLTABLE": true,
"XMLTEXT": true,
"XMLVALIDATE": true,
"YEAR": true,
"YES": true,
"ZONE": true,
2014-09-07 00:32:58 +00:00
}
postgresQuoter = schemas.Quoter{
Prefix: '"',
Suffix: '"',
IsReserved: schemas.AlwaysReserve,
}
)
2013-10-12 15:16:51 +00:00
var (
// DefaultPostgresSchema default postgres schema
DefaultPostgresSchema = "public"
)
2014-01-07 09:33:27 +00:00
type postgres struct {
Base
2013-12-17 09:30:05 +00:00
}
func (db *postgres) Init(uri *URI) error {
db.quoter = postgresQuoter
return db.Base.Init(db, uri)
}
func (db *postgres) getSchema() string {
if db.uri.Schema != "" {
return db.uri.Schema
}
return DefaultPostgresSchema
}
func (db *postgres) needQuote(name string) bool {
if db.IsReserved(name) {
return true
}
for _, c := range name {
if c >= 'A' && c <= 'Z' {
return true
}
}
return false
}
func (db *postgres) SetQuotePolicy(quotePolicy QuotePolicy) {
switch quotePolicy {
case QuotePolicyNone:
var q = postgresQuoter
q.IsReserved = schemas.AlwaysNoReserve
db.quoter = q
case QuotePolicyReserved:
var q = postgresQuoter
q.IsReserved = db.needQuote
db.quoter = q
case QuotePolicyAlways:
fallthrough
default:
db.quoter = postgresQuoter
}
}
func (db *postgres) SQLType(c *schemas.Column) string {
2013-12-18 03:31:32 +00:00
var res string
switch t := c.SQLType.Name; t {
case schemas.TinyInt:
res = schemas.SmallInt
return res
case schemas.Bit:
res = schemas.Boolean
return res
case schemas.MediumInt, schemas.Int, schemas.Integer, schemas.UnsignedInt:
if c.IsAutoIncrement {
return schemas.Serial
}
return schemas.Integer
case schemas.BigInt, schemas.UnsignedBigInt:
2016-12-10 02:53:27 +00:00
if c.IsAutoIncrement {
return schemas.BigSerial
2016-12-10 02:53:27 +00:00
}
return schemas.BigInt
case schemas.Serial, schemas.BigSerial:
2013-12-18 03:31:32 +00:00
c.IsAutoIncrement = true
c.Nullable = false
res = t
case schemas.Binary, schemas.VarBinary:
return schemas.Bytea
case schemas.DateTime:
res = schemas.TimeStamp
case schemas.TimeStampz:
2013-12-18 03:31:32 +00:00
return "timestamp with time zone"
case schemas.Float:
res = schemas.Real
case schemas.TinyText, schemas.MediumText, schemas.LongText:
res = schemas.Text
Fix warnings with schema Sync2 with default varchar as NVARCHAR (#1783) prod CI Merge branch 'fix-1782-MSSQL-nvarchar-fixes' of gitea.com:zeripath/xorm into fix-1782-MSSQL-nvarchar-fixes map "character" to Char for postgres Signed-off-by: Andrew Thornton <art27@cantab.net> Merge branch 'master' into fix-1782-MSSQL-nvarchar-fixes Postgres (and cockroachDB by inheritance) maps Char to Varchar Signed-off-by: Andrew Thornton <art27@cantab.net> fix test Add a few more column testcases in light of postgres weirdness prod CI prod CI prod CI Properly handle MAX Signed-off-by: Andrew Thornton <art27@cantab.net> Add tests for Test and Char columns Signed-off-by: Andrew Thornton <art27@cantab.net> prod CI fix test Signed-off-by: Andrew Thornton <art27@cantab.net> Remove the duplicate mssql drone test and add a specific sync test Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on (2) Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on Signed-off-by: Andrew Thornton <art27@cantab.net> add nvarchar as a testcase Signed-off-by: Andrew Thornton <art27@cantab.net> Set defaultVarchar to upper case Signed-off-by: Andrew Thornton <art27@cantab.net> Fix length issue Signed-off-by: Andrew Thornton <art27@cantab.net> schemas.Text should map to db.defaultVarchar Signed-off-by: Andrew Thornton <art27@cantab.net> Add failing test Signed-off-by: Andrew Thornton <art27@cantab.net> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1783 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-09-08 01:36:50 +00:00
case schemas.NChar:
res = schemas.Char
case schemas.NVarchar:
res = schemas.Varchar
case schemas.Uuid:
return schemas.Uuid
case schemas.Blob, schemas.TinyBlob, schemas.MediumBlob, schemas.LongBlob:
return schemas.Bytea
case schemas.Double:
2013-12-18 03:31:32 +00:00
return "DOUBLE PRECISION"
default:
if c.IsAutoIncrement {
return schemas.Serial
2013-12-18 03:31:32 +00:00
}
res = t
}
if strings.EqualFold(res, "bool") {
// for bool, we don't need length information
return res
}
hasLen1 := (c.Length > 0)
hasLen2 := (c.Length2 > 0)
2014-05-29 08:53:23 +00:00
if hasLen2 {
2013-12-18 03:31:32 +00:00
res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
2014-05-29 08:53:23 +00:00
} else if hasLen1 {
res += "(" + strconv.Itoa(c.Length) + ")"
2013-12-18 03:31:32 +00:00
}
return res
}
func (db *postgres) IsReserved(name string) bool {
_, ok := postgresReservedWords[strings.ToUpper(name)]
return ok
}
func (db *postgres) AutoIncrStr() string {
2013-12-18 03:31:32 +00:00
return ""
}
func (db *postgres) CreateTableSQL(table *schemas.Table, tableName string) ([]string, bool) {
var sql string
sql = "CREATE TABLE IF NOT EXISTS "
if tableName == "" {
tableName = table.Name
}
quoter := db.Quoter()
sql += quoter.Quote(tableName)
sql += " ("
2013-09-26 07:19:39 +00:00
if len(table.ColumnsSeq()) > 0 {
pkList := table.PrimaryKeys
for _, colName := range table.ColumnsSeq() {
col := table.GetColumn(colName)
s, _ := ColumnString(db, col, col.IsPrimaryKey && len(pkList) == 1)
sql += s
sql = strings.TrimSpace(sql)
sql += ", "
}
if len(pkList) > 1 {
sql += "PRIMARY KEY ( "
sql += quoter.Join(pkList, ",")
sql += " ), "
}
sql = sql[:len(sql)-2]
}
sql += ")"
return []string{sql}, true
2013-09-26 07:19:39 +00:00
}
func (db *postgres) IndexCheckSQL(tableName, idxName string) (string, []interface{}) {
if len(db.getSchema()) == 0 {
args := []interface{}{tableName, idxName}
return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
}
args := []interface{}{db.getSchema(), tableName, idxName}
2013-12-18 03:31:32 +00:00
return `SELECT indexname FROM pg_indexes ` +
`WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
}
func (db *postgres) IsTableExist(queryer core.Queryer, ctx context.Context, tableName string) (bool, error) {
if len(db.getSchema()) == 0 {
return db.HasRecords(queryer, ctx, `SELECT tablename FROM pg_tables WHERE tablename = $1`, tableName)
}
return db.HasRecords(queryer, ctx, `SELECT tablename FROM pg_tables WHERE schemaname = $1 AND tablename = $2`,
db.getSchema(), tableName)
}
func (db *postgres) ModifyColumnSQL(tableName string, col *schemas.Column) string {
if len(db.getSchema()) == 0 || strings.Contains(tableName, ".") {
return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s",
tableName, col.Name, db.SQLType(col))
}
return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s",
db.getSchema(), tableName, col.Name, db.SQLType(col))
}
func (db *postgres) DropIndexSQL(tableName string, index *schemas.Index) string {
idxName := index.Name
tableParts := strings.Split(strings.Replace(tableName, `"`, "", -1), ".")
tableName = tableParts[len(tableParts)-1]
if !strings.HasPrefix(idxName, "UQE_") &&
!strings.HasPrefix(idxName, "IDX_") {
if index.Type == schemas.UniqueType {
idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
} else {
idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
}
}
if db.getSchema() != "" {
idxName = db.getSchema() + "." + idxName
}
Fix join table name quote bug (#1534) Fix test Fix test Add new Quoter object to handle quote Fix join table name quote bug Move reserve words related files into dialects sub package (#1544) Move reserve words related files into dialects sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1544 Fix mssql quote (#1535) Fix some quotes Fix mssql quote Merge core package back into the main repository and split into serval sub packages. (#1543) Fix test Improve fmt update go.mod Move core as a sub package Reviewed-on: https://gitea.com/xorm/xorm/pulls/1543 Fix int time deleted bug (#1539) Fix panic Fix test Fix test for mssql time Add sql type check on deleted cond Fix int time deleted bug Reviewed-on: https://gitea.com/xorm/xorm/pulls/1539 Add test for mysql8.0 (#1538) Fix pk order on test Add test for mysql8.0 Reviewed-on: https://gitea.com/xorm/xorm/pulls/1538 Add test for join limit (#1536) Add test for join limit Reviewed-on: https://gitea.com/xorm/xorm/pulls/1536 Improve drone (#1537) Fix drone Improve drone * use traditional positional parameters on inser... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1537 Fix slice of struct not cache bug (#895) Fix failure caused by nil bean Judge both type of struct and pointer in case of out-of-range Fix issue #894 Add test for join subquery (#1528) Fix test Fix subquery with schema Add test for join subquery Add makefile (#1531) Fix drone Fix ci Add deps Improve drone Fix envs Add makefile Reviewed-on: https://gitea.com/xorm/xorm/pulls/1531 Add password for postgres drone image (#1530) Add password for postgres drone image Reviewed-on: https://gitea.com/xorm/xorm/pulls/1530 format time when sqlTypeName is core.Varchar (#1026) fix time test add test for time format sign codes according to contributing rules. format time when sqlTypeName is core.Varchar. Same with core.DateTime or core.TimeStamp Add test for second insert error (#1527) Add test for second insert error Reviewed-on: https://gitea.com/xorm/xorm/pulls/1527 Add tests for table name (#1517) add tests for table name Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix test (#1526) Fix test Reviewed-on: https://gitea.com/xorm/xorm/pulls/1526 Fix wrong warning log on autoincrement column when sync table (#1525) improve doc Fix wrong warning log on autoincrement column when sync table Reviewed-on: https://gitea.com/xorm/xorm/pulls/1525 Fixed Join strings on func Exist (#1520) fix test fixed Join strings on func Exist Co-authored-by: Tomofumi Kusana <tkusana@morisawa.co.jp> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1520 For nullable columns, store nil values as NULL (#531) Merge branch 'master' into jcsalem/fix/nil_ptr_is_nullable fix bug when buffersize with iterate (#941) Merge branch 'master' into lunny/fix_buffer_iterate Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 fix test fix bug fix bug when buffersize with iterate SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Co-authored-by: Guillermo Prandi <guillep2k@noreply.gitea.io> Reviewed-on: https://gitea.com/xorm/xorm/pulls/941 fix update map with version (#1448) fix test fix update map with version SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Reviewed-on: https://gitea.com/xorm/xorm/pulls/1448 Exclude schema from index name (#1505) Merge branch 'master' into fix-schema-idx SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 fix vet fix drone lint remove go1.10 test on drone Exclude schema from the index name Co-authored-by: Guillermo Prandi <guillep2k@users.noreply.github.com> Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1505 SetExpr support more go types (#1499) Improve tests SetExpr support more go types fix vet fix drone lint remove go1.10 test on drone Reviewed-on: https://gitea.com/xorm/xorm/pulls/1499 For nullable columns, store nil values as NULL fix vet fix drone lint remove go1.10 test on drone Fix update with Alias (#1455) Improve c... Reviewed-on: https://gitea.com/xorm/xorm/pulls/1534
2020-02-25 00:01:36 +00:00
return fmt.Sprintf("DROP INDEX %v", db.Quoter().Quote(idxName))
}
func (db *postgres) IsColumnExist(queryer core.Queryer, ctx context.Context, tableName, colName string) (bool, error) {
args := []interface{}{db.getSchema(), tableName, colName}
query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" +
" AND column_name = $3"
if len(db.getSchema()) == 0 {
args = []interface{}{tableName, colName}
query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
" AND column_name = $2"
}
rows, err := queryer.QueryContext(ctx, query, args...)
2014-04-29 07:20:18 +00:00
if err != nil {
return false, err
}
defer rows.Close()
return rows.Next(), nil
2014-04-29 07:20:18 +00:00
}
func (db *postgres) GetColumns(queryer core.Queryer, ctx context.Context, tableName string) ([]string, map[string]*schemas.Column, error) {
args := []interface{}{tableName}
2019-09-05 08:14:27 +00:00
s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
2014-06-23 13:46:08 +00:00
CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey,
CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey
FROM pg_attribute f
JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid
LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)
LEFT JOIN pg_class AS g ON p.confrelid = g.oid
LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name
WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
schema := db.getSchema()
if schema != "" {
s = fmt.Sprintf(s, " AND s.table_schema = $2")
args = append(args, schema)
} else {
s = fmt.Sprintf(s, "")
}
rows, err := queryer.QueryContext(ctx, s, args...)
2014-06-26 06:35:40 +00:00
if err != nil {
return nil, nil, err
}
defer rows.Close()
cols := make(map[string]*schemas.Column)
2014-06-26 06:35:40 +00:00
colSeq := make([]string, 0)
for rows.Next() {
col := new(schemas.Column)
2016-06-30 08:35:04 +00:00
col.Indexes = make(map[string]int)
2014-06-26 06:35:40 +00:00
var colName, isNullable, dataType string
2019-09-05 08:14:27 +00:00
var maxLenStr, colDefault *string
2014-06-26 06:35:40 +00:00
var isPK, isUnique bool
2019-09-05 08:14:27 +00:00
err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
2014-06-26 06:35:40 +00:00
if err != nil {
return nil, nil, err
}
2014-08-28 14:48:01 +00:00
2014-06-26 06:35:40 +00:00
var maxLen int
if maxLenStr != nil {
maxLen, err = strconv.Atoi(*maxLenStr)
if err != nil {
return nil, nil, err
}
}
if colDefault != nil && *colDefault == "unique_rowid()" { // ignore the system column added by cockroach
continue
}
2014-06-26 06:35:40 +00:00
col.Name = strings.Trim(colName, `" `)
if colDefault != nil {
var theDefault = *colDefault
// cockroach has type with the default value with :::
// and postgres with ::, we should remove them before store them
idx := strings.Index(theDefault, ":::")
if idx == -1 {
idx = strings.Index(theDefault, "::")
}
if idx > -1 {
theDefault = theDefault[:idx]
}
if strings.HasSuffix(theDefault, "+00:00'") {
theDefault = theDefault[:len(theDefault)-7] + "'"
}
col.Default = theDefault
col.DefaultIsEmpty = false
if strings.HasPrefix(col.Default, "nextval(") {
col.IsAutoIncrement = true
col.Default = ""
col.DefaultIsEmpty = true
2014-06-26 06:35:40 +00:00
}
} else {
col.DefaultIsEmpty = true
2014-06-26 06:35:40 +00:00
}
if isPK {
col.IsPrimaryKey = true
2014-08-28 15:04:28 +00:00
}
2014-06-26 06:35:40 +00:00
col.Nullable = (isNullable == "YES")
switch strings.ToLower(dataType) {
Fix warnings with schema Sync2 with default varchar as NVARCHAR (#1783) prod CI Merge branch 'fix-1782-MSSQL-nvarchar-fixes' of gitea.com:zeripath/xorm into fix-1782-MSSQL-nvarchar-fixes map "character" to Char for postgres Signed-off-by: Andrew Thornton <art27@cantab.net> Merge branch 'master' into fix-1782-MSSQL-nvarchar-fixes Postgres (and cockroachDB by inheritance) maps Char to Varchar Signed-off-by: Andrew Thornton <art27@cantab.net> fix test Add a few more column testcases in light of postgres weirdness prod CI prod CI prod CI Properly handle MAX Signed-off-by: Andrew Thornton <art27@cantab.net> Add tests for Test and Char columns Signed-off-by: Andrew Thornton <art27@cantab.net> prod CI fix test Signed-off-by: Andrew Thornton <art27@cantab.net> Remove the duplicate mssql drone test and add a specific sync test Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on (2) Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on Signed-off-by: Andrew Thornton <art27@cantab.net> add nvarchar as a testcase Signed-off-by: Andrew Thornton <art27@cantab.net> Set defaultVarchar to upper case Signed-off-by: Andrew Thornton <art27@cantab.net> Fix length issue Signed-off-by: Andrew Thornton <art27@cantab.net> schemas.Text should map to db.defaultVarchar Signed-off-by: Andrew Thornton <art27@cantab.net> Add failing test Signed-off-by: Andrew Thornton <art27@cantab.net> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1783 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-09-08 01:36:50 +00:00
case "character varying", "string":
col.SQLType = schemas.SQLType{Name: schemas.Varchar, DefaultLength: 0, DefaultLength2: 0}
Fix warnings with schema Sync2 with default varchar as NVARCHAR (#1783) prod CI Merge branch 'fix-1782-MSSQL-nvarchar-fixes' of gitea.com:zeripath/xorm into fix-1782-MSSQL-nvarchar-fixes map "character" to Char for postgres Signed-off-by: Andrew Thornton <art27@cantab.net> Merge branch 'master' into fix-1782-MSSQL-nvarchar-fixes Postgres (and cockroachDB by inheritance) maps Char to Varchar Signed-off-by: Andrew Thornton <art27@cantab.net> fix test Add a few more column testcases in light of postgres weirdness prod CI prod CI prod CI Properly handle MAX Signed-off-by: Andrew Thornton <art27@cantab.net> Add tests for Test and Char columns Signed-off-by: Andrew Thornton <art27@cantab.net> prod CI fix test Signed-off-by: Andrew Thornton <art27@cantab.net> Remove the duplicate mssql drone test and add a specific sync test Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on (2) Signed-off-by: Andrew Thornton <art27@cantab.net> add depends_on Signed-off-by: Andrew Thornton <art27@cantab.net> add nvarchar as a testcase Signed-off-by: Andrew Thornton <art27@cantab.net> Set defaultVarchar to upper case Signed-off-by: Andrew Thornton <art27@cantab.net> Fix length issue Signed-off-by: Andrew Thornton <art27@cantab.net> schemas.Text should map to db.defaultVarchar Signed-off-by: Andrew Thornton <art27@cantab.net> Add failing test Signed-off-by: Andrew Thornton <art27@cantab.net> Reviewed-on: https://gitea.com/xorm/xorm/pulls/1783 Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-09-08 01:36:50 +00:00
case "character":
col.SQLType = schemas.SQLType{Name: schemas.Char, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
case "timestamp without time zone":
col.SQLType = schemas.SQLType{Name: schemas.DateTime, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
case "timestamp with time zone":
col.SQLType = schemas.SQLType{Name: schemas.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
case "double precision":
col.SQLType = schemas.SQLType{Name: schemas.Double, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
case "boolean":
col.SQLType = schemas.SQLType{Name: schemas.Bool, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
case "time without time zone":
col.SQLType = schemas.SQLType{Name: schemas.Time, DefaultLength: 0, DefaultLength2: 0}
case "bytes":
col.SQLType = schemas.SQLType{Name: schemas.Binary, DefaultLength: 0, DefaultLength2: 0}
2016-04-22 13:43:22 +00:00
case "oid":
col.SQLType = schemas.SQLType{Name: schemas.BigInt, DefaultLength: 0, DefaultLength2: 0}
case "array":
col.SQLType = schemas.SQLType{Name: schemas.Array, DefaultLength: 0, DefaultLength2: 0}
2014-06-26 06:35:40 +00:00
default:
startIdx := strings.Index(strings.ToLower(dataType), "string(")
if startIdx != -1 && strings.HasSuffix(dataType, ")") {
length := dataType[startIdx+8 : len(dataType)-1]
l, _ := strconv.Atoi(length)
col.SQLType = schemas.SQLType{Name: "STRING", DefaultLength: l, DefaultLength2: 0}
} else {
col.SQLType = schemas.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
}
2014-06-26 06:35:40 +00:00
}
if _, ok := schemas.SqlTypes[col.SQLType.Name]; !ok {
return nil, nil, fmt.Errorf("Unknown colType: %s - %s", dataType, col.SQLType.Name)
2014-06-26 06:35:40 +00:00
}
col.Length = maxLen
if !col.DefaultIsEmpty {
if col.SQLType.IsText() {
if strings.HasSuffix(col.Default, "::character varying") {
col.Default = strings.TrimRight(col.Default, "::character varying")
} else if !strings.HasPrefix(col.Default, "'") {
col.Default = "'" + col.Default + "'"
}
} else if col.SQLType.IsTime() {
if strings.HasSuffix(col.Default, "::timestamp without time zone") {
col.Default = strings.TrimRight(col.Default, "::timestamp without time zone")
2014-06-26 06:35:40 +00:00
}
}
}
cols[col.Name] = col
colSeq = append(colSeq, col.Name)
}
return colSeq, cols, nil
2013-10-12 15:16:51 +00:00
}
func (db *postgres) GetTables(queryer core.Queryer, ctx context.Context) ([]*schemas.Table, error) {
args := []interface{}{}
s := "SELECT tablename FROM pg_tables"
schema := db.getSchema()
if schema != "" {
args = append(args, schema)
s = s + " WHERE schemaname = $1"
}
rows, err := queryer.QueryContext(ctx, s, args...)
2013-12-18 03:31:32 +00:00
if err != nil {
return nil, err
}
2014-04-18 10:39:07 +00:00
defer rows.Close()
2013-12-18 03:31:32 +00:00
tables := make([]*schemas.Table, 0)
2014-01-07 09:33:27 +00:00
for rows.Next() {
table := schemas.NewEmptyTable()
2014-01-07 09:33:27 +00:00
var name string
err = rows.Scan(&name)
if err != nil {
return nil, err
2013-12-18 03:31:32 +00:00
}
2014-01-07 09:33:27 +00:00
table.Name = name
2013-12-18 03:31:32 +00:00
tables = append(tables, table)
}
return tables, nil
2013-10-12 15:16:51 +00:00
}
func getIndexColName(indexdef string) []string {
var colNames []string
cs := strings.Split(indexdef, "(")
for _, v := range strings.Split(strings.Split(cs[1], ")")[0], ",") {
colNames = append(colNames, strings.Split(strings.TrimLeft(v, " "), " ")[0])
}
return colNames
}
func (db *postgres) GetIndexes(queryer core.Queryer, ctx context.Context, tableName string) (map[string]*schemas.Index, error) {
args := []interface{}{tableName}
s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
if len(db.getSchema()) != 0 {
args = append(args, db.getSchema())
s = s + " AND schemaname=$2"
}
2013-12-18 03:31:32 +00:00
rows, err := queryer.QueryContext(ctx, s, args...)
2013-12-18 03:31:32 +00:00
if err != nil {
return nil, err
}
2014-04-18 10:39:07 +00:00
defer rows.Close()
2013-12-18 03:31:32 +00:00
indexes := make(map[string]*schemas.Index, 0)
2014-01-07 09:33:27 +00:00
for rows.Next() {
2013-12-18 03:31:32 +00:00
var indexType int
2014-01-07 09:33:27 +00:00
var indexName, indexdef string
2013-12-18 03:31:32 +00:00
var colNames []string
2014-01-07 09:33:27 +00:00
err = rows.Scan(&indexName, &indexdef)
if err != nil {
return nil, err
}
if indexName == "primary" {
continue
}
2014-01-07 09:33:27 +00:00
indexName = strings.Trim(indexName, `" `)
if strings.HasSuffix(indexName, "_pkey") {
continue
}
2014-01-07 09:33:27 +00:00
if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
indexType = schemas.UniqueType
2014-01-07 09:33:27 +00:00
} else {
indexType = schemas.IndexType
2013-12-18 03:31:32 +00:00
}
colNames = getIndexColName(indexdef)
2017-04-05 10:17:41 +00:00
var isRegular bool
2013-12-18 03:31:32 +00:00
if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
2017-01-09 01:52:23 +00:00
newIdxName := indexName[5+len(tableName):]
2017-04-05 10:17:41 +00:00
isRegular = true
2013-12-18 03:31:32 +00:00
if newIdxName != "" {
indexName = newIdxName
}
}
index := &schemas.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
2013-12-18 03:31:32 +00:00
for _, colName := range colNames {
index.Cols = append(index.Cols, strings.TrimSpace(strings.Replace(colName, `"`, "", -1)))
2013-12-18 03:31:32 +00:00
}
2017-04-05 10:17:41 +00:00
index.IsRegular = isRegular
2013-12-18 03:31:32 +00:00
indexes[index.Name] = index
}
return indexes, nil
2013-10-12 15:16:51 +00:00
}
2014-01-07 09:33:27 +00:00
func (db *postgres) Filters() []Filter {
return []Filter{&SeqFilter{Prefix: "$", Start: 1}}
2014-01-07 09:33:27 +00:00
}
2017-03-23 06:05:32 +00:00
type pqDriver struct {
}
type values map[string]string
func (vs values) Set(k, v string) {
vs[k] = v
}
func (vs values) Get(k string) (v string) {
return vs[k]
}
func parseURL(connstr string) (string, error) {
u, err := url.Parse(connstr)
if err != nil {
return "", err
}
if u.Scheme != "postgresql" && u.Scheme != "postgres" {
return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
}
escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
if u.Path != "" {
return escaper.Replace(u.Path[1:]), nil
2017-03-23 06:05:32 +00:00
}
return "", nil
2017-03-23 06:05:32 +00:00
}
func parseOpts(name string, o values) error {
2017-03-23 06:05:32 +00:00
if len(name) == 0 {
return fmt.Errorf("invalid options: %s", name)
2017-03-23 06:05:32 +00:00
}
name = strings.TrimSpace(name)
ps := strings.Split(name, " ")
for _, p := range ps {
kv := strings.Split(p, "=")
if len(kv) < 2 {
return fmt.Errorf("invalid option: %q", p)
2017-03-23 06:05:32 +00:00
}
o.Set(kv[0], kv[1])
}
return nil
2017-03-23 06:05:32 +00:00
}
func (p *pqDriver) Parse(driverName, dataSourceName string) (*URI, error) {
db := &URI{DBType: schemas.POSTGRES}
2017-03-23 06:05:32 +00:00
var err error
2017-03-23 06:05:32 +00:00
if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") {
db.DBName, err = parseURL(dataSourceName)
if err != nil {
return nil, err
}
} else {
o := make(values)
err = parseOpts(dataSourceName, o)
2017-03-23 06:05:32 +00:00
if err != nil {
return nil, err
}
db.DBName = o.Get("dbname")
2017-03-23 06:05:32 +00:00
}
if db.DBName == "" {
2017-03-23 06:05:32 +00:00
return nil, errors.New("dbname is empty")
}
2017-03-23 06:05:32 +00:00
return db, nil
}
type pqDriverPgx struct {
pqDriver
}
func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*URI, error) {
// Remove the leading characters for driver to work
if len(dataSourceName) >= 9 && dataSourceName[0] == 0 {
dataSourceName = dataSourceName[9:]
}
return pgx.pqDriver.Parse(driverName, dataSourceName)
}
// QueryDefaultPostgresSchema returns the default postgres schema
func QueryDefaultPostgresSchema(ctx context.Context, queryer core.Queryer) (string, error) {
rows, err := queryer.QueryContext(ctx, "SHOW SEARCH_PATH")
if err != nil {
return "", err
}
defer rows.Close()
if rows.Next() {
var defaultSchema string
if err = rows.Scan(&defaultSchema); err != nil {
return "", err
}
parts := strings.Split(defaultSchema, ",")
return strings.TrimSpace(parts[len(parts)-1]), nil
}
return "", errors.New("No default schema")
}