Beispiel #1
0
func (isp *InfoSchemaPlan) fetchColumns(schemas []*model.DBInfo) {
	for _, schema := range schemas {
		for _, table := range schema.Tables {
			for i, col := range table.Columns {
				colLen := col.Flen
				if colLen == types.UnspecifiedLength {
					colLen = mysql.GetDefaultFieldLength(col.Tp)
				}
				decimal := col.Decimal
				if decimal == types.UnspecifiedLength {
					decimal = 0
				}
				columnType := col.FieldType.CompactStr()
				columnDesc := column.NewColDesc(&column.Col{ColumnInfo: *col})
				var columnDefault interface{}
				if columnDesc.DefaultValue != nil {
					columnDefault = fmt.Sprintf("%v", columnDesc.DefaultValue)
				}
				record := []interface{}{
					catalogVal,                           // TABLE_CATALOG
					schema.Name.O,                        // TABLE_SCHEMA
					table.Name.O,                         // TABLE_NAME
					col.Name.O,                           // COLUMN_NAME
					i + 1,                                // ORIGINAL_POSITION
					columnDefault,                        // COLUMN_DEFAULT
					columnDesc.Null,                      // IS_NULLABLE
					types.TypeToStr(col.Tp, col.Charset), // DATA_TYPE
					colLen,                            // CHARACTER_MAXIMUM_LENGTH
					colLen,                            // CHARACTOR_OCTET_LENGTH
					decimal,                           // NUMERIC_PRECISION
					0,                                 // NUMERIC_SCALE
					0,                                 // DATETIME_PRECISION
					col.Charset,                       // CHARACTER_SET_NAME
					col.Collate,                       // COLLATION_NAME
					columnType,                        // COLUMN_TYPE
					columnDesc.Key,                    // COLUMN_KEY
					columnDesc.Extra,                  // EXTRA
					"select,insert,update,references", // PRIVILEGES
					"", // COLUMN_COMMENT
				}
				isp.rows = append(isp.rows, &plan.Row{Data: record})
			}
		}
	}
}
Beispiel #2
0
func (d *ddl) setCharsetCollationFlenDecimal(tp *types.FieldType) {
	if len(tp.Charset) == 0 {
		switch tp.Tp {
		case mysql.TypeString, mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:
			tp.Charset, tp.Collate = getDefaultCharsetAndCollate()
		default:
			tp.Charset = charset.CharsetBin
			tp.Collate = charset.CharsetBin
		}
	}
	// If flen is not assigned, assigned it by type.
	if tp.Flen == types.UnspecifiedLength {
		tp.Flen = mysql.GetDefaultFieldLength(tp.Tp)
	}
	if tp.Decimal == types.UnspecifiedLength {
		tp.Decimal = mysql.GetDefaultDecimal(tp.Tp)
	}
}
Beispiel #3
0
// Set ResultField info according to values
// This is used for inferring calculated fields type/Flen/charset
// For example "select count(*) from t;" will return a ResultField with type TypeLonglong, charset binary and Flen 21.
func setResultFieldInfo(fields []*field.ResultField, values []interface{}) error {
	if len(fields) != len(values) {
		return errors.Errorf("Fields and Values length unmatch %d VS %d", len(fields), len(values))
	}
	for i, rf := range fields {
		if mysql.IsUninitializedType(rf.Col.Tp) {
			// 0 == TypeDecimal, Tp maybe uninitialized
			rf.Col.Charset = charset.CharsetBin
			rf.Col.Collate = charset.CharsetBin
			c := values[i]
			switch v := c.(type) {
			case int8, int16, int, int32, int64:
				rf.Col.Tp = mysql.TypeLonglong
			case uint8, uint16, uint, uint32, uint64:
				rf.Col.Tp = mysql.TypeLonglong
				rf.Col.Flag |= mysql.UnsignedFlag
			case float32, float64:
				rf.Col.Tp = mysql.TypeFloat
			case string:
				rf.Col.Tp = mysql.TypeVarchar
				rf.Col.Flen = len(v)
				rf.Col.Charset = mysql.DefaultCharset
				rf.Col.Collate = mysql.DefaultCollationName
			case []byte:
				rf.Col.Tp = mysql.TypeBlob
			case mysql.Time:
				rf.Col.Tp = v.Type
			case mysql.Duration:
				rf.Col.Tp = mysql.TypeDuration
			case mysql.Decimal:
				rf.Col.Tp = mysql.TypeDecimal
			case nil:
				rf.Col.Tp = mysql.TypeNull
			default:
				return errors.Errorf("Unknown type %T", c)
			}
			if rf.Col.Flen == 0 {
				rf.Col.Flen = mysql.GetDefaultFieldLength(rf.Col.Tp)
			}
			// TODO: set flags
		}
	}
	return nil
}
Beispiel #4
0
func dataForColumnsInTable(schema *model.DBInfo, tbl *model.TableInfo) [][]types.Datum {
	rows := [][]types.Datum{}
	for i, col := range tbl.Columns {
		colLen := col.Flen
		if colLen == types.UnspecifiedLength {
			colLen = mysql.GetDefaultFieldLength(col.Tp)
		}
		decimal := col.Decimal
		if decimal == types.UnspecifiedLength {
			decimal = 0
		}
		columnType := col.FieldType.CompactStr()
		columnDesc := table.NewColDesc(&table.Column{ColumnInfo: *col})
		var columnDefault interface{}
		if columnDesc.DefaultValue != nil {
			columnDefault = fmt.Sprintf("%v", columnDesc.DefaultValue)
		}
		record := types.MakeDatums(
			catalogVal,                           // TABLE_CATALOG
			schema.Name.O,                        // TABLE_SCHEMA
			tbl.Name.O,                           // TABLE_NAME
			col.Name.O,                           // COLUMN_NAME
			i+1,                                  // ORIGINAL_POSITION
			columnDefault,                        // COLUMN_DEFAULT
			columnDesc.Null,                      // IS_NULLABLE
			types.TypeToStr(col.Tp, col.Charset), // DATA_TYPE
			colLen,                            // CHARACTER_MAXIMUM_LENGTH
			colLen,                            // CHARACTOR_OCTET_LENGTH
			decimal,                           // NUMERIC_PRECISION
			0,                                 // NUMERIC_SCALE
			0,                                 // DATETIME_PRECISION
			col.Charset,                       // CHARACTER_SET_NAME
			col.Collate,                       // COLLATION_NAME
			columnType,                        // COLUMN_TYPE
			columnDesc.Key,                    // COLUMN_KEY
			columnDesc.Extra,                  // EXTRA
			"select,insert,update,references", // PRIVILEGES
			"", // COLUMN_COMMENT
		)
		rows = append(rows, record)
	}
	return rows
}
Beispiel #5
0
// columnDefToCol converts ColumnDef to Col and TableConstraints.
func columnDefToCol(ctx context.Context, offset int, colDef *ast.ColumnDef) (*table.Column, []*ast.Constraint, error) {
	constraints := []*ast.Constraint{}
	col := &table.Column{
		ColumnInfo: model.ColumnInfo{
			Offset:    offset,
			Name:      colDef.Name.Name,
			FieldType: *colDef.Tp,
		},
	}

	// Check and set TimestampFlag and OnUpdateNowFlag.
	if col.Tp == mysql.TypeTimestamp {
		col.Flag |= mysql.TimestampFlag
		col.Flag |= mysql.OnUpdateNowFlag
		col.Flag |= mysql.NotNullFlag
	}

	// If flen is not assigned, assigned it by type.
	if col.Flen == types.UnspecifiedLength {
		col.Flen = mysql.GetDefaultFieldLength(col.Tp)
	}
	if col.Decimal == types.UnspecifiedLength {
		col.Decimal = mysql.GetDefaultDecimal(col.Tp)
	}

	setOnUpdateNow := false
	hasDefaultValue := false
	if colDef.Options != nil {
		keys := []*ast.IndexColName{
			{
				Column: colDef.Name,
				Length: colDef.Tp.Flen,
			},
		}
		for _, v := range colDef.Options {
			switch v.Tp {
			case ast.ColumnOptionNotNull:
				col.Flag |= mysql.NotNullFlag
			case ast.ColumnOptionNull:
				col.Flag &= ^uint(mysql.NotNullFlag)
				removeOnUpdateNowFlag(col)
			case ast.ColumnOptionAutoIncrement:
				col.Flag |= mysql.AutoIncrementFlag
			case ast.ColumnOptionPrimaryKey:
				constraint := &ast.Constraint{Tp: ast.ConstraintPrimaryKey, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.PriKeyFlag
			case ast.ColumnOptionUniq:
				constraint := &ast.Constraint{Tp: ast.ConstraintUniq, Name: colDef.Name.Name.O, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ast.ColumnOptionIndex:
				constraint := &ast.Constraint{Tp: ast.ConstraintIndex, Name: colDef.Name.Name.O, Keys: keys}
				constraints = append(constraints, constraint)
			case ast.ColumnOptionUniqIndex:
				constraint := &ast.Constraint{Tp: ast.ConstraintUniqIndex, Name: colDef.Name.Name.O, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ast.ColumnOptionKey:
				constraint := &ast.Constraint{Tp: ast.ConstraintKey, Name: colDef.Name.Name.O, Keys: keys}
				constraints = append(constraints, constraint)
			case ast.ColumnOptionUniqKey:
				constraint := &ast.Constraint{Tp: ast.ConstraintUniqKey, Name: colDef.Name.Name.O, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ast.ColumnOptionDefaultValue:
				value, err := getDefaultValue(ctx, v, colDef.Tp.Tp, colDef.Tp.Decimal)
				if err != nil {
					return nil, nil, ErrColumnBadNull.Gen("invalid default value - %s", err)
				}
				col.DefaultValue = value
				hasDefaultValue = true
				removeOnUpdateNowFlag(col)
			case ast.ColumnOptionOnUpdate:
				if !evaluator.IsCurrentTimeExpr(v.Expr) {
					return nil, nil, ErrInvalidOnUpdate.Gen("invalid ON UPDATE for - %s", col.Name)
				}

				col.Flag |= mysql.OnUpdateNowFlag
				setOnUpdateNow = true
			case ast.ColumnOptionComment:
				value, err := evaluator.Eval(ctx, v.Expr)
				if err != nil {
					return nil, nil, errors.Trace(err)
				}
				col.Comment, err = value.ToString()
				if err != nil {
					return nil, nil, errors.Trace(err)
				}
			case ast.ColumnOptionFulltext:
				// Do nothing.
			}
		}
	}

	setTimestampDefaultValue(col, hasDefaultValue, setOnUpdateNow)

	// Set `NoDefaultValueFlag` if this field doesn't have a default value and
	// it is `not null` and not an `AUTO_INCREMENT` field or `TIMESTAMP` field.
	setNoDefaultValueFlag(col, hasDefaultValue)

	err := checkDefaultValue(col, hasDefaultValue)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	if col.Charset == charset.CharsetBin {
		col.Flag |= mysql.BinaryFlag
	}
	return col, constraints, nil
}
Beispiel #6
0
// ColumnDefToCol converts ColumnDef to Col and TableConstraints.
func ColumnDefToCol(offset int, colDef *ColumnDef) (*column.Col, []*TableConstraint, error) {
	constraints := []*TableConstraint{}
	col := &column.Col{
		ColumnInfo: model.ColumnInfo{
			Offset:    offset,
			Name:      model.NewCIStr(colDef.Name),
			FieldType: *colDef.Tp,
		},
	}

	// Check and set TimestampFlag and OnUpdateNowFlag.
	if col.Tp == mysql.TypeTimestamp {
		col.Flag |= mysql.TimestampFlag
		col.Flag |= mysql.OnUpdateNowFlag
		col.Flag |= mysql.NotNullFlag
	}

	// If flen is not assigned, assigned it by type.
	if col.Flen == types.UnspecifiedLength {
		col.Flen = mysql.GetDefaultFieldLength(col.Tp)
	}
	if col.Decimal == types.UnspecifiedLength {
		col.Decimal = mysql.GetDefaultDecimal(col.Tp)
	}

	setOnUpdateNow := false
	hasDefaultValue := false
	if colDef.Constraints != nil {
		keys := []*IndexColName{
			{
				colDef.Name,
				colDef.Tp.Flen,
			},
		}
		for _, v := range colDef.Constraints {
			switch v.Tp {
			case ConstrNotNull:
				col.Flag |= mysql.NotNullFlag
			case ConstrNull:
				col.Flag &= ^uint(mysql.NotNullFlag)
				removeOnUpdateNowFlag(col)
			case ConstrAutoIncrement:
				col.Flag |= mysql.AutoIncrementFlag
			case ConstrPrimaryKey:
				constraint := &TableConstraint{Tp: ConstrPrimaryKey, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.PriKeyFlag
			case ConstrUniq:
				constraint := &TableConstraint{Tp: ConstrUniq, ConstrName: colDef.Name, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ConstrIndex:
				constraint := &TableConstraint{Tp: ConstrIndex, ConstrName: colDef.Name, Keys: keys}
				constraints = append(constraints, constraint)
			case ConstrUniqIndex:
				constraint := &TableConstraint{Tp: ConstrUniqIndex, ConstrName: colDef.Name, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ConstrKey:
				constraint := &TableConstraint{Tp: ConstrKey, ConstrName: colDef.Name, Keys: keys}
				constraints = append(constraints, constraint)
			case ConstrUniqKey:
				constraint := &TableConstraint{Tp: ConstrUniqKey, ConstrName: colDef.Name, Keys: keys}
				constraints = append(constraints, constraint)
				col.Flag |= mysql.UniqueKeyFlag
			case ConstrDefaultValue:
				value, err := getDefaultValue(v, colDef.Tp.Tp, colDef.Tp.Decimal)
				if err != nil {
					return nil, nil, errors.Errorf("invalid default value - %s", errors.Trace(err))
				}
				col.DefaultValue = value
				hasDefaultValue = true
				removeOnUpdateNowFlag(col)
			case ConstrOnUpdate:
				if !expression.IsCurrentTimeExpr(v.Evalue) {
					return nil, nil, errors.Errorf("invalid ON UPDATE for - %s", col.Name)
				}

				col.Flag |= mysql.OnUpdateNowFlag
				setOnUpdateNow = true
			case ConstrFulltext:
				// Do nothing.
			case ConstrComment:
				// Do nothing.
			}
		}
	}

	setTimestampDefaultValue(col, hasDefaultValue, setOnUpdateNow)

	// Set `NoDefaultValueFlag` if this field doesn't have a default value and
	// it is `not null` and not an `AUTO_INCREMENT` field or `TIMESTAMP` field.
	setNoDefaultValueFlag(col, hasDefaultValue)

	err := checkDefaultValue(col, hasDefaultValue)
	if err != nil {
		return nil, nil, errors.Trace(err)
	}
	if col.Charset == charset.CharsetBin {
		col.Flag |= mysql.BinaryFlag
	}
	return col, constraints, nil
}