Database progress

dev
POUDEROUX Tom 2025-04-27 23:59:23 +02:00
parent 91dd9ce173
commit 15deca0a90
1 changed files with 245 additions and 6 deletions

View File

@ -22,6 +22,112 @@ const (
database_ROUTINE_TYPE_FUNCTION uint8 = 2
)
type databaseEnumIndexType string
const (
database_ENUM_INDEX_PRIMARY databaseEnumIndexType = "PRIMARY"
database_ENUM_INDEX_UNIQUE databaseEnumIndexType = "UNIQUE"
)
type columsDefinition struct {
Name string
Type string
Default any
IsNullable bool
Extra string
Charset any
Collation any
Table string
}
type indexDefinition struct {
Type databaseEnumIndexType
Name string
Table string
Columns []string
}
type foreignKeyDefinition struct {
Name string
Table string
ColumnName string
PointingToTable string
PointingToColumn string
UpdateRule string
DeleteRule string
}
type tableDefinition struct {
Name string
Columns []columsDefinition
}
type databaseDefinition struct {
Name string
Tables []tableDefinition
Indexes []indexDefinition
ForeignKeys []foreignKeyDefinition
}
var listTables = []tableDefinition{
{
Name: "users",
Columns: []columsDefinition{
{
Name: "id",
Type: "int(11)",
Default: nil,
IsNullable: false,
Extra: "AUTO_INCREMENT",
},
{
Name: "name",
Type: "varchar(256)",
Default: nil,
IsNullable: false,
Extra: "",
Charset: "utf8mb4",
Collation: "utf8mb4_unicode_ci",
},
{
Name: "password",
Type: "varchar(256)",
Default: nil,
IsNullable: false,
Extra: "",
Charset: "utf8mb4",
Collation: "utf8mb4_unicode",
},
{
Name: "password-salt",
Type: "varchar(256)",
Default: nil,
IsNullable: false,
Extra: "",
Charset: "utf8mb4",
Collation: "utf8mb4_unicode",
},
{
Name: "permission_level",
Type: "enum('ADMIN', 'MODERATOR', 'USER')",
Default: "USER",
IsNullable: false,
Extra: "",
Charset: nil,
},
{
Name: "email",
Type: "varchar(256)",
Default: nil,
IsNullable: true,
Extra: "",
Charset: "utf8mb4",
Collation: "utf8mb4_unicode",
},
},
},
}
var dbPath string
var dbConfig config.Database
var isInit bool
@ -40,14 +146,10 @@ func Init() {
profiler.Register(profiler_DATABASE_QUERY, 4000, "µs")
isInit = true
fetchStoredRoutines()
initDatabaseStructure()
}
func connect() {
if !isInit {
return
}
var err error
log.Printf("Connecting to database %s at %s:%d as %s\n", dbConfig.Database, dbConfig.Host, dbConfig.Port, dbConfig.User)
@ -170,6 +272,7 @@ func fetchStoredRoutines() {
}
}
}
fmt.Print("ROUTINES : ")
fmt.Println(storedRoutines)
}
@ -192,9 +295,145 @@ func callStoredProcedure(name string, args ...any) {
rows.Scan(&res)
log.Println(res)
}
}
func callStoredFunction(name string, args ...any) {
var query string
if len(args) == 0 {
query = fmt.Sprintf("SELECT %s()", name)
} else if len(args) == 1 {
query = fmt.Sprintf("SELECT %s(?)", name)
} else {
query = strings.Repeat(", ?", len(args)-1)
query = fmt.Sprintf("SELECT %s(?%s)", name, query)
}
var rows *sql.Rows = executeQuery(query, args...)
defer rows.Close()
for rows.Next() {
var res string
rows.Scan(&res)
log.Println(res)
}
}
func fetchTables() []string {
var query string = fmt.Sprintf("SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA=\"%s\";", dbConfig.Database)
var rows *sql.Rows = executeQuery(query)
var tables []string = make([]string, 0)
if rows != nil {
defer rows.Close()
for rows.Next() {
var resName string
rows.Scan(&resName)
tables = append(tables, resName)
}
}
return tables
}
func fetchColumns(table string) []columsDefinition {
var query string = fmt.Sprintf("SELECT COLUMN_NAME, COLUMN_TYPE, COLUMN_DEFAULT, IS_NULLABLE, EXTRA, CHARACTER_SET_NAME, COLLATION_NAME FROM information_schema.COLUMNS WHERE TABLE_SCHEMA=\"%s\" AND TABLE_NAME=\"%s\";", dbConfig.Database, table)
var rows *sql.Rows = executeQuery(query)
var columns []columsDefinition = make([]columsDefinition, 0)
if rows != nil {
defer rows.Close()
for rows.Next() {
var resName, resType, resDefault, resNullable, resExtra, resCharset, resCollation string
rows.Scan(&resName, &resType, &resDefault, &resNullable, &resExtra, &resCharset, &resCollation)
columns = append(columns, columsDefinition{
Name: resName,
Type: resType,
Default: resDefault,
IsNullable: resNullable == "YES",
Extra: resExtra,
Charset: resCharset,
Collation: resCollation,
Table: table,
})
}
}
return columns
}
func fetchIndexes() []indexDefinition {
// SELECT * FROM STATISTICS as S INNER JOIN TABLE_CONSTRAINTS as TC ON TC.TABLE_SCHEMA = S.TABLE_SCHEMA AND TC.CONSTRAINT_NAME = S.INDEX_NAME AND TC.TABLE_NAME = S.TABLE_NAME WHERE S.TABLE_SCHEMA = "RPG";
// SELECT S.COLUMN_NAME as COLUMN_NAME, S.INDEX_NAME AS INDEX_NAME, TC.CONSTRAINT_TYPE AS CONSTRAINT_TYPE FROM STATISTICS as S INNER JOIN TABLE_CONSTRAINTS as TC ON TC.TABLE_SCHEMA = S.TABLE_SCHEMA AND TC.CONSTRAINT_NAME = S.INDEX_NAME AND TC.TABLE_NAME = S.TABLE_NAME WHERE S.TABLE_SCHEMA = "RPG" AND S.TABLE_NAME = "folders" AND TC.CONSTRAINT_TYPE IN("UNIQUE", "PRIMARY KEY");
// Add PRIMARY : ALTER TABLE <table> ADD CONSTRAINT PRIMARY KEY(<columns>);
// Add UNIQUE : ALTER TABLE <table> ADD CONSTRAINT <constraint_name> UNIQUE(<columns>);
var query string = fmt.Sprintf("SELECT S.COLUMN_NAME as COLUMN_NAME, S.INDEX_NAME AS INDEX_NAME, TC.CONSTRAINT_TYPE AS CONSTRAINT_TYPE, S.TABLE_NAME AS TABLE_NAME FROM information_schema.STATISTICS as S INNER JOIN information_schema.TABLE_CONSTRAINTS as TC ON TC.TABLE_SCHEMA = S.TABLE_SCHEMA AND TC.CONSTRAINT_NAME = S.INDEX_NAME AND TC.TABLE_NAME = S.TABLE_NAME WHERE S.TABLE_SCHEMA = \"%s\" AND TC.CONSTRAINT_TYPE IN(\"UNIQUE\", \"PRIMARY KEY\");", dbConfig.Database)
fmt.Println(query)
var rows *sql.Rows = executeQuery(query)
var indexes []indexDefinition = make([]indexDefinition, 0)
if rows != nil {
defer rows.Close()
for rows.Next() {
var resColumn, resIndex, resType, resTable string
rows.Scan(&resColumn, &resIndex, &resType, &resTable)
var index indexDefinition = indexDefinition{
Table: resTable,
Name: resIndex,
Type: database_ENUM_INDEX_PRIMARY,
Columns: []string{resColumn},
}
if resType == "UNIQUE" {
index.Type = database_ENUM_INDEX_UNIQUE
}
indexes = append(indexes, index)
}
}
return indexes
}
func fetchForeignKeys() []foreignKeyDefinition {
// ADD ALTER TABLE <table> ADD CONSTRAINT <constraint_name> FOREIGN KEY(<column>) REFERENCES <ref_table>(<ref_column>) ON DELETE <CASCADE / SET NULL> UPDATE <CASCADE / SET NULL>;
// SELECT RC.CONSTRAINT_NAME as CONTRAINT_NAME, KCU.TABLE_NAME, KCU.COLUMN_NAME, KCU.REFERENCED_TABLE_NAME, KCU.REFERENCED_COLUMN_NAME, RC.UPDATE_RULE, RC.DELETE_RULE FROM REFERENTIAL_CONSTRAINTS AS RC INNER JOIN KEY_COLUMN_USAGE AS KCU ON KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME WHERE KCU.TABLE_SCHEMA = "RPG";
var query string = fmt.Sprintf("SELECT INDEX_NAME, COLUMN_NAME FROM information_schema.STATISTICS WHERE TABLE_SCHEMA=\"%s\";", dbConfig.Database)
var rows *sql.Rows = executeQuery(query)
var fk []foreignKeyDefinition = make([]foreignKeyDefinition, 0)
if rows != nil {
defer rows.Close()
for rows.Next() {
var resName string
rows.Scan(&resName)
fk = append(fk, foreignKeyDefinition{
Name: resName,
})
}
}
return fk
}
func initDatabaseStructure() {
fetchStoredRoutines()
fetchIndexes()
fetchForeignKeys()
var tables []string = fetchTables()
for i := range tables {
var columns []columsDefinition = fetchColumns(tables[i])
fmt.Printf("Table %s : \n", tables[i])
for j := range columns {
fmt.Printf(" - Column %s %s IsNullable:%t Default:%s Extra:%s Charset:%s/%s\n",
columns[j].Name, columns[j].Type, columns[j].IsNullable, columns[j].Default, columns[j].Extra, columns[j].Charset, columns[j].Collation)
}
}
var indexes []indexDefinition = fetchIndexes()
for i := range indexes {
fmt.Printf("Index %s : \n", indexes[i])
}
var fk []foreignKeyDefinition = fetchForeignKeys()
for i := range fk {
fmt.Printf("Foreign key %s : \n", fk[i])
}
}