func (m *DbMap) TruncateTables() error {
	var err error
	for i := range m.tables {
		table := m.tables[i]
		_, e := m.Exec(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
		if e != nil {
			err = e
		}
	}
	for _, table := range m.dynamicTableMap() {
		_, e := m.Exec(fmt.Sprintf("%s %s;", m.Dialect.TruncateClause(), m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
		if e != nil {
			err = e
		}
	}
	return err
}
TruncateTables iterates through TableMaps registered to this DbMap and
executes "truncate table" statements against the database for each, or in the case of
sqlite, a "delete from" with no "where" clause, which uses the truncate optimization
(http://www.sqlite.org/lang_delete.html)
package gorp
import (
	"bytes"
	"database/sql"
	"database/sql/driver"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"
)
type DbMap struct {
	Db *sql.DB
	Dialect Dialect
	TypeConverter TypeConverter
	tables        []*TableMap
	tablesDynamic map[string]*TableMap  
	logger        GorpLogger
	logPrefix     string
}
func (m *DbMap) dynamicTableAdd(tableName string, tbl *TableMap) {
	if m.tablesDynamic == nil {
		m.tablesDynamic = make(map[string]*TableMap)
	}
	m.tablesDynamic[tableName] = tbl
}
func (m *DbMap) dynamicTableFind(tableName string) (*TableMap, bool) {
	if m.tablesDynamic == nil {
		return nil, false
	}
	tbl, found := m.tablesDynamic[tableName]
	return tbl, found
}
func (m *DbMap) dynamicTableMap() map[string]*TableMap {
	if m.tablesDynamic == nil {
		m.tablesDynamic = make(map[string]*TableMap)
	}
	return m.tablesDynamic
}
func (m *DbMap) CreateIndex() error {
	var err error
	dialect := reflect.TypeOf(m.Dialect)
	for _, table := range m.tables {
		for _, index := range table.indexes {
			err = m.createIndexImpl(dialect, table, index)
			if err != nil {
				break
			}
		}
	}
	for _, table := range m.dynamicTableMap() {
		for _, index := range table.indexes {
			err = m.createIndexImpl(dialect, table, index)
			if err != nil {
				break
			}
		}
	}
	return err
}
func (m *DbMap) createIndexImpl(dialect reflect.Type,
	table *TableMap,
	index *IndexMap) error {
	s := bytes.Buffer{}
	s.WriteString("create")
	if index.Unique {
		s.WriteString(" unique")
	}
	s.WriteString(" index")
	s.WriteString(fmt.Sprintf(" %s on %s", index.IndexName, table.TableName))
	if dname := dialect.Name(); dname == "PostgresDialect" && index.IndexType != "" {
		s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
	}
	s.WriteString(" (")
	for x, col := range index.columns {
		if x > 0 {
			s.WriteString(", ")
		}
		s.WriteString(m.Dialect.QuoteField(col))
	}
	s.WriteString(")")
	if dname := dialect.Name(); dname == "MySQLDialect" && index.IndexType != "" {
		s.WriteString(fmt.Sprintf(" %s %s", m.Dialect.CreateIndexSuffix(), index.IndexType))
	}
	s.WriteString(";")
	_, err := m.Exec(s.String())
	return err
}
func (t *TableMap) DropIndex(name string) error {
	var err error
	dialect := reflect.TypeOf(t.dbmap.Dialect)
	for _, idx := range t.indexes {
		if idx.IndexName == name {
			s := bytes.Buffer{}
			s.WriteString(fmt.Sprintf("DROP INDEX %s", idx.IndexName))
			if dname := dialect.Name(); dname == "MySQLDialect" {
				s.WriteString(fmt.Sprintf(" %s %s", t.dbmap.Dialect.DropIndexSuffix(), t.TableName))
			}
			s.WriteString(";")
			_, e := t.dbmap.Exec(s.String())
			if e != nil {
				err = e
			}
			break
		}
	}
	t.ResetSql()
	return err
}
func (m *DbMap) AddTable(i interface{}) *TableMap {
	return m.AddTableWithName(i, "")
}
func (m *DbMap) AddTableWithName(i interface{}, name string) *TableMap {
	return m.AddTableWithNameAndSchema(i, "", name)
}
func (m *DbMap) AddTableWithNameAndSchema(i interface{}, schema string, name string) *TableMap {
	t := reflect.TypeOf(i)
	if name == "" {
		name = t.Name()
	}
	for i := range m.tables {
		table := m.tables[i]
		if table.gotype == t {
			table.TableName = name
			return table
		}
	}
	tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
	var primaryKey []*ColumnMap
	tmap.Columns, primaryKey = m.readStructColumns(t)
	m.tables = append(m.tables, tmap)
	if len(primaryKey) > 0 {
		tmap.keys = append(tmap.keys, primaryKey...)
	}
	return tmap
}
func (m *DbMap) AddTableDynamic(inp DynamicTable, schema string) *TableMap {
	val := reflect.ValueOf(inp)
	elm := val.Elem()
	t := elm.Type()
	name := inp.TableName()
	if name == "" {
		panic("Missing table name in DynamicTable instance")
	}
	if _, found := m.dynamicTableFind(name); found {
		panic(fmt.Sprintf("A table with the same name %v already exists", name))
	}
	tmap := &TableMap{gotype: t, TableName: name, SchemaName: schema, dbmap: m}
	var primaryKey []*ColumnMap
	tmap.Columns, primaryKey = m.readStructColumns(t)
	if len(primaryKey) > 0 {
		tmap.keys = append(tmap.keys, primaryKey...)
	}
	m.dynamicTableAdd(name, tmap)
	return tmap
}
func (m *DbMap) readStructColumns(t reflect.Type) (cols []*ColumnMap, primaryKey []*ColumnMap) {
	primaryKey = make([]*ColumnMap, 0)
	n := t.NumField()
	for i := 0; i < n; i++ {
		f := t.Field(i)
		if f.Anonymous && f.Type.Kind() == reflect.Struct {
			subcols, subpk := m.readStructColumns(f.Type)
			for _, subcol := range subcols {
				shouldAppend := true
				for _, col := range cols {
					if !subcol.Transient && subcol.fieldName == col.fieldName {
						shouldAppend = false
						break
					}
				}
				if shouldAppend {
					cols = append(cols, subcol)
				}
			}
			if subpk != nil {
				primaryKey = append(primaryKey, subpk...)
			}
		} else {
			cArguments := strings.Split(f.Tag.Get("db"), ",")
			columnName := cArguments[0]
			var maxSize int
			var defaultValue string
			var isAuto bool
			var isPK bool
			var isNotNull bool
			for _, argString := range cArguments[1:] {
				argString = strings.TrimSpace(argString)
				arg := strings.SplitN(argString, ":", 2)
				switch arg[0] {
				case "size", "default":
					if len(arg) == 1 {
						panic(fmt.Sprintf("missing option value for option %v on field %v", arg[0], f.Name))
					}
				default:
					if len(arg) == 2 {
						panic(fmt.Sprintf("unexpected option value for option %v on field %v", arg[0], f.Name))
					}
				}
				switch arg[0] {
				case "size":
					maxSize, _ = strconv.Atoi(arg[1])
				case "default":
					defaultValue = arg[1]
				case "primarykey":
					isPK = true
				case "autoincrement":
					isAuto = true
				case "notnull":
					isNotNull = true
				default:
					panic(fmt.Sprintf("Unrecognized tag option for field %v: %v", f.Name, arg))
				}
			}
			if columnName == "" {
				columnName = f.Name
			}
			gotype := f.Type
			valueType := gotype
			if valueType.Kind() == reflect.Ptr {
				valueType = valueType.Elem()
			}
			value := reflect.New(valueType).Interface()
			if m.TypeConverter != nil {
				scanner, useHolder := m.TypeConverter.FromDb(value)
				if useHolder {
					value = scanner.Holder
					gotype = reflect.TypeOf(value)
				}
			}
			if typer, ok := value.(SqlTyper); ok {
				gotype = reflect.TypeOf(typer.SqlType())
			} else if valuer, ok := value.(driver.Valuer); ok {
				v, err := valuer.Value()
				if err == nil && v != nil {
					gotype = reflect.TypeOf(v)
				}
			}
			cm := &ColumnMap{
				ColumnName:   columnName,
				DefaultValue: defaultValue,
				Transient:    columnName == "-",
				fieldName:    f.Name,
				gotype:       gotype,
				isPK:         isPK,
				isAutoIncr:   isAuto,
				isNotNull:    isNotNull,
				MaxSize:      maxSize,
			}
			if isPK {
				primaryKey = append(primaryKey, cm)
			}
			shouldAppend := true
			for index, col := range cols {
				if !col.Transient && col.fieldName == cm.fieldName {
					cols[index] = cm
					shouldAppend = false
					break
				}
			}
			if shouldAppend {
				cols = append(cols, cm)
			}
		}
	}
	return
}
func (m *DbMap) CreateTables() error {
	return m.createTables(false)
}
func (m *DbMap) CreateTablesIfNotExists() error {
	return m.createTables(true)
}
func (m *DbMap) createTables(ifNotExists bool) error {
	var err error
	for i := range m.tables {
		table := m.tables[i]
		sql := table.SqlForCreate(ifNotExists)
		_, err = m.Exec(sql)
		if err != nil {
			return err
		}
	}
	for _, tbl := range m.dynamicTableMap() {
		sql := tbl.SqlForCreate(ifNotExists)
		_, err = m.Exec(sql)
		if err != nil {
			return err
		}
	}
	return err
}
func (m *DbMap) DropTable(table interface{}) error {
	t := reflect.TypeOf(table)
	tableName := ""
	if dyn, ok := table.(DynamicTable); ok {
		tableName = dyn.TableName()
	}
	return m.dropTable(t, tableName, false)
}
func (m *DbMap) DropTableIfExists(table interface{}) error {
	t := reflect.TypeOf(table)
	tableName := ""
	if dyn, ok := table.(DynamicTable); ok {
		tableName = dyn.TableName()
	}
	return m.dropTable(t, tableName, true)
}
func (m *DbMap) DropTables() error {
	return m.dropTables(false)
}
func (m *DbMap) DropTablesIfExists() error {
	return m.dropTables(true)
}
func (m *DbMap) dropTables(addIfExists bool) (err error) {
	for _, table := range m.tables {
		err = m.dropTableImpl(table, addIfExists)
		if err != nil {
			return err
		}
	}
	for _, table := range m.dynamicTableMap() {
		err = m.dropTableImpl(table, addIfExists)
		if err != nil {
			return err
		}
	}
	return err
}
func (m *DbMap) dropTable(t reflect.Type, name string, addIfExists bool) error {
	table := tableOrNil(m, t, name)
	if table == nil {
		return fmt.Errorf("table %s was not registered", table.TableName)
	}
	return m.dropTableImpl(table, addIfExists)
}
func (m *DbMap) dropTableImpl(table *TableMap, ifExists bool) (err error) {
	tableDrop := "drop table"
	if ifExists {
		tableDrop = m.Dialect.IfTableExists(tableDrop, table.SchemaName, table.TableName)
	}
	_, err = m.Exec(fmt.Sprintf("%s %s;", tableDrop, m.Dialect.QuotedTableForQuery(table.SchemaName, table.TableName)))
	return err
}