|
- // 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 xorm
-
- import (
- "errors"
- "fmt"
- "net/url"
- "strconv"
- "strings"
-
- "xorm.io/core"
- )
-
- // from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html
- var (
- 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,
- "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,
- }
-
- // DefaultPostgresSchema default postgres schema
- DefaultPostgresSchema = "public"
- )
-
- const postgresPublicSchema = "public"
-
- type postgres struct {
- core.Base
- }
-
- func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error {
- err := db.Base.Init(d, db, uri, drivername, dataSourceName)
- if err != nil {
- return err
- }
- if db.Schema == "" {
- db.Schema = DefaultPostgresSchema
- }
- return nil
- }
-
- func (db *postgres) SqlType(c *core.Column) string {
- var res string
- switch t := c.SQLType.Name; t {
- case core.TinyInt:
- res = core.SmallInt
- return res
- case core.Bit:
- res = core.Boolean
- return res
- case core.MediumInt, core.Int, core.Integer:
- if c.IsAutoIncrement {
- return core.Serial
- }
- return core.Integer
- case core.BigInt:
- if c.IsAutoIncrement {
- return core.BigSerial
- }
- return core.BigInt
- case core.Serial, core.BigSerial:
- c.IsAutoIncrement = true
- c.Nullable = false
- res = t
- case core.Binary, core.VarBinary:
- return core.Bytea
- case core.DateTime:
- res = core.TimeStamp
- case core.TimeStampz:
- return "timestamp with time zone"
- case core.Float:
- res = core.Real
- case core.TinyText, core.MediumText, core.LongText:
- res = core.Text
- case core.NVarchar:
- res = core.Varchar
- case core.Uuid:
- return core.Uuid
- case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob:
- return core.Bytea
- case core.Double:
- return "DOUBLE PRECISION"
- default:
- if c.IsAutoIncrement {
- return core.Serial
- }
- 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)
-
- if hasLen2 {
- res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")"
- } else if hasLen1 {
- res += "(" + strconv.Itoa(c.Length) + ")"
- }
- return res
- }
-
- func (db *postgres) SupportInsertMany() bool {
- return true
- }
-
- func (db *postgres) IsReserved(name string) bool {
- _, ok := postgresReservedWords[name]
- return ok
- }
-
- func (db *postgres) Quote(name string) string {
- name = strings.Replace(name, ".", `"."`, -1)
- return "\"" + name + "\""
- }
-
- func (db *postgres) AutoIncrStr() string {
- return ""
- }
-
- func (db *postgres) SupportEngine() bool {
- return false
- }
-
- func (db *postgres) SupportCharset() bool {
- return false
- }
-
- func (db *postgres) IndexOnTable() bool {
- return false
- }
-
- func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) {
- if len(db.Schema) == 0 {
- args := []interface{}{tableName, idxName}
- return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args
- }
-
- args := []interface{}{db.Schema, tableName, idxName}
- return `SELECT indexname FROM pg_indexes ` +
- `WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args
- }
-
- func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) {
- if len(db.Schema) == 0 {
- args := []interface{}{tableName}
- return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args
- }
-
- args := []interface{}{db.Schema, tableName}
- return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args
- }
-
- func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string {
- if len(db.Schema) == 0 {
- 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.Schema, tableName, col.Name, db.SqlType(col))
- }
-
- func (db *postgres) DropIndexSql(tableName string, index *core.Index) string {
- quote := db.Quote
- idxName := index.Name
-
- tableName = strings.Replace(tableName, `"`, "", -1)
- tableName = strings.Replace(tableName, `.`, "_", -1)
-
- if !strings.HasPrefix(idxName, "UQE_") &&
- !strings.HasPrefix(idxName, "IDX_") {
- if index.Type == core.UniqueType {
- idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name)
- } else {
- idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name)
- }
- }
- if db.Uri.Schema != "" {
- idxName = db.Uri.Schema + "." + idxName
- }
- return fmt.Sprintf("DROP INDEX %v", quote(idxName))
- }
-
- func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) {
- args := []interface{}{db.Schema, 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.Schema) == 0 {
- args = []interface{}{tableName, colName}
- query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" +
- " AND column_name = $2"
- }
- db.LogSQL(query, args)
-
- rows, err := db.DB().Query(query, args...)
- if err != nil {
- return false, err
- }
- defer rows.Close()
-
- return rows.Next(), nil
- }
-
- func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) {
- args := []interface{}{tableName}
- s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length,
- 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 c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;`
-
- var f string
- if len(db.Schema) != 0 {
- args = append(args, db.Schema)
- f = " AND s.table_schema = $2"
- }
- s = fmt.Sprintf(s, f)
-
- db.LogSQL(s, args)
-
- rows, err := db.DB().Query(s, args...)
- if err != nil {
- return nil, nil, err
- }
- defer rows.Close()
-
- cols := make(map[string]*core.Column)
- colSeq := make([]string, 0)
-
- for rows.Next() {
- col := new(core.Column)
- col.Indexes = make(map[string]int)
-
- var colName, isNullable, dataType string
- var maxLenStr, colDefault *string
- var isPK, isUnique bool
- err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique)
- if err != nil {
- return nil, nil, err
- }
-
- // fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique)
- var maxLen int
- if maxLenStr != nil {
- maxLen, err = strconv.Atoi(*maxLenStr)
- if err != nil {
- return nil, nil, err
- }
- }
-
- col.Name = strings.Trim(colName, `" `)
-
- if colDefault != nil {
- col.Default = *colDefault
- col.DefaultIsEmpty = false
- if strings.HasPrefix(col.Default, "nextval(") {
- col.IsAutoIncrement = true
- }
- } else {
- col.DefaultIsEmpty = true
- }
-
- if isPK {
- col.IsPrimaryKey = true
- }
-
- col.Nullable = (isNullable == "YES")
-
- switch dataType {
- case "character varying", "character":
- col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 0, DefaultLength2: 0}
- case "timestamp without time zone":
- col.SQLType = core.SQLType{Name: core.DateTime, DefaultLength: 0, DefaultLength2: 0}
- case "timestamp with time zone":
- col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0}
- case "double precision":
- col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0}
- case "boolean":
- col.SQLType = core.SQLType{Name: core.Bool, DefaultLength: 0, DefaultLength2: 0}
- case "time without time zone":
- col.SQLType = core.SQLType{Name: core.Time, DefaultLength: 0, DefaultLength2: 0}
- case "oid":
- col.SQLType = core.SQLType{Name: core.BigInt, DefaultLength: 0, DefaultLength2: 0}
- default:
- col.SQLType = core.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0}
- }
- if _, ok := core.SqlTypes[col.SQLType.Name]; !ok {
- return nil, nil, fmt.Errorf("Unknown colType: %v", dataType)
- }
-
- 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")
- }
- }
- }
- cols[col.Name] = col
- colSeq = append(colSeq, col.Name)
- }
-
- return colSeq, cols, nil
- }
-
- func (db *postgres) GetTables() ([]*core.Table, error) {
- args := []interface{}{}
- s := "SELECT tablename FROM pg_tables"
- if len(db.Schema) != 0 {
- args = append(args, db.Schema)
- s = s + " WHERE schemaname = $1"
- }
-
- db.LogSQL(s, args)
-
- rows, err := db.DB().Query(s, args...)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- tables := make([]*core.Table, 0)
- for rows.Next() {
- table := core.NewEmptyTable()
- var name string
- err = rows.Scan(&name)
- if err != nil {
- return nil, err
- }
- table.Name = name
- tables = append(tables, table)
- }
- return tables, nil
- }
-
- 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(tableName string) (map[string]*core.Index, error) {
- args := []interface{}{tableName}
- s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1")
- if len(db.Schema) != 0 {
- args = append(args, db.Schema)
- s = s + " AND schemaname=$2"
- }
- db.LogSQL(s, args)
-
- rows, err := db.DB().Query(s, args...)
- if err != nil {
- return nil, err
- }
- defer rows.Close()
-
- indexes := make(map[string]*core.Index, 0)
- for rows.Next() {
- var indexType int
- var indexName, indexdef string
- var colNames []string
- err = rows.Scan(&indexName, &indexdef)
- if err != nil {
- return nil, err
- }
- indexName = strings.Trim(indexName, `" `)
- if strings.HasSuffix(indexName, "_pkey") {
- continue
- }
- if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") {
- indexType = core.UniqueType
- } else {
- indexType = core.IndexType
- }
- colNames = getIndexColName(indexdef)
- var isRegular bool
- if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) {
- newIdxName := indexName[5+len(tableName):]
- isRegular = true
- if newIdxName != "" {
- indexName = newIdxName
- }
- }
-
- index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)}
- for _, colName := range colNames {
- index.Cols = append(index.Cols, strings.Trim(colName, `" `))
- }
- index.IsRegular = isRegular
- indexes[index.Name] = index
- }
- return indexes, nil
- }
-
- func (db *postgres) Filters() []core.Filter {
- return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}}
- }
-
- 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
- }
-
- return "", nil
- }
-
- func parseOpts(name string, o values) error {
- if len(name) == 0 {
- return fmt.Errorf("invalid options: %s", name)
- }
-
- 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)
- }
- o.Set(kv[0], kv[1])
- }
-
- return nil
- }
-
- func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) {
- db := &core.Uri{DbType: core.POSTGRES}
- var err error
-
- 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)
- if err != nil {
- return nil, err
- }
-
- db.DbName = o.Get("dbname")
- }
-
- if db.DbName == "" {
- return nil, errors.New("dbname is empty")
- }
-
- return db, nil
- }
-
- type pqDriverPgx struct {
- pqDriver
- }
-
- func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.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)
- }
|