package store import ( "context" "database/sql" . "ffqp_go/src/common" "fmt" _ "github.com/denisenkom/go-mssqldb" "reflect" "strconv" "time" ) type sql_task struct { sql string v []interface{} } var ( db_in_thread_chan = make(chan sql_task, 1000) DBCon *sql.DB SQL_TIME_NULL = SQL_TIME{Valid: false} ) func SQL_INIT() error { conn_str := fmt.Sprintf("server=%s;user id=%s;password=%s;port=%d;database=%s;log=0;", "localhost", "sa", DB_PWD, 1433, "sadb") conn, err := sql.Open("sqlserver", conn_str) if err != nil { TRACE_ERROR(err) return err } if err := conn.Ping(); err != nil { TRACE_ERROR(err) return err } conn.SetMaxOpenConns(48) conn.SetMaxIdleConns(24) DBCon = conn return nil } type SQL_TIME struct { Time time.Time Valid bool } func (c SQL_TIME) IsNotToday() bool { return !c.IsToday() } func (c SQL_TIME) IsToday() bool { if !c.Valid { return false } return IS_TOADY(c.Time) } func (c SQL_TIME) String() string { return TIME_2_STR(c.Time) } type SQL_VALUE struct { db_name string db_val interface{} } func (c SQL_VALUE) Int() int64 { if c.db_val == nil { return 0 } rv := reflect.ValueOf(c.db_val) switch rv.Kind() { case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return rv.Int() default: TRACE_ERROR(LOGIC("SQL_VALUE TYPE LOGIC Int:" + c.db_name)) } return 0 } func (c SQL_VALUE) String() string { rv := reflect.ValueOf(c.db_val) switch rv.Kind() { case reflect.String: return c.db_val.(string) case reflect.Slice: switch (c.db_val).(type) { case []uint8: return string((c.db_val).([]uint8)) } case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: return ITOA64(rv.Int()) case reflect.Float64, reflect.Float32: return strconv.FormatFloat(rv.Float(), 'f', 6, 64) } return "UNKNWONTYPE:" + c.db_name } func (c SQL_VALUE) Str() string { if c.db_val == nil { return "" } rv := reflect.ValueOf(c.db_val) switch rv.Kind() { case reflect.String: return c.db_val.(string) case reflect.Slice: switch (c.db_val).(type) { case []uint8: return string((c.db_val).([]uint8)) } default: TRACE_ERROR(LOGIC("SQL_VALUE TYPE LOGIC Str:" + c.db_name)) } return "" } func (c SQL_VALUE) Float() float64 { if c.db_val == nil { return 0 } rv := reflect.ValueOf(c.db_val) switch rv.Kind() { case reflect.Float64, reflect.Float32: return rv.Float() default: TRACE_ERROR(LOGIC("SQL_VALUE TYPE LOGIC Float:" + c.db_name)) } return 0 } func (c SQL_VALUE) Bool() bool { return c.Int() != 0 } func (c SQL_VALUE) Tm() SQL_TIME { if c.db_val == nil { return SQL_TIME{Valid: false} } return SQL_TIME{Valid: true, Time: c.db_val.(time.Time)} } func (c SQL_VALUE) TmStr() string { tm := c.Tm() if !tm.Valid { return "" } return TIME_2_STR(tm.Time) } func SQL_EXEC(sql_str string, v ...interface{}) error { stmt, err := DBCon.Prepare(sql_str) if err != nil { return err } ctx := context.Background() _, err = stmt.ExecContext(ctx, sql_param(v)...) if err != nil { return err } return nil } func SQL_EXEC_I(sql_str string, v ...interface{}) { stmt, err := DBCon.Prepare(sql_str) if err != nil { LOG.Printf(err.Error() + "\n SQL IS:" + fmt.Sprintf(sql_str, v...)) return } ctx := context.Background() _, err = stmt.ExecContext(ctx, v...) if err != nil { LOG.Printf(err.Error() + "\n SQL IS:" + fmt.Sprintf(sql_str, v...)) return } } func SQL_INSERT(sql_str string, v ...interface{}) (int64, error) { inert_id := int64(0) stmt, err := DBCon.Prepare(sql_str) if err != nil { return inert_id, err } ctx := context.Background() rs, err := stmt.ExecContext(ctx, sql_param(v)...) if err != nil { return inert_id, err } rows_affect, err := rs.RowsAffected() if err != nil { return inert_id, err } if rows_affect != 0 { inert_id, err = rs.LastInsertId() if err != nil { inert_id = 0 } } return inert_id, err } func SQL_ARRAY_I(sql_str string, v ...interface{}) ([]map[string]SQL_VALUE, error) { stmt, err := DBCon.Prepare(sql_str) if err != nil { return nil, err } defer stmt.Close() ctx := context.Background() rows, err := stmt.QueryContext(ctx, sql_param(v)...) if err != nil { return nil, err } defer rows.Close() columns, err := rows.Columns() var result_dict = make([]map[string]SQL_VALUE, 0) for rows.Next() { values := make([]interface{}, len(columns)) scan_args := make([]interface{}, len(columns)) values_map := make(map[string]SQL_VALUE) for i := range values { scan_args[i] = &values[i] } err = rows.Scan(scan_args...) for i := range columns { values_map[columns[i]] = SQL_VALUE{columns[i], values[i]} } result_dict = append(result_dict, values_map) if err != nil { return nil, err } } return result_dict, nil } func SQL_ARRAY(sql_str string, v ...interface{}) ([]map[string]SQL_VALUE, error) { return SQL_ARRAY_I(sql_str, v...) } func SQL_IS_EXIST(sql_str string, v ...interface{}) (bool, error) { stmt, err := DBCon.Prepare(sql_str) if err != nil { return false, err } defer stmt.Close() ctx := context.Background() rows, err := stmt.QueryContext(ctx, sql_param(v)...) if err != nil { return false, err } defer rows.Close() for rows.Next() { return true, nil } return false, nil } func SQL_IS_NOT_EXIST(sql_str string, v ...interface{}) (bool, error) { ret, err := SQL_IS_EXIST(sql_str, v...) if err != nil { ret = !ret } return ret, err } func SQL_ROW(sql_str string, v ...interface{}) (map[string]SQL_VALUE, error) { stmt, err := DBCon.Prepare(sql_str) if err != nil { return nil, err } defer stmt.Close() ctx := context.Background() rows, err := stmt.QueryContext(ctx, sql_param(v)...) if err != nil { return nil, err } defer rows.Close() columns, err := rows.Columns() for rows.Next() { values := make([]interface{}, len(columns)) scan_args := make([]interface{}, len(columns)) values_map := make(map[string]SQL_VALUE) for i := range values { scan_args[i] = &values[i] } err = rows.Scan(scan_args...) if err != nil { return nil, err } for i := range values { values_map[columns[i]] = SQL_VALUE{columns[i], values[i]} } return values_map, nil } return nil, nil } func sql_param(v []interface{}) []interface{} { var ps []interface{} for _, p := range v { sql_v, ok := p.(SQL_VALUE) if ok { ps = append(ps, sql_v.db_val) } else { ps = append(ps, p) } } return ps } func SQL_IN_THREAD(sql_str string, v ...interface{}) { packet := new(sql_task) packet.sql = sql_str packet.v = v db_in_thread_chan <- *packet } func DB_IN_THREAD() { go func() { select { case sql_task := <-db_in_thread_chan: _ = SQL_EXEC(sql_task.sql, sql_task.v...) default: time.Sleep(5 * time.Second) } }() } func SQL_PROC(sql_str string, v ...interface{}) ([][]map[string]SQL_VALUE, error) { stmt, err := DBCon.Prepare("DECLARE @RC int;" + sql_str + ";SELECT @RC AS RET;") if err != nil { return nil, err } defer stmt.Close() ctx := context.Background() rows, err := stmt.QueryContext(ctx, sql_param(v)...) if err != nil { return nil, err } defer rows.Close() var result_sets [][]map[string]SQL_VALUE for { columns, err := rows.Columns() var result_dict = make([]map[string]SQL_VALUE, 0) for rows.Next() { values := make([]interface{}, len(columns)) scan_args := make([]interface{}, len(columns)) values_map := make(map[string]SQL_VALUE) for i := range values { scan_args[i] = &values[i] } err = rows.Scan(scan_args...) for i := range columns { values_map[columns[i]] = SQL_VALUE{columns[i], values[i]} } result_dict = append(result_dict, values_map) if err != nil { return nil, err } } result_sets = append(result_sets, result_dict) if !rows.NextResultSet() { break } } return result_sets, nil }