-
Notifications
You must be signed in to change notification settings - Fork 0
/
postgres.go
156 lines (139 loc) · 3.52 KB
/
postgres.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
package main
import "database/sql"
type postgresColumnInfo struct {
Name string
DataType string
Nullable bool
IsArray bool
DataTypeName string
}
type postgresDialect struct{}
func (postgresDialect) tables(db *sql.DB, tableSchema string) ([]string, error) {
const query = `
SELECT
table_name
FROM
information_schema.tables
WHERE
(
table_type = 'BASE TABLE' OR
table_type = 'VIEW'
) AND table_schema = $1
ORDER BY
table_name`
rows, err := db.Query(query, tableSchema)
if err != nil {
return nil, err
}
defer rows.Close()
var names []string
for rows.Next() {
var name string
if err = rows.Scan(&name); err != nil {
return nil, err
}
names = append(names, name)
}
return names, nil
}
func (postgresDialect) primaryKeys(db *sql.DB, tableSchema, tableName string) (map[string]bool, error) {
const query = `
SELECT
kcu.column_name
FROM
information_schema.table_constraints tco
JOIN
information_schema.key_column_usage kcu
ON kcu.constraint_name = tco.constraint_name AND
kcu.constraint_schema = tco.constraint_schema AND
kcu.constraint_name = tco.constraint_name
WHERE
tco.constraint_type = 'PRIMARY KEY' AND
kcu.table_schema = $1 AND
kcu.table_name = $2
ORDER BY
kcu.ordinal_position`
rows, err := db.Query(query, tableSchema, tableName)
if err != nil {
return nil, err
}
defer rows.Close()
pks := make(map[string]bool)
for rows.Next() {
var name string
if err = rows.Scan(&name); err != nil {
return nil, err
}
pks[name] = true
}
return pks, nil
}
func (postgresDialect) columns(db *sql.DB, tableSchema, tableName string) ([]postgresColumnInfo, error) {
const query = `
SELECT
column_name,
data_type,
is_nullable = 'YES' as nullable,
data_type = 'ARRAY' as is_array,
udt_name::regtype as udt_name
FROM information_schema.columns
WHERE
table_schema = $1 AND
table_name = $2
ORDER BY
column_name`
rows, err := db.Query(query, tableSchema, tableName)
if err != nil {
return nil, err
}
defer rows.Close()
var cols []postgresColumnInfo
for rows.Next() {
var name, dataType, dataTypeName string
var nullable, isArray bool
if err = rows.Scan(&name, &dataType, &nullable, &isArray, &dataTypeName); err != nil {
return nil, err
}
cols = append(cols, postgresColumnInfo{
Name: name,
DataType: dataType,
Nullable: nullable,
IsArray: isArray,
DataTypeName: dataTypeName,
})
}
return cols, nil
}
func (postgresDialect) foreignTables(db *sql.DB, tableSchema, tableName string) (map[string]string, error) {
const query = `
SELECT
kcu.column_name,
ccu.table_name AS foreign_table_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu
ON tc.constraint_name = kcu.constraint_name
AND tc.table_schema = kcu.table_schema
JOIN information_schema.constraint_column_usage AS ccu
ON ccu.constraint_name = tc.constraint_name
AND ccu.table_schema = tc.table_schema
WHERE
tc.constraint_type = 'FOREIGN KEY' AND
tc.table_schema = $1 AND
ccu.table_schema = $1 AND
tc.table_name= $2`
rows, err := db.Query(query, tableSchema, tableName)
if err != nil {
return nil, err
}
defer rows.Close()
foreignTableNames := make(map[string]string, 0)
for rows.Next() {
var col, ftable string
if err := rows.Scan(&col, &ftable); err != nil {
return nil, err
}
foreignTableNames[col] = ftable
}
return foreignTableNames, nil
}