// GetColDefaultValue gets default value of the column. func GetColDefaultValue(ctx context.Context, col *model.ColumnInfo) (interface{}, bool, error) { // Check no default value flag. if mysql.HasNoDefaultValueFlag(col.Flag) && col.Tp != mysql.TypeEnum { return nil, false, errors.Errorf("Field '%s' doesn't have a default value", col.Name) } // Check and get timestamp/datetime default value. if col.Tp == mysql.TypeTimestamp || col.Tp == mysql.TypeDatetime { if col.DefaultValue == nil { return nil, true, nil } value, err := expression.GetTimeValue(ctx, col.DefaultValue, col.Tp, col.Decimal) if err != nil { return nil, true, errors.Errorf("Field '%s' get default value fail - %s", col.Name, errors.Trace(err)) } return value, true, nil } else if col.Tp == mysql.TypeEnum { // For enum type, if no default value and not null is set, // the default value is the first element of the enum list if col.DefaultValue == nil && mysql.HasNotNullFlag(col.Flag) { return col.FieldType.Elems[0], true, nil } } return col.DefaultValue, true, nil }
// handleRowData deals with raw row data: // 1. Decodes row from raw byte slice. // 2. Checks if it fit where condition. // 3. Update aggregate functions. // returns true if got a row. func (rs *localRegion) handleRowData(ctx *selectContext, handle int64, value []byte) (bool, error) { columns := ctx.sel.TableInfo.Columns values, err := rs.getRowData(value, ctx.colTps) if err != nil { return false, errors.Trace(err) } // Fill handle and null columns. for _, col := range columns { if col.GetPkHandle() { var handleDatum types.Datum if mysql.HasUnsignedFlag(uint(col.Flag)) { // PK column is Unsigned handleDatum = types.NewUintDatum(uint64(handle)) } else { handleDatum = types.NewIntDatum(handle) } handleData, err1 := codec.EncodeValue(nil, handleDatum) if err1 != nil { return false, errors.Trace(err1) } values[col.GetColumnId()] = handleData } else { _, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return false, errors.New("Miss column") } values[col.GetColumnId()] = []byte{codec.NilFlag} } } } return rs.valuesToRow(ctx, handle, values) }
func rowWithCols(txn kv.Retriever, t table.Table, h int64, cols []*table.Column) ([]types.Datum, error) { v := make([]types.Datum, len(cols)) for i, col := range cols { if col.State != model.StatePublic { return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.Meta()) { v[i].SetInt64(h) continue } k := t.RecordKey(h, col) data, err := txn.Get(k) if terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(col.Flag) { continue } else if err != nil { return nil, errors.Trace(err) } val, err := tables.DecodeValue(data, &col.FieldType) if err != nil { return nil, errors.Trace(err) } v[i] = val } return v, nil }
func (isp *InfoSchemaPlan) fetchStatisticsInTable(is infoschema.InfoSchema, schema *model.DBInfo, table *model.TableInfo) { if table.PKIsHandle { for _, col := range table.Columns { if mysql.HasPriKeyFlag(col.Flag) { record := []interface{}{ catalogVal, // TABLE_CATALOG schema.Name.O, // TABLE_SCHEMA table.Name.O, // TABLE_NAME "0", // NON_UNIQUE schema.Name.O, // INDEX_SCHEMA "PRIMARY", // INDEX_NAME 1, // SEQ_IN_INDEX col.Name.O, // COLUMN_NAME "A", // COLLATION 0, // CARDINALITY nil, // SUB_PART nil, // PACKED "", // NULLABLE "BTREE", // INDEX_TYPE "", // COMMENT "", // INDEX_COMMENT } isp.rows = append(isp.rows, &plan.Row{Data: record}) } } } for _, index := range table.Indices { nonUnique := "1" if index.Unique { nonUnique = "0" } for i, key := range index.Columns { col, _ := is.ColumnByName(schema.Name, table.Name, key.Name) nullable := "YES" if mysql.HasNotNullFlag(col.Flag) { nullable = "" } record := []interface{}{ catalogVal, // TABLE_CATALOG schema.Name.O, // TABLE_SCHEMA table.Name.O, // TABLE_NAME nonUnique, // NON_UNIQUE schema.Name.O, // INDEX_SCHEMA index.Name.O, // INDEX_NAME i + 1, // SEQ_IN_INDEX key.Name.O, // COLUMN_NAME "A", // COLLATION 0, // CARDINALITY nil, // SUB_PART nil, // PACKED nullable, // NULLABLE "BTREE", // INDEX_TYPE "", // COMMENT "", // INDEX_COMMENT } isp.rows = append(isp.rows, &plan.Row{Data: record}) } } }
// String implements fmt.Stringer interface. func (c *Column) String() string { ans := []string{c.Name.O, types.TypeToStr(c.Tp, c.Charset)} if mysql.HasAutoIncrementFlag(c.Flag) { ans = append(ans, "AUTO_INCREMENT") } if mysql.HasNotNullFlag(c.Flag) { ans = append(ans, "NOT NULL") } return strings.Join(ans, " ") }
// RowWithCols implements table.Table RowWithCols interface. func (t *Table) RowWithCols(ctx context.Context, h int64, cols []*table.Column) ([]types.Datum, error) { txn, err := ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } // Get raw row data from kv. key := t.RecordKey(h) value, err := txn.Get(key) if err != nil { return nil, errors.Trace(err) } // Decode raw row data. v := make([]types.Datum, len(cols)) colTps := make(map[int64]*types.FieldType, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } colTps[col.ID] = &col.FieldType } row, err := tablecodec.DecodeRow(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { // TODO: check this return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { continue } ri, ok := row[col.ID] if !ok && mysql.HasNotNullFlag(col.Flag) { return nil, errors.New("Miss column") } v[i] = ri } return v, nil }
func setTimestampDefaultValue(c *table.Column, hasDefaultValue bool, setOnUpdateNow bool) { if hasDefaultValue { return } // For timestamp Col, if is not set default value or not set null, use current timestamp. if mysql.HasTimestampFlag(c.Flag) && mysql.HasNotNullFlag(c.Flag) { if setOnUpdateNow { c.DefaultValue = evaluator.ZeroTimestamp } else { c.DefaultValue = evaluator.CurrentTimestamp } } }
func setNoDefaultValueFlag(c *table.Column, hasDefaultValue bool) { if hasDefaultValue { return } if !mysql.HasNotNullFlag(c.Flag) { return } // Check if it is an `AUTO_INCREMENT` field or `TIMESTAMP` field. if !mysql.HasAutoIncrementFlag(c.Flag) && !mysql.HasTimestampFlag(c.Flag) { c.Flag |= mysql.NoDefaultValueFlag } }
func (h *rpcHandler) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) { tid := ctx.sel.TableInfo.GetTableId() columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } for _, col := range columns { if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(col.GetFlag())) { row.Data, err = codec.EncodeValue(row.Data, types.NewUintDatum(uint64(handle))) if err != nil { return nil, errors.Trace(err) } } else { row.Data = append(row.Data, row.Handle...) } } else { colID := col.GetColumnId() if ctx.whereColumns[colID] != nil { // The column is saved in evaluator, use it directly. datum := ctx.eval.Row[colID] row.Data, err = codec.EncodeValue(row.Data, datum) if err != nil { return nil, errors.Trace(err) } } else { key := tablecodec.EncodeColumnKey(tid, handle, colID) data, err1 := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err1 != nil { return nil, errors.Trace(err1) } if data == nil { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.Trace(kv.ErrNotExist) } row.Data = append(row.Data, codec.NilFlag) } else { row.Data = append(row.Data, data...) } } } } return row, nil }
func rowWithCols(txn kv.Retriever, t table.Table, h int64, cols []*table.Column) ([]types.Datum, error) { key := t.RecordKey(h) value, err := txn.Get(key) if err != nil { return nil, errors.Trace(err) } v := make([]types.Datum, len(cols)) colTps := make(map[int64]*types.FieldType, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.Meta()) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } colTps[col.ID] = &col.FieldType } row, err := tablecodec.DecodeRow(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { // TODO: check this return nil, errInvalidColumnState.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.Meta()) { continue } ri, ok := row[col.ID] if !ok && mysql.HasNotNullFlag(col.Flag) { return nil, errors.New("Miss") } v[i] = ri } return v, nil }
func checkDefaultValue(c *column.Col, hasDefaultValue bool) error { if !hasDefaultValue { return nil } if c.DefaultValue != nil { return nil } // Set not null but default null is invalid. if mysql.HasNotNullFlag(c.Flag) { return errors.Errorf("invalid default value for %s", c.Name) } return nil }
func checkDefaultValue(c *table.Column, hasDefaultValue bool) error { if !hasDefaultValue { return nil } if c.DefaultValue != nil { return nil } // Set not null but default null is invalid. if mysql.HasNotNullFlag(c.Flag) { return ErrColumnBadNull.Gen("invalid default value for %s", c.Name) } return nil }
func (h *rpcHandler) evalWhereForRow(ctx *selectContext, handle int64) (bool, error) { if ctx.sel.Where == nil { return true, nil } tid := ctx.sel.TableInfo.GetTableId() for colID, col := range ctx.whereColumns { if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(col.GetFlag())) { ctx.eval.Row[colID] = types.NewUintDatum(uint64(handle)) } else { ctx.eval.Row[colID] = types.NewIntDatum(handle) } } else { key := tablecodec.EncodeColumnKey(tid, handle, colID) data, err := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err != nil { return false, errors.Trace(err) } if data == nil { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return false, errors.Trace(kv.ErrNotExist) } ctx.eval.Row[colID] = types.Datum{} } else { var d types.Datum d, err = tablecodec.DecodeColumnValue(data, col) if err != nil { return false, errors.Trace(err) } ctx.eval.Row[colID] = d } } } result, err := ctx.eval.Eval(ctx.sel.Where) if err != nil { return false, errors.Trace(err) } if result.IsNull() { return false, nil } boolResult, err := result.ToBool() if err != nil { return false, errors.Trace(err) } return boolResult == 1, nil }
// getColDefaultValue gets default value of the column. func getColDefaultValue(col *model.ColumnInfo) (interface{}, bool, error) { // Check no default value flag. if mysql.HasNoDefaultValueFlag(col.Flag) && col.Tp != mysql.TypeEnum { return nil, false, errors.Errorf("Field '%s' doesn't have a default value", col.Name) } // Check and get timestamp/datetime default value. if col.Tp == mysql.TypeEnum { // For enum type, if no default value and not null is set, // the default value is the first element of the enum list if col.DefaultValue == nil && mysql.HasNotNullFlag(col.Flag) { return col.FieldType.Elems[0], true, nil } } return col.DefaultValue, true, nil }
func (d *ddl) backfillColumn(ctx context.Context, t table.Table, columnInfo *model.ColumnInfo, handles []int64, reorgInfo *reorgInfo) error { var defaultVal types.Datum var err error if columnInfo.DefaultValue != nil { defaultVal, _, err = table.GetColDefaultValue(ctx, columnInfo) if err != nil { return errors.Trace(err) } } else if mysql.HasNotNullFlag(columnInfo.Flag) { defaultVal = table.GetZeroValue(columnInfo) } colMap := make(map[int64]*types.FieldType) for _, col := range t.Meta().Columns { colMap[col.ID] = &col.FieldType } var endIdx int for len(handles) > 0 { if len(handles) >= defaultSmallBatchCnt { endIdx = defaultSmallBatchCnt } else { endIdx = len(handles) } err = kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { if err := d.isReorgRunnable(txn, ddlJobFlag); err != nil { return errors.Trace(err) } nextHandle, err1 := d.backfillColumnInTxn(t, columnInfo.ID, handles[:endIdx], colMap, defaultVal, txn) if err1 != nil { return errors.Trace(err1) } return errors.Trace(reorgInfo.UpdateHandle(txn, nextHandle)) }) if err != nil { return errors.Trace(err) } handles = handles[endIdx:] } return nil }
// NewColDesc returns a new ColDesc for a column. func NewColDesc(col *Column) *ColDesc { // TODO: if we have no primary key and a unique index which's columns are all not null // we will set these columns' flag as PriKeyFlag // see https://dev.mysql.com/doc/refman/5.7/en/show-columns.html // create table name := col.Name nullFlag := "YES" if mysql.HasNotNullFlag(col.Flag) { nullFlag = "NO" } keyFlag := "" if mysql.HasPriKeyFlag(col.Flag) { keyFlag = "PRI" } else if mysql.HasUniKeyFlag(col.Flag) { keyFlag = "UNI" } else if mysql.HasMultipleKeyFlag(col.Flag) { keyFlag = "MUL" } var defaultValue interface{} if !mysql.HasNoDefaultValueFlag(col.Flag) { defaultValue = col.DefaultValue } extra := "" if mysql.HasAutoIncrementFlag(col.Flag) { extra = "auto_increment" } else if mysql.HasOnUpdateNowFlag(col.Flag) { extra = "on update CURRENT_TIMESTAMP" } return &ColDesc{ Field: name.O, Type: col.GetTypeDesc(), Collation: col.Collate, Null: nullFlag, Key: keyFlag, DefaultValue: defaultValue, Extra: extra, Privileges: defaultPrivileges, Comment: "", } }
// GetColDefaultValue gets default value of the column. func GetColDefaultValue(ctx context.Context, col *model.ColumnInfo) (types.Datum, bool, error) { // Check no default value flag. if mysql.HasNoDefaultValueFlag(col.Flag) && col.Tp != mysql.TypeEnum { err := errNoDefaultValue.Gen("Field '%s' doesn't have a default value", col.Name) if ctx != nil { sessVars := variable.GetSessionVars(ctx) if !sessVars.StrictSQLMode { // TODO: add warning. return GetZeroValue(col), true, nil } } return types.Datum{}, false, errors.Trace(err) } // Check and get timestamp/datetime default value. if col.Tp == mysql.TypeTimestamp || col.Tp == mysql.TypeDatetime { if col.DefaultValue == nil { return types.Datum{}, true, nil } value, err := evaluator.GetTimeValue(ctx, col.DefaultValue, col.Tp, col.Decimal) if err != nil { return types.Datum{}, true, errGetDefaultFailed.Gen("Field '%s' get default value fail - %s", col.Name, errors.Trace(err)) } return value, true, nil } else if col.Tp == mysql.TypeEnum { // For enum type, if no default value and not null is set, // the default value is the first element of the enum list if col.DefaultValue == nil && mysql.HasNotNullFlag(col.Flag) { return types.NewDatum(col.FieldType.Elems[0]), true, nil } } value, err := CastValue(ctx, types.NewDatum(col.DefaultValue), col) if err != nil { return types.Datum{}, false, errors.Trace(err) } return value, true, nil }
// RowWithCols implements table.Table RowWithCols interface. func (t *Table) RowWithCols(ctx context.Context, h int64, cols []*table.Column) ([]types.Datum, error) { txn, err := ctx.GetTxn(false) if err != nil { return nil, errors.Trace(err) } v := make([]types.Datum, len(cols)) for i, col := range cols { if col == nil { continue } if col.State != model.StatePublic { return nil, table.ErrColumnStateNonPublic.Gen("Cannot use none public column - %v", cols) } if col.IsPKHandleColumn(t.meta) { if mysql.HasUnsignedFlag(col.Flag) { v[i].SetUint64(uint64(h)) } else { v[i].SetInt64(h) } continue } k := t.RecordKey(h, col) data, err := txn.Get(k) if terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(col.Flag) { continue } else if err != nil { return nil, errors.Trace(err) } v[i], err = DecodeValue(data, &col.FieldType) if err != nil { return nil, errors.Trace(err) } } return v, nil }
func fetchRowColVals(txn kv.Transaction, t table.Table, handle int64, indexInfo *model.IndexInfo) ([]types.Datum, error) { // fetch datas cols := t.Cols() vals := make([]types.Datum, 0, len(indexInfo.Columns)) for _, v := range indexInfo.Columns { col := cols[v.Offset] k := t.RecordKey(handle, col) data, err := txn.Get(k) if err != nil { if terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(col.Flag) { vals = append(vals, types.Datum{}) continue } return nil, errors.Trace(err) } val, err := tables.DecodeValue(data, &col.FieldType) if err != nil { return nil, errors.Trace(err) } vals = append(vals, val) } return vals, nil }
func dataForStatisticsInTable(schema *model.DBInfo, table *model.TableInfo) [][]types.Datum { rows := [][]types.Datum{} if table.PKIsHandle { for _, col := range table.Columns { if mysql.HasPriKeyFlag(col.Flag) { record := types.MakeDatums( catalogVal, // TABLE_CATALOG schema.Name.O, // TABLE_SCHEMA table.Name.O, // TABLE_NAME "0", // NON_UNIQUE schema.Name.O, // INDEX_SCHEMA "PRIMARY", // INDEX_NAME 1, // SEQ_IN_INDEX col.Name.O, // COLUMN_NAME "A", // COLLATION 0, // CARDINALITY nil, // SUB_PART nil, // PACKED "", // NULLABLE "BTREE", // INDEX_TYPE "", // COMMENT "", // INDEX_COMMENT ) rows = append(rows, record) } } } nameToCol := make(map[string]*model.ColumnInfo, len(table.Columns)) for _, c := range table.Columns { nameToCol[c.Name.L] = c } for _, index := range table.Indices { nonUnique := "1" if index.Unique { nonUnique = "0" } for i, key := range index.Columns { col := nameToCol[key.Name.L] nullable := "YES" if mysql.HasNotNullFlag(col.Flag) { nullable = "" } record := types.MakeDatums( catalogVal, // TABLE_CATALOG schema.Name.O, // TABLE_SCHEMA table.Name.O, // TABLE_NAME nonUnique, // NON_UNIQUE schema.Name.O, // INDEX_SCHEMA index.Name.O, // INDEX_NAME i+1, // SEQ_IN_INDEX key.Name.O, // COLUMN_NAME "A", // COLLATION 0, // CARDINALITY nil, // SUB_PART nil, // PACKED nullable, // NULLABLE "BTREE", // INDEX_TYPE "", // COMMENT "", // INDEX_COMMENT ) rows = append(rows, record) } } return rows }
// CheckNotNull checks if nil value set to a column with NotNull flag is set. func (c *Col) CheckNotNull(data types.Datum) error { if mysql.HasNotNullFlag(c.Flag) && data.Kind() == types.KindNull { return errors.Errorf("Column %s can't be null.", c.Name) } return nil }
func (h *rpcHandler) getRowByHandle(ctx *selectContext, handle int64) (*tipb.Row, error) { tid := ctx.sel.TableInfo.GetTableId() columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } rowData := make([][]byte, len(columns)) colTps := make(map[int64]*types.FieldType, len(columns)) for i, col := range columns { var colVal []byte if col.GetPkHandle() { if mysql.HasUnsignedFlag(uint(*col.Flag)) { // PK column is Unsigned var ud types.Datum ud.SetUint64(uint64(handle)) var err1 error colVal, err1 = codec.EncodeValue(nil, ud) if err1 != nil { return nil, errors.Trace(err1) } } else { colVal = row.Handle } rowData[i] = colVal } else { colTps[col.GetColumnId()] = xapi.FieldTypeFromPBColumn(col) } } key := tablecodec.EncodeRowKeyWithHandle(tid, handle) value, err := h.mvccStore.Get(key, ctx.sel.GetStartTs()) if err != nil { return nil, errors.Trace(err) } values, err := h.getRowData(value, colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range columns { if col.GetPkHandle() { continue } v, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.New("Miss column") } v = []byte{codec.NilFlag} values[col.GetColumnId()] = v } rowData[i] = v } // Evalue where match, err := h.evalWhereForRow(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } if !match { return nil, nil } for _, d := range rowData { row.Data = append(row.Data, d...) } return row, nil }
// handleRowData deals with raw row data: // 1. Decodes row from raw byte slice. // 2. Checks if it fit where condition. // 3. Update aggregate functions. func (rs *localRegion) handleRowData(ctx *selectContext, handle int64, value []byte) (*tipb.Row, error) { columns := ctx.sel.TableInfo.Columns row := new(tipb.Row) var d types.Datum d.SetInt64(handle) var err error row.Handle, err = codec.EncodeValue(nil, d) if err != nil { return nil, errors.Trace(err) } rowData := make([][]byte, len(columns)) values, err := rs.getRowData(value, ctx.colTps) if err != nil { return nil, errors.Trace(err) } for i, col := range columns { if *col.PkHandle { var colVal []byte if mysql.HasUnsignedFlag(uint(*col.Flag)) { // PK column is Unsigned var ud types.Datum ud.SetUint64(uint64(handle)) var err1 error colVal, err1 = codec.EncodeValue(nil, ud) if err1 != nil { return nil, errors.Trace(err1) } } else { colVal = row.Handle } rowData[i] = colVal continue } v, ok := values[col.GetColumnId()] if !ok { if mysql.HasNotNullFlag(uint(col.GetFlag())) { return nil, errors.New("Miss column") } v = []byte{codec.NilFlag} values[col.GetColumnId()] = v } rowData[i] = v } // Evalue where match, err := rs.evalWhereForRow(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } if !match { return nil, nil } if ctx.aggregate { // Update aggregate functions. err = rs.aggregate(ctx, handle, values) if err != nil { return nil, errors.Trace(err) } } else { // If without aggregate functions, just return raw row data. for _, d := range rowData { row.Data = append(row.Data, d...) } } return row, nil }
func (d *ddl) backfillColumnData(t table.Table, columnInfo *model.ColumnInfo, handles []int64, reorgInfo *reorgInfo) error { var ( defaultVal types.Datum err error ) if columnInfo.DefaultValue != nil { defaultVal, _, err = table.GetColDefaultValue(nil, columnInfo) if err != nil { return errors.Trace(err) } } else if mysql.HasNotNullFlag(columnInfo.Flag) { defaultVal = table.GetZeroValue(columnInfo) } colMap := make(map[int64]*types.FieldType) for _, col := range t.Meta().Columns { colMap[col.ID] = &col.FieldType } for _, handle := range handles { log.Info("[ddl] backfill column...", handle) err := kv.RunInNewTxn(d.store, true, func(txn kv.Transaction) error { if err := d.isReorgRunnable(txn); err != nil { return errors.Trace(err) } rowKey := t.RecordKey(handle) rowVal, err := txn.Get(rowKey) if terror.ErrorEqual(err, kv.ErrNotExist) { // If row doesn't exist, skip it. return nil } if err != nil { return errors.Trace(err) } rowColumns, err := tablecodec.DecodeRow(rowVal, colMap) if err != nil { return errors.Trace(err) } if _, ok := rowColumns[columnInfo.ID]; ok { // The column is already added by update or insert statement, skip it. return nil } newColumnIDs := make([]int64, 0, len(rowColumns)+1) newRow := make([]types.Datum, 0, len(rowColumns)+1) for colID, val := range rowColumns { newColumnIDs = append(newColumnIDs, colID) newRow = append(newRow, val) } newColumnIDs = append(newColumnIDs, columnInfo.ID) newRow = append(newRow, defaultVal) newRowVal, err := tablecodec.EncodeRow(newRow, newColumnIDs) if err != nil { return errors.Trace(err) } err = txn.Set(rowKey, newRowVal) if err != nil { return errors.Trace(err) } return errors.Trace(reorgInfo.UpdateHandle(txn, handle)) }) if err != nil { return errors.Trace(err) } } return nil }
// CheckNotNull checks if nil value set to a column with NotNull flag is set. func (c *Column) CheckNotNull(data types.Datum) error { if mysql.HasNotNullFlag(c.Flag) && data.IsNull() { return errColumnCantNull.Gen("Column %s can't be null.", c.Name) } return nil }
// CheckNotNull checks if nil value set to a column with NotNull flag is set. func (c *Col) CheckNotNull(data interface{}) error { if mysql.HasNotNullFlag(c.Flag) && data == nil { return errors.Errorf("Column %s can't be null.", c.Name) } return nil }
func (s *ShowPlan) fetchShowCreateTable(ctx context.Context) error { tb, err := s.getTable(ctx) if err != nil { return errors.Trace(err) } // TODO: let the result more like MySQL. var buf bytes.Buffer buf.WriteString(fmt.Sprintf("CREATE TABLE `%s` (\n", tb.TableName().O)) for i, col := range tb.Cols() { buf.WriteString(fmt.Sprintf(" `%s` %s", col.Name.O, col.GetTypeDesc())) if mysql.HasAutoIncrementFlag(col.Flag) { buf.WriteString(" NOT NULL AUTO_INCREMENT") } else { if mysql.HasNotNullFlag(col.Flag) { buf.WriteString(" NOT NULL") } switch col.DefaultValue { case nil: buf.WriteString(" DEFAULT NULL") case "CURRENT_TIMESTAMP": buf.WriteString(" DEFAULT CURRENT_TIMESTAMP") default: buf.WriteString(fmt.Sprintf(" DEFAULT '%v'", col.DefaultValue)) } if mysql.HasOnUpdateNowFlag(col.Flag) { buf.WriteString(" ON UPDATE CURRENT_TIMESTAMP") } } if i != len(tb.Cols())-1 { buf.WriteString(",\n") } } if len(tb.Indices()) > 0 { buf.WriteString(",\n") } for i, idx := range tb.Indices() { if idx.Primary { buf.WriteString(" PRIMARY KEY ") } else if idx.Unique { buf.WriteString(fmt.Sprintf(" UNIQUE KEY `%s` ", idx.Name.O)) } else { buf.WriteString(fmt.Sprintf(" KEY `%s` ", idx.Name.O)) } cols := make([]string, 0, len(idx.Columns)) for _, c := range idx.Columns { cols = append(cols, c.Name.O) } buf.WriteString(fmt.Sprintf("(`%s`)", strings.Join(cols, "`,`"))) if i != len(tb.Indices())-1 { buf.WriteString(",\n") } } buf.WriteString("\n") buf.WriteString(") ENGINE=InnoDB") if s := tb.Meta().Charset; len(s) > 0 { buf.WriteString(fmt.Sprintf(" DEFAULT CHARSET=%s", s)) } else { buf.WriteString(" DEFAULT CHARSET=latin1") } data := []interface{}{ tb.TableName().O, buf.String(), } s.rows = append(s.rows, &plan.Row{Data: data}) return nil }
func (d *ddl) onAddColumn(t *meta.Meta, job *model.Job) error { schemaID := job.SchemaID tblInfo, err := d.getTableInfo(t, job) if err != nil { return errors.Trace(err) } col := &model.ColumnInfo{} pos := &ast.ColumnPosition{} offset := 0 err = job.DecodeArgs(col, pos, &offset) if err != nil { job.State = model.JobCancelled return errors.Trace(err) } columnInfo := findCol(tblInfo.Columns, col.Name.L) if columnInfo != nil { if columnInfo.State == model.StatePublic { // we already have a column with same column name job.State = model.JobCancelled return infoschema.ErrColumnExists.Gen("ADD COLUMN: column already exist %s", col.Name.L) } } else { columnInfo, offset, err = d.addColumn(tblInfo, col, pos) if err != nil { job.State = model.JobCancelled return errors.Trace(err) } // Set offset arg to job. if offset != 0 { job.Args = []interface{}{columnInfo, pos, offset} } } _, err = t.GenSchemaVersion() if err != nil { return errors.Trace(err) } switch columnInfo.State { case model.StateNone: // none -> delete only job.SchemaState = model.StateDeleteOnly columnInfo.State = model.StateDeleteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateDeleteOnly: // delete only -> write only job.SchemaState = model.StateWriteOnly columnInfo.State = model.StateWriteOnly err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateWriteOnly: // write only -> reorganization job.SchemaState = model.StateWriteReorganization columnInfo.State = model.StateWriteReorganization // initialize SnapshotVer to 0 for later reorganization check. job.SnapshotVer = 0 err = t.UpdateTable(schemaID, tblInfo) return errors.Trace(err) case model.StateWriteReorganization: // reorganization -> public // get the current version for reorganization if we don't have reorgInfo, err := d.getReorgInfo(t, job) if err != nil || reorgInfo.first { // if we run reorg firstly, we should update the job snapshot version // and then run the reorg next time. return errors.Trace(err) } tbl, err := d.getTable(schemaID, tblInfo) if err != nil { return errors.Trace(err) } if columnInfo.DefaultValue != nil || mysql.HasNotNullFlag(columnInfo.Flag) { err = d.runReorgJob(func() error { return d.backfillColumn(tbl, columnInfo, reorgInfo) }) if terror.ErrorEqual(err, errWaitReorgTimeout) { // if timeout, we should return, check for the owner and re-wait job done. return nil } if err != nil { return errors.Trace(err) } } // Adjust column offset. d.adjustColumnOffset(tblInfo.Columns, tblInfo.Indices, offset, true) columnInfo.State = model.StatePublic if err = t.UpdateTable(schemaID, tblInfo); err != nil { return errors.Trace(err) } // finish this job job.SchemaState = model.StatePublic job.State = model.JobDone return nil default: return ErrInvalidColumnState.Gen("invalid column state %v", columnInfo.State) } }
func isDefaultNull(err error, col *tipb.ColumnInfo) bool { return terror.ErrorEqual(err, kv.ErrNotExist) && !mysql.HasNotNullFlag(uint(col.GetFlag())) }
func (e *ShowExec) fetchShowCreateTable() error { tb, err := e.getTable() if err != nil { return errors.Trace(err) } // TODO: let the result more like MySQL. var buf bytes.Buffer buf.WriteString(fmt.Sprintf("CREATE TABLE `%s` (\n", tb.Meta().Name.O)) var pkCol *table.Column for i, col := range tb.Cols() { buf.WriteString(fmt.Sprintf(" `%s` %s", col.Name.O, col.GetTypeDesc())) if mysql.HasAutoIncrementFlag(col.Flag) { buf.WriteString(" NOT NULL AUTO_INCREMENT") } else { if mysql.HasNotNullFlag(col.Flag) { buf.WriteString(" NOT NULL") } if !mysql.HasNoDefaultValueFlag(col.Flag) { switch col.DefaultValue { case nil: buf.WriteString(" DEFAULT NULL") case "CURRENT_TIMESTAMP": buf.WriteString(" DEFAULT CURRENT_TIMESTAMP") default: buf.WriteString(fmt.Sprintf(" DEFAULT '%v'", col.DefaultValue)) } } if mysql.HasOnUpdateNowFlag(col.Flag) { buf.WriteString(" ON UPDATE CURRENT_TIMESTAMP") } } if len(col.Comment) > 0 { buf.WriteString(fmt.Sprintf(" COMMENT '%s'", col.Comment)) } if i != len(tb.Cols())-1 { buf.WriteString(",\n") } if tb.Meta().PKIsHandle && mysql.HasPriKeyFlag(col.Flag) { pkCol = col } } if pkCol != nil { // If PKIsHanle, pk info is not in tb.Indices(). We should handle it here. buf.WriteString(",\n") buf.WriteString(fmt.Sprintf(" PRIMARY KEY (`%s`)", pkCol.Name.O)) } if len(tb.Indices()) > 0 || len(tb.Meta().ForeignKeys) > 0 { buf.WriteString(",\n") } for i, idx := range tb.Indices() { idxInfo := idx.Meta() if idxInfo.Primary { buf.WriteString(" PRIMARY KEY ") } else if idxInfo.Unique { buf.WriteString(fmt.Sprintf(" UNIQUE KEY `%s` ", idxInfo.Name.O)) } else { buf.WriteString(fmt.Sprintf(" KEY `%s` ", idxInfo.Name.O)) } cols := make([]string, 0, len(idxInfo.Columns)) for _, c := range idxInfo.Columns { cols = append(cols, c.Name.O) } buf.WriteString(fmt.Sprintf("(`%s`)", strings.Join(cols, "`,`"))) if i != len(tb.Indices())-1 { buf.WriteString(",\n") } } if len(tb.Indices()) > 0 && len(tb.Meta().ForeignKeys) > 0 { buf.WriteString(",\n") } for _, fk := range tb.Meta().ForeignKeys { if fk.State != model.StatePublic { continue } cols := make([]string, 0, len(fk.Cols)) for _, c := range fk.Cols { cols = append(cols, c.O) } refCols := make([]string, 0, len(fk.RefCols)) for _, c := range fk.Cols { refCols = append(refCols, c.O) } buf.WriteString(fmt.Sprintf(" CONSTRAINT `%s` FOREIGN KEY (`%s`)", fk.Name.O, strings.Join(cols, "`,`"))) buf.WriteString(fmt.Sprintf(" REFERENCES `%s` (`%s`)", fk.RefTable.O, strings.Join(refCols, "`,`"))) if ast.ReferOptionType(fk.OnDelete) != ast.ReferOptionNoOption { buf.WriteString(fmt.Sprintf(" ON DELETE %s", ast.ReferOptionType(fk.OnDelete))) } if ast.ReferOptionType(fk.OnUpdate) != ast.ReferOptionNoOption { buf.WriteString(fmt.Sprintf(" ON UPDATE %s", ast.ReferOptionType(fk.OnUpdate))) } } buf.WriteString("\n") buf.WriteString(") ENGINE=InnoDB") if s := tb.Meta().Charset; len(s) > 0 { buf.WriteString(fmt.Sprintf(" DEFAULT CHARSET=%s", s)) } if tb.Meta().AutoIncID > 0 { buf.WriteString(fmt.Sprintf(" AUTO_INCREMENT=%d", tb.Meta().AutoIncID)) } if len(tb.Meta().Comment) > 0 { buf.WriteString(fmt.Sprintf(" COMMENT='%s'", tb.Meta().Comment)) } data := types.MakeDatums(tb.Meta().Name.O, buf.String()) e.rows = append(e.rows, &Row{Data: data}) return nil }