예제 #1
0
func (tbl *Table) FieldName(field string) string {
	_, ok := tbl._structfieldmap[field]
	if ok {
		return field
	}
	field = sqlx.NameMapper(field)
	_, ok = tbl._structfieldmap[field]
	if ok {
		return field
	}
	return field + "_unk"
}
예제 #2
0
func (db *Db) FindRefs(name string) []string {
	var ret []string = []string{sqlx.NameMapper(name)}
	for _, tbl := range db.Tables {
		if tbl.Name != name {
			continue
		}
		for _, fld := range tbl.Fields {
			if len(fld.Ref) <= 0 {
				continue
			}
			res := db.FindRefs(fld.Ref)
			for _, n := range res {
				if !util.StringInSlice(n, ret) {
					ret = append(ret, n)
				}
			}
		}
	}
	return ret
}
예제 #3
0
func (db *Db) ApplyRebuilds() error {
	rNames := make([]string, 0)
	for _, tbl := range db.Tables {
		if tbl._rebuildorg != tbl._rebuildnew {
			rNames = append(rNames, db.FindRefs(tbl.Name)...)
			//log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>", tbl.Name, tbl._rebuildorg, tbl._rebuildnew)
		}
	}
	if len(rNames) <= 0 {
		return nil
	}

	for {
		bChange := false
		for _, tbl := range db.Tables {
			if util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) {
				continue
			}
			refs := db.FindRefs(tbl.Name)[1:]
			//log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>2", tbl.Name, refs)
			for _, n := range refs {
				if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) && util.StringInSlice(n, rNames) {
					rNames = append(rNames, sqlx.NameMapper(tbl.Name))
					//log.Println(">>>>>>>>>>>>>>>>>>>>>>>>>3", n)
					bChange = true
				}
			}
		}
		if !bChange {
			break
		}
	}

	log.Println("!!!DB Rebuild Begin!!!", rNames)

	tx, err := db.Begin()
	if err != nil {
		return err
	}

	for _, tbl := range db.Tables {
		if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) {
			continue
		}
		err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 0)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	for _, tbl := range db.Tables {
		if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) {
			continue
		}
		err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 1)
		if err != nil {
			tx.Rollback()
			return err
		}
	}
	for _, tbl := range db.Tables {
		if !util.StringInSlice(sqlx.NameMapper(tbl.Name), rNames) {
			continue
		}
		err := db.RebuildTable(tbl.Name, tbl._rebuildorg, tbl._rebuildnew, tx, 2)
		if err != nil {
			tx.Rollback()
			return err
		}

		for _, fld := range tbl.Fields {
			if len(fld.Index) > 0 {
				_, err := db.DB.Exec(fld.Index)
				if err != nil {
					tx.Rollback()
					return err
				}
			}
		}
	}

	tx.Commit()
	db.DB.Exec("VACUUM;")

	log.Println("!!!DB Rebuild Successful!!!")
	return nil
}
예제 #4
0
func (db *Db) InitTableName(t interface{}, name string) (*Table, error) {
	val := reflect.ValueOf(t)    //.Elem()
	reftype := reflect.TypeOf(t) //.Elem()

	fm, err := sqlx.StructFieldMap(t)
	if err != nil {
		fmt.Println("Error: ", err)
		return nil, err
	}

	cmdCreate := "CREATE TABLE IF NOT EXISTS " + name + " ( "
	cmdIdx := make([]string, 0, 32)
	fields := make([]Field, 0, 32)
	primKey := ""
	primType := COLTYPE_STRING
	primAuto := false
	hasuqnoprim := false

	for i := 0; i < val.NumField(); i++ {
		valueField := val.Field(i)
		typeField := val.Type().Field(i)

		// skip unexported field
		if len(typeField.PkgPath) != 0 {
			continue
		}

		tag := typeField.Tag
		fn := sqlx.NameMapper(typeField.Name)
		tn := valueField.Kind().String()
		if tag := tag.Get("db"); tag != "" {
			fn = tag
		}

		//skip nameless field
		if len(fn) <= 0 || fn == "dbcache" {
			continue
		}

		tagIdx := tag.Get("sqlidx")
		tagUIdx := tag.Get("sqluidx")
		tagSql := tag.Get("sql")
		bPrim := strings.Contains(strings.ToLower(tagSql), "primary")
		bAutoInc := strings.Contains(strings.ToLower(tagSql), "autoincrement")
		bUnique := bPrim || strings.Contains(strings.ToLower(tagSql), "unique")
		bRef := strings.Contains(strings.ToLower(tagSql), "references")

		if tn == "int8" || tn == "int16" || tn == "int32" || tn == "int64" || tn == "uint8" || tn == "uint16" || tn == "uint32" || tn == "uint64" {
			tn = "integer"
			if bPrim {
				primType = COLTYPE_INT
			}
		} else if tn == "string" {
			tn = "text"
		} else if tn == "float32" || tn == "float64" {
			tn = "real"
			if bPrim {
				primType = COLTYPE_FLOAT
			}
		} else if tn == "slice" {
			//sliceType:=typeField.Type.Elem();
			//bPtr:=sliceType.String()[0]=="*"
			continue
		} else if tn == "struct" {
			tn = typeField.Type.Name()
			if tn == "NullString" {
				tn = "text"
			} else {
				fmt.Println("!tn2: ", tn)
				continue
			}
		} else {
			fmt.Println("!tn: ", tn)
			continue
		}

		if bUnique && !bPrim {
			hasuqnoprim = true
		}

		if bPrim {
			primKey = fn
		}
		if bAutoInc {
			primAuto = true
		}

		if i > 0 {
			cmdCreate += " , "
		}
		cmdCreate += "" + fn + " " + tn + " " + tagSql

		varIdx, ok := fm[fn]
		if !ok {
			varIdx = -1
		}

		sRef := ""
		if bRef {
			sRef = strings.Split(tagSql, " ")[1]
		}

		bIndexUnique := false
		if len(tagUIdx) > 0 {
			bIndexUnique = true
			tagIdx = tagUIdx
		}
		ci := ""
		if len(tagIdx) > 0 {
			sUnique := " "
			if bIndexUnique {
				sUnique = " UNIQUE "
			}
			if !strings.Contains(tagIdx, ",") {
				tagIdx = "'" + fn + "' " + tagIdx
			}
			ci := "CREATE" + sUnique + "INDEX IF NOT EXISTS 'dbidx_" + name + "_" + fn + "' ON '" + name + "' (" + tagIdx + ");"
			cmdIdx = append(cmdIdx, ci)
		}
		//fmt.Printf("Field Name: %s,\t Field Value: %v,\t Tag Value: %s\n", typeField.Name, valueField.Interface(), tag.Get("tag_name"))
		fields = append(fields, Field{
			Name:     fn,
			Type:     tn,
			Primary:  bPrim,
			AutoInc:  bAutoInc,
			Unique:   bUnique,
			VarIndex: varIdx,
			Ref:      sRef,
			Index:    ci,
		})
	}
	cmdCreate += " ) "

	//fmt.Println("cmdCreate: ", cmdCreate)

	if primKey == "" {
		err := errors.New("No primary key found in Table: " + name)
		fmt.Println("Error: ", err)
		return nil, err
	}

	_, err = db.DB.Exec(cmdCreate)
	if err != nil {
		fmt.Println("Error: ", err, " cmd:", cmdCreate)
		return nil, err
	}
	for i := 0; i < len(cmdIdx); i++ {
		ci := cmdIdx[i]
		_, err := db.DB.Exec(ci)
		if err != nil {
			fmt.Println("Error: ", err, " cmd:", cmdCreate)
		}
	}

	qRes := db.DB.QueryRowx("select sql from sqlite_master where type='table' and tbl_name='" + name + "'")
	cmdCreateOrg := ""
	qRes.Scan(&cmdCreateOrg)

	iOrg := strings.Index(cmdCreateOrg, "(")
	cOrg := ""
	if iOrg >= 0 {
		cOrg = strings.TrimSpace(cmdCreateOrg[iOrg:])
	}
	cNew := strings.TrimSpace(cmdCreate[strings.Index(cmdCreate, "("):])

	if strings.Trim(cOrg, " ()") != strings.Trim(cNew, " ()") {
		log.Println("Table Layout Changed", name)
		log.Println("f--->", strings.Trim(cOrg, " ()"))
		log.Println("t--->", strings.Trim(cNew, " ()"))
		log.Println("rebuild pending ...")
		/*err := db.RebuildTable(name, cOrg, cNew)
		if err != nil {
			log.Println("!!!!!!!!!!!!!!!!!!!!!", err)
			panic(err)
			//return nil, err
		}*/
	} else {
		cOrg = cNew
	}

	tbl := &Table{
		Name:            name,
		Schema:          cmdCreate,
		Db:              db,
		Fields:          fields,
		PrimKey:         primKey,
		RefType:         reftype,
		PrimType:        primType,
		PrimAuto:        primAuto,
		_hasuqnoprim:    hasuqnoprim,
		_structfieldmap: fm,
		_rebuildorg:     cOrg,
		_rebuildnew:     cNew,
	}

	for i := 0; i < len(tbl.Fields); i++ {
		if tbl.Fields[i].Primary {
			continue
		}
		if len(tbl._allsetnames) > 0 {
			tbl._allsetnames += ","
		}
		field := sqlx.NameMapper(tbl.Fields[i].Name)
		tbl._allsetnames += field + "=:" + field + " "
	}
	for i := 0; i < len(tbl.Fields); i++ {
		if tbl.Fields[i].Primary {
			continue
		}
		if len(tbl._allsetvnames) > 0 {
			tbl._allsetvnames += ","
		}
		field := sqlx.NameMapper(tbl.Fields[i].Name)
		if field == "version" {
			tbl._allsetvnames += field + "=:" + field + " + 1 "
		} else {
			tbl._allsetvnames += field + "=:" + field + " "
		}
	}
	{
		var fn, vn string
		vn = ":"
		iC := len(tbl.Fields)
		for i := 0; i < iC; i++ {
			f := tbl.Fields[i]
			if f.AutoInc {
				//don't insert autoincrement field
				continue
			}
			if len(fn) > 0 {
				fn += ","
				vn += ", :"
			}
			fn += f.Name
			vn += f.Name
		}
		tbl._fieldnames, tbl._valuenames = fn, vn
	}

	db.Tables = append(db.Tables, tbl)
	return tbl, nil
}
예제 #5
0
func (db *Db) InitTable(t interface{}) (*Table, error) {
	val := reflect.ValueOf(t) //.Elem()
	name := sqlx.NameMapper(val.Type().Name())
	return db.InitTableName(t, name)
}