MySQL: Add parseTime=true to SQL connections (#92469)

This commit is contained in:
Ryan McKinley 2024-08-27 14:16:04 +03:00 committed by GitHub
parent c98e3e0483
commit c59dddf7af
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 47 additions and 3 deletions

View File

@ -122,6 +122,7 @@ Experimental features might be changed or removed without prior notice.
| `logRequestsInstrumentedAsUnknown` | Logs the path for requests that are instrumented as unknown | | `logRequestsInstrumentedAsUnknown` | Logs the path for requests that are instrumented as unknown |
| `showDashboardValidationWarnings` | Show warnings when dashboards do not validate against the schema | | `showDashboardValidationWarnings` | Show warnings when dashboards do not validate against the schema |
| `mysqlAnsiQuotes` | Use double quotes to escape keyword in a MySQL query | | `mysqlAnsiQuotes` | Use double quotes to escape keyword in a MySQL query |
| `mysqlParseTime` | Ensure the parseTime flag is set for MySQL driver |
| `alertingBacktesting` | Rule backtesting API for alerting | | `alertingBacktesting` | Rule backtesting API for alerting |
| `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files | | `editPanelCSVDragAndDrop` | Enables drag and drop for CSV and Excel files |
| `lokiQuerySplittingConfig` | Give users the option to configure split durations for Loki queries | | `lokiQuerySplittingConfig` | Give users the option to configure split durations for Loki queries |

View File

@ -45,6 +45,7 @@ export interface FeatureToggles {
cloudWatchCrossAccountQuerying?: boolean; cloudWatchCrossAccountQuerying?: boolean;
showDashboardValidationWarnings?: boolean; showDashboardValidationWarnings?: boolean;
mysqlAnsiQuotes?: boolean; mysqlAnsiQuotes?: boolean;
mysqlParseTime?: boolean;
accessControlOnCall?: boolean; accessControlOnCall?: boolean;
nestedFolders?: boolean; nestedFolders?: boolean;
alertingBacktesting?: boolean; alertingBacktesting?: boolean;

View File

@ -214,6 +214,12 @@ var (
Stage: FeatureStageExperimental, Stage: FeatureStageExperimental,
Owner: grafanaSearchAndStorageSquad, Owner: grafanaSearchAndStorageSquad,
}, },
{
Name: "mysqlParseTime",
Description: "Ensure the parseTime flag is set for MySQL driver",
Stage: FeatureStageExperimental,
Owner: grafanaSearchAndStorageSquad,
},
{ {
Name: "accessControlOnCall", Name: "accessControlOnCall",
Description: "Access control primitives for OnCall", Description: "Access control primitives for OnCall",

View File

@ -26,6 +26,7 @@ grpcServer,preview,@grafana/search-and-storage,false,false,false
cloudWatchCrossAccountQuerying,GA,@grafana/aws-datasources,false,false,false cloudWatchCrossAccountQuerying,GA,@grafana/aws-datasources,false,false,false
showDashboardValidationWarnings,experimental,@grafana/dashboards-squad,false,false,false showDashboardValidationWarnings,experimental,@grafana/dashboards-squad,false,false,false
mysqlAnsiQuotes,experimental,@grafana/search-and-storage,false,false,false mysqlAnsiQuotes,experimental,@grafana/search-and-storage,false,false,false
mysqlParseTime,experimental,@grafana/search-and-storage,false,false,false
accessControlOnCall,preview,@grafana/identity-access-team,false,false,false accessControlOnCall,preview,@grafana/identity-access-team,false,false,false
nestedFolders,GA,@grafana/search-and-storage,false,false,false nestedFolders,GA,@grafana/search-and-storage,false,false,false
alertingBacktesting,experimental,@grafana/alerting-squad,false,false,false alertingBacktesting,experimental,@grafana/alerting-squad,false,false,false

1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
26 cloudWatchCrossAccountQuerying GA @grafana/aws-datasources false false false
27 showDashboardValidationWarnings experimental @grafana/dashboards-squad false false false
28 mysqlAnsiQuotes experimental @grafana/search-and-storage false false false
29 mysqlParseTime experimental @grafana/search-and-storage false false false
30 accessControlOnCall preview @grafana/identity-access-team false false false
31 nestedFolders GA @grafana/search-and-storage false false false
32 alertingBacktesting experimental @grafana/alerting-squad false false false

View File

@ -115,6 +115,10 @@ const (
// Use double quotes to escape keyword in a MySQL query // Use double quotes to escape keyword in a MySQL query
FlagMysqlAnsiQuotes = "mysqlAnsiQuotes" FlagMysqlAnsiQuotes = "mysqlAnsiQuotes"
// FlagMysqlParseTime
// Ensure the parseTime flag is set for MySQL driver
FlagMysqlParseTime = "mysqlParseTime"
// FlagAccessControlOnCall // FlagAccessControlOnCall
// Access control primitives for OnCall // Access control primitives for OnCall
FlagAccessControlOnCall = "accessControlOnCall" FlagAccessControlOnCall = "accessControlOnCall"

View File

@ -1789,6 +1789,18 @@
"codeowner": "@grafana/search-and-storage" "codeowner": "@grafana/search-and-storage"
} }
}, },
{
"metadata": {
"name": "mysqlParseTime",
"resourceVersion": "1724750152191",
"creationTimestamp": "2024-08-27T09:15:52Z"
},
"spec": {
"description": "Ensure the parseTime flag is set for MySQL driver",
"stage": "experimental",
"codeowner": "@grafana/search-and-storage"
}
},
{ {
"metadata": { "metadata": {
"name": "nestedFolders", "name": "nestedFolders",

View File

@ -791,7 +791,11 @@ func TestIntegrationSoftDeletion(t *testing.T) {
// Set up dashboard store. // Set up dashboard store.
quotaService := quotatest.New(false, nil) quotaService := quotatest.New(false, nil)
featureToggles := featuremgmt.WithFeatures(featuremgmt.FlagPanelTitleSearch, featuremgmt.FlagDashboardRestore) featureToggles := featuremgmt.WithFeatures(
featuremgmt.FlagPanelTitleSearch,
featuremgmt.FlagDashboardRestore,
featuremgmt.FlagMysqlParseTime,
)
dashboardStore, err := database.ProvideDashboardStore(replStore, cfg, featureToggles, tagimpl.ProvideService(sqlStore), quotaService) dashboardStore, err := database.ProvideDashboardStore(replStore, cfg, featureToggles, tagimpl.ProvideService(sqlStore), quotaService)
require.NoError(t, err) require.NoError(t, err)

View File

@ -166,6 +166,10 @@ func (dbCfg *DatabaseConfig) buildConnectionString(cfg *setting.Cfg, features fe
cnnstr += fmt.Sprintf("&transaction_isolation=%s", val) cnnstr += fmt.Sprintf("&transaction_isolation=%s", val)
} }
if features != nil && features.IsEnabledGlobally(featuremgmt.FlagMysqlParseTime) {
cnnstr += "&parseTime=true"
}
if features != nil && features.IsEnabledGlobally(featuremgmt.FlagMysqlAnsiQuotes) { if features != nil && features.IsEnabledGlobally(featuremgmt.FlagMysqlAnsiQuotes) {
cnnstr += "&sql_mode='ANSI_QUOTES'" cnnstr += "&sql_mode='ANSI_QUOTES'"
} }

View File

@ -296,15 +296,24 @@ func (ss *SQLStore) initEngine(engine *xorm.Engine) error {
} }
} }
if engine == nil { if engine == nil {
connection := ss.dbCfg.ConnectionString
// Ensure that parseTime is enabled for MySQL
if ss.dbCfg.Type == migrator.MySQL && !strings.Contains(connection, "parseTime=") {
if ss.features.IsEnabledGlobally(featuremgmt.FlagMysqlParseTime) {
connection += "&parseTime=true"
}
}
var err error var err error
engine, err = xorm.NewEngine(ss.dbCfg.Type, ss.dbCfg.ConnectionString) engine, err = xorm.NewEngine(ss.dbCfg.Type, connection)
if err != nil { if err != nil {
return err return err
} }
// Only for MySQL or MariaDB, verify we can connect with the current connection string's system var for transaction isolation. // Only for MySQL or MariaDB, verify we can connect with the current connection string's system var for transaction isolation.
// If not, create a new engine with a compatible connection string. // If not, create a new engine with a compatible connection string.
if ss.dbCfg.Type == migrator.MySQL { if ss.dbCfg.Type == migrator.MySQL {
engine, err = ss.ensureTransactionIsolationCompatibility(engine, ss.dbCfg.ConnectionString) engine, err = ss.ensureTransactionIsolationCompatibility(engine, connection)
if err != nil { if err != nil {
return err return err
} }
@ -481,6 +490,7 @@ func getCfgForTesting(opts ...InitTestDBOpt) *setting.Cfg {
func getFeaturesForTesting(opts ...InitTestDBOpt) featuremgmt.FeatureToggles { func getFeaturesForTesting(opts ...InitTestDBOpt) featuremgmt.FeatureToggles {
featureKeys := []any{ featureKeys := []any{
featuremgmt.FlagPanelTitleSearch, featuremgmt.FlagPanelTitleSearch,
featuremgmt.FlagMysqlParseTime,
} }
for _, opt := range opts { for _, opt := range opts {
if len(opt.FeatureFlags) > 0 { if len(opt.FeatureFlags) > 0 {

View File

@ -31,6 +31,7 @@ func getEngineMySQL(getter *sectionGetter, tracer tracing.Tracer) (*xorm.Engine,
config.Loc = time.UTC config.Loc = time.UTC
config.AllowNativePasswords = true config.AllowNativePasswords = true
config.ClientFoundRows = true config.ClientFoundRows = true
config.ParseTime = true
// allow executing multiple SQL statements in a single roundtrip, and also // allow executing multiple SQL statements in a single roundtrip, and also
// enable executing the CALL statement to run stored procedures that execute // enable executing the CALL statement to run stored procedures that execute