func (si *SchemaInfo) createTable(conn dbconnpool.PoolConnection, tableName string) { tables, err := conn.ExecuteFetch(fmt.Sprintf("%s and table_name = '%s'", base_show_tables, tableName), 1, false) if err != nil { panic(NewTabletError(FAIL, "Error fetching table %s: %v", tableName, err)) } if len(tables.Rows) != 1 { panic(NewTabletError(FAIL, "rows for %s !=1: %v", tableName, len(tables.Rows))) } tableInfo, err := NewTableInfo( conn, tableName, tables.Rows[0][1].String(), // table_type tables.Rows[0][2], // create_time tables.Rows[0][3].String(), // table_comment si.cachePool, ) if err != nil { panic(NewTabletError(FATAL, "Could not get load table %s: %v", tableName, err)) } if tableInfo.CacheType == schema.CACHE_NONE { log.Infof("Initialized table: %s", tableName) } else { log.Infof("Initialized cached table: %s", tableInfo.Cache.prefix) } si.mu.Lock() defer si.mu.Unlock() if _, ok := si.tables[tableName]; ok { panic(NewTabletError(FAIL, "Table %s already exists", tableName)) } si.tables[tableName] = tableInfo }
func (rqc *RequestContext) execStreamSQL(conn dbconnpool.PoolConnection, sql string, callback func(*mproto.QueryResult) error) { start := time.Now() err := conn.ExecuteStreamFetch(sql, callback, int(rqc.qe.streamBufferSize.Get())) rqc.logStats.AddRewrittenSql(sql, start) if err != nil { panic(NewTabletErrorSql(FAIL, err)) } }
func (axp *ActiveTxPool) SafeBegin(conn dbconnpool.PoolConnection) (transactionId int64, err error) { defer handleError(&err, nil) if _, err := conn.ExecuteFetch(BEGIN, 1, false); err != nil { panic(NewTabletErrorSql(FAIL, err)) } transactionId = axp.lastId.Add(1) axp.pool.Register(transactionId, newTxConnection(conn, transactionId, axp)) return transactionId, nil }
func (ti *TableInfo) fetchColumns(conn dbconnpool.PoolConnection) error { columns, err := conn.ExecuteFetch(fmt.Sprintf("describe `%s`", ti.Name), 10000, false) if err != nil { return err } for _, row := range columns.Rows { ti.AddColumn(row[0].String(), row[1].String(), row[4], row[5].String()) } return nil }
func (qe *QueryEngine) executeStreamSql(logStats *SQLQueryStats, conn dbconnpool.PoolConnection, sql string, callback func(*mproto.QueryResult) error) { logStats.QuerySources |= QUERY_SOURCE_MYSQL logStats.NumberOfQueries++ logStats.AddRewrittenSql(sql) fetchStart := time.Now() err := conn.ExecuteStreamFetch(sql, callback, int(qe.streamBufferSize.Get())) logStats.MysqlResponseTime += time.Now().Sub(fetchStart) if err != nil { panic(NewTabletErrorSql(FAIL, err)) } }
func (ti *TableInfo) fetchIndexes(conn dbconnpool.PoolConnection) error { indexes, err := conn.ExecuteFetch(fmt.Sprintf("show index from `%s`", ti.Name), 10000, false) if err != nil { return err } var currentIndex *schema.Index currentName := "" for _, row := range indexes.Rows { indexName := row[2].String() if currentName != indexName { currentIndex = ti.AddIndex(indexName) currentName = indexName } var cardinality uint64 if !row[6].IsNull() { cardinality, err = strconv.ParseUint(row[6].String(), 0, 64) if err != nil { log.Warningf("%s", err) } } currentIndex.AddColumn(row[4].String(), cardinality) } if len(ti.Indexes) == 0 { return nil } pkIndex := ti.Indexes[0] if pkIndex.Name != "PRIMARY" { return nil } ti.PKColumns = make([]int, len(pkIndex.Columns)) for i, pkCol := range pkIndex.Columns { ti.PKColumns[i] = ti.FindColumn(pkCol) } // Primary key contains all table columns for _, col := range ti.Columns { pkIndex.DataColumns = append(pkIndex.DataColumns, col.Name) } // Secondary indices contain all primary key columns for i := 1; i < len(ti.Indexes); i++ { for _, c := range ti.Indexes[i].Columns { ti.Indexes[i].DataColumns = append(ti.Indexes[i].DataColumns, c) } for _, c := range pkIndex.Columns { // pk columns may already be part of the index. So, // check before adding. if ti.Indexes[i].FindDataColumn(c) != -1 { continue } ti.Indexes[i].DataColumns = append(ti.Indexes[i].DataColumns, c) } } return nil }
func (rqc *RequestContext) execSQLNoPanic(conn dbconnpool.PoolConnection, sql string, wantfields bool) (*mproto.QueryResult, error) { if qd := rqc.qe.connKiller.SetDeadline(conn.Id(), rqc.deadline); qd != nil { defer qd.Done() } start := time.Now() result, err := conn.ExecuteFetch(sql, int(rqc.qe.maxResultSize.Get()), wantfields) rqc.logStats.AddRewrittenSql(sql, start) if err != nil { return nil, NewTabletErrorSql(FAIL, err) } return result, nil }
func (qe *QueryEngine) executeSql(logStats *SQLQueryStats, conn dbconnpool.PoolConnection, sql string, wantfields bool) (*mproto.QueryResult, error) { connid := conn.Id() qe.activePool.Put(connid) defer qe.activePool.Remove(connid) logStats.QuerySources |= QUERY_SOURCE_MYSQL logStats.NumberOfQueries++ logStats.AddRewrittenSql(sql) // NOTE(szopa): I am not doing this measurement inside // conn.ExecuteFetch because that would require changing the // PoolConnection interface. Same applies to executeStreamSql. fetchStart := time.Now() result, err := conn.ExecuteFetch(sql, int(qe.maxResultSize.Get()), wantfields) logStats.MysqlResponseTime += time.Now().Sub(fetchStart) if err != nil { return nil, NewTabletErrorSql(FAIL, err) } return result, nil }
func (mysqld *Mysqld) restoreAfterSnapshot(slaveStartRequired, readOnly bool, hookExtraEnv map[string]string, connToRelease dbconnpool.PoolConnection) (err error) { // Try to fix mysqld regardless of snapshot success.. log.Infof("exec UNLOCK TABLES") _, err = connToRelease.ExecuteFetch("UNLOCK TABLES", 10000, false) connToRelease.Recycle() if err != nil { return fmt.Errorf("failed to UNLOCK TABLES: %v", err) } // restore original mysqld state that we saved above if slaveStartRequired { if err = mysqld.StartSlave(hookExtraEnv); err != nil { return } // this should be quick, but we might as well just wait if err = mysqld.WaitForSlaveStart(5); err != nil { return } } if err = mysqld.SetReadOnly(readOnly); err != nil { return } return nil }
// executeFetchContext calls ExecuteFetch() on the given connection, // while respecting Context deadline and cancellation. func (mysqld *Mysqld) executeFetchContext(ctx context.Context, conn dbconnpool.PoolConnection, query string, maxrows int, wantfields bool) (*sqltypes.Result, error) { // Fast fail if context is done. select { case <-ctx.Done(): return nil, ctx.Err() default: } // Execute asynchronously so we can select on both it and the context. var qr *sqltypes.Result var executeErr error done := make(chan struct{}) go func() { defer close(done) qr, executeErr = conn.ExecuteFetch(query, maxrows, wantfields) }() // Wait for either the query or the context to be done. select { case <-done: return qr, executeErr case <-ctx.Done(): // If both are done already, we may end up here anyway because select // chooses among multiple ready channels pseudorandomly. // Check the done channel and prefer that one if it's ready. select { case <-done: return qr, executeErr default: } // The context expired or was cancelled. // Try to kill the connection to effectively cancel the ExecuteFetch(). connID := conn.ID() log.Infof("Mysqld.executeFetchContext(): killing connID %v due to timeout of query: %v", connID, query) if killErr := mysqld.killConnection(connID); killErr != nil { // Log it, but go ahead and wait for the query anyway. log.Warningf("Mysqld.executeFetchContext(): failed to kill connID %v: %v", connID, killErr) } // Wait for the conn.ExecuteFetch() call to return. <-done // Close the connection. Upon Recycle() it will be thrown out. conn.Close() // ExecuteFetch() may have succeeded before we tried to kill it. // If ExecuteFetch() had returned because we cancelled it, // then executeErr would be an error like "MySQL has gone away". if executeErr == nil { return qr, executeErr } return nil, ctx.Err() } }