Folders: Switch order of the columns in folder table indexes so that org_id becomes first (#82454)
* Folders: Switch order of the columns in folder table so that org_id becomes first
This commit is contained in:
@@ -55,6 +55,31 @@ func addFolderMigrations(mg *migrator.Migrator) {
|
||||
DELETE FROM folder WHERE NOT EXISTS
|
||||
(SELECT 1 FROM dashboard WHERE dashboard.uid = folder.uid AND dashboard.org_id = folder.org_id AND dashboard.is_folder = true)
|
||||
`))
|
||||
|
||||
mg.AddMigration("Remove unique index UQE_folder_uid_org_id", migrator.NewDropIndexMigration(folderv1(), &migrator.Index{
|
||||
Type: migrator.UniqueIndex,
|
||||
Cols: []string{"uid", "org_id"},
|
||||
}))
|
||||
|
||||
mg.AddMigration("Add unique index UQE_folder_org_id_uid", migrator.NewAddIndexMigration(folderv1(), &migrator.Index{
|
||||
Type: migrator.UniqueIndex,
|
||||
Cols: []string{"org_id", "uid"},
|
||||
}))
|
||||
|
||||
mg.AddMigration("Remove unique index UQE_folder_title_parent_uid_org_id", migrator.NewDropIndexMigration(folderv1(), &migrator.Index{
|
||||
Type: migrator.UniqueIndex,
|
||||
Cols: []string{"title", "parent_uid", "org_id"},
|
||||
}))
|
||||
|
||||
mg.AddMigration("Add unique index UQE_folder_org_id_parent_uid_title", migrator.NewAddIndexMigration(folderv1(), &migrator.Index{
|
||||
Type: migrator.UniqueIndex,
|
||||
Cols: []string{"org_id", "parent_uid", "title"},
|
||||
}))
|
||||
|
||||
// No need to introduce IDX_folder_org_id_parent_uid because is covered by UQE_folder_org_id_parent_uid_title
|
||||
mg.AddMigration("Remove index IDX_folder_parent_uid_org_id", migrator.NewDropIndexMigration(folderv1(), &migrator.Index{
|
||||
Cols: []string{"parent_uid", "org_id"},
|
||||
}))
|
||||
}
|
||||
|
||||
func folderv1() migrator.Table {
|
||||
|
||||
@@ -42,7 +42,7 @@ type PermissionsFilter interface {
|
||||
Where() (string, []any)
|
||||
|
||||
buildClauses()
|
||||
nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTableCol string, rightTableCol string, orgID int64) (string, []any)
|
||||
nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTable string, Col string, rightTableCol string, orgID int64) (string, []any)
|
||||
}
|
||||
|
||||
// NewAccessControlDashboardPermissionFilter creates a new AccessControlDashboardPermissionFilter that is configured with specific actions calculated based on the dashboardaccess.PermissionType and query type
|
||||
@@ -211,11 +211,11 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() {
|
||||
case true:
|
||||
builder.WriteString("(dashboard.folder_id IN (SELECT d.id FROM dashboard as d ")
|
||||
recQueryName := fmt.Sprintf("RecQry%d", len(f.recQueries))
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs)
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs, orgID)
|
||||
builder.WriteString(fmt.Sprintf("WHERE d.org_id = ? AND d.uid IN (SELECT uid FROM %s)", recQueryName))
|
||||
args = append(args, orgID)
|
||||
default:
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard.folder_id", "d.id", orgID)
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard", "folder_id", "d.id", orgID)
|
||||
builder.WriteRune('(')
|
||||
builder.WriteString(nestedFoldersSelectors)
|
||||
args = append(args, nestedFoldersArgs...)
|
||||
@@ -289,11 +289,11 @@ func (f *accessControlDashboardPermissionFilter) buildClauses() {
|
||||
switch f.recursiveQueriesAreSupported {
|
||||
case true:
|
||||
recQueryName := fmt.Sprintf("RecQry%d", len(f.recQueries))
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs)
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs, orgID)
|
||||
builder.WriteString("(dashboard.uid IN ")
|
||||
builder.WriteString(fmt.Sprintf("(SELECT uid FROM %s)", recQueryName))
|
||||
default:
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard.uid", "d.uid", orgID)
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard", "uid", "d.uid", orgID)
|
||||
builder.WriteRune('(')
|
||||
builder.WriteString(nestedFoldersSelectors)
|
||||
builder.WriteRune(')')
|
||||
@@ -340,15 +340,17 @@ func (f *accessControlDashboardPermissionFilter) With() (string, []any) {
|
||||
return sb.String(), params
|
||||
}
|
||||
|
||||
func (f *accessControlDashboardPermissionFilter) addRecQry(queryName string, whereUIDSelect string, whereParams []any) {
|
||||
func (f *accessControlDashboardPermissionFilter) addRecQry(queryName string, whereUIDSelect string, whereParams []any, orgID int64) {
|
||||
if f.recQueries == nil {
|
||||
f.recQueries = make([]clause, 0, maximumRecursiveQueries)
|
||||
}
|
||||
c := make([]any, len(whereParams))
|
||||
copy(c, whereParams)
|
||||
c = append([]any{orgID}, c...)
|
||||
f.recQueries = append(f.recQueries, clause{
|
||||
// covered by UQE_folder_org_id_uid and UQE_folder_org_id_parent_uid_title
|
||||
string: fmt.Sprintf(`%s AS (
|
||||
SELECT uid, parent_uid, org_id FROM folder WHERE uid IN %s
|
||||
SELECT uid, parent_uid, org_id FROM folder WHERE org_id = ? AND uid IN %s
|
||||
UNION ALL SELECT f.uid, f.parent_uid, f.org_id FROM folder f INNER JOIN %s r ON f.parent_uid = r.uid and f.org_id = r.org_id
|
||||
)`, queryName, whereUIDSelect, queryName),
|
||||
params: c,
|
||||
@@ -378,12 +380,13 @@ func actionsToCheck(actions []string, permissions map[string][]string, wildcards
|
||||
return toCheck
|
||||
}
|
||||
|
||||
func (f *accessControlDashboardPermissionFilter) nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTableCol string, rightTableCol string, orgID int64) (string, []any) {
|
||||
func (f *accessControlDashboardPermissionFilter) nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTable string, leftCol string, rightTableCol string, orgID int64) (string, []any) {
|
||||
wheres := make([]string, 0, folder.MaxNestedFolderDepth+1)
|
||||
args := make([]any, 0, len(permSelectorArgs)*(folder.MaxNestedFolderDepth+1))
|
||||
|
||||
joins := make([]string, 0, folder.MaxNestedFolderDepth+2)
|
||||
|
||||
// covered by UQE_folder_org_id_uid
|
||||
tmpl := "INNER JOIN folder %s ON %s.%s = %s.uid AND %s.org_id = %s.org_id "
|
||||
|
||||
prev := "d"
|
||||
@@ -393,8 +396,9 @@ func (f *accessControlDashboardPermissionFilter) nestedFoldersSelectors(permSele
|
||||
s := fmt.Sprintf(tmpl, t, prev, onCol, t, prev, t)
|
||||
joins = append(joins, s)
|
||||
|
||||
wheres = append(wheres, fmt.Sprintf("(%s IN (SELECT %s FROM dashboard d %s WHERE %s.org_id = ? AND %s.uid IN %s)", leftTableCol, rightTableCol, strings.Join(joins, " "), t, t, permSelector))
|
||||
args = append(args, orgID)
|
||||
// covered by UQE_folder_org_id_uid
|
||||
wheres = append(wheres, fmt.Sprintf("(%s.org_id = ? AND %s.%s IN (SELECT %s FROM dashboard d %s WHERE %s.org_id = ? AND %s.uid IN %s)", leftTable, leftTable, leftCol, rightTableCol, strings.Join(joins, " "), t, t, permSelector))
|
||||
args = append(args, orgID, orgID)
|
||||
args = append(args, permSelectorArgs...)
|
||||
|
||||
prev = t
|
||||
|
||||
@@ -122,10 +122,10 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
|
||||
switch f.recursiveQueriesAreSupported {
|
||||
case true:
|
||||
recQueryName := fmt.Sprintf("RecQry%d", len(f.recQueries))
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs)
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs, orgID)
|
||||
builder.WriteString("(folder.uid IN (SELECT uid FROM " + recQueryName)
|
||||
default:
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "folder.uid", "", orgID)
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "folder", "uid", "", orgID)
|
||||
builder.WriteRune('(')
|
||||
builder.WriteString(nestedFoldersSelectors)
|
||||
args = append(args, nestedFoldersArgs...)
|
||||
@@ -199,11 +199,11 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
|
||||
switch f.recursiveQueriesAreSupported {
|
||||
case true:
|
||||
recQueryName := fmt.Sprintf("RecQry%d", len(f.recQueries))
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs)
|
||||
f.addRecQry(recQueryName, permSelector.String(), permSelectorArgs, orgID)
|
||||
builder.WriteString("(dashboard.uid IN ")
|
||||
builder.WriteString(fmt.Sprintf("(SELECT uid FROM %s)", recQueryName))
|
||||
default:
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard.uid", "", orgID)
|
||||
nestedFoldersSelectors, nestedFoldersArgs := f.nestedFoldersSelectors(permSelector.String(), permSelectorArgs, "dashboard", "uid", "", orgID)
|
||||
builder.WriteRune('(')
|
||||
builder.WriteString(nestedFoldersSelectors)
|
||||
builder.WriteRune(')')
|
||||
@@ -231,15 +231,18 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) buildClauses()
|
||||
f.where = clause{string: builder.String(), params: args}
|
||||
}
|
||||
|
||||
func (f *accessControlDashboardPermissionFilterNoFolderSubquery) nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTableCol string, _ string, orgID int64) (string, []any) {
|
||||
func (f *accessControlDashboardPermissionFilterNoFolderSubquery) nestedFoldersSelectors(permSelector string, permSelectorArgs []any, leftTable string, leftCol string, _ string, orgID int64) (string, []any) {
|
||||
wheres := make([]string, 0, folder.MaxNestedFolderDepth+1)
|
||||
args := make([]any, 0, len(permSelectorArgs)*(folder.MaxNestedFolderDepth+1))
|
||||
|
||||
joins := make([]string, 0, folder.MaxNestedFolderDepth+2)
|
||||
|
||||
// covered by UQE_folder_org_id_parent_uid_title
|
||||
tmpl := "INNER JOIN folder %s ON %s.parent_uid = %s.uid AND %s.org_id = %s.org_id "
|
||||
|
||||
wheres = append(wheres, fmt.Sprintf("(%s IN (SELECT f1.uid FROM folder f1 WHERE f1.uid IN %s)", leftTableCol, permSelector))
|
||||
// covered by UQE_folder_org_id_uid
|
||||
wheres = append(wheres, fmt.Sprintf("(%s.org_id = ? AND %s.%s IN (SELECT f1.uid FROM folder f1 WHERE f1.org_id = ? AND f1.uid IN %s)", leftTable, leftTable, leftCol, permSelector))
|
||||
args = append(args, orgID, orgID)
|
||||
args = append(args, permSelectorArgs...)
|
||||
|
||||
prev := "f1"
|
||||
@@ -248,8 +251,9 @@ func (f *accessControlDashboardPermissionFilterNoFolderSubquery) nestedFoldersSe
|
||||
s := fmt.Sprintf(tmpl, t, prev, t, prev, t)
|
||||
joins = append(joins, s)
|
||||
|
||||
wheres = append(wheres, fmt.Sprintf("(%s IN (SELECT f1.uid FROM folder f1 %s WHERE %s.org_id = ? AND %s.uid IN %s)", leftTableCol, strings.Join(joins, " "), t, t, permSelector))
|
||||
args = append(args, orgID)
|
||||
// covered by UQE_folder_org_id_uid
|
||||
wheres = append(wheres, fmt.Sprintf("(%s.org_id = ? AND %s.%s IN (SELECT f1.uid FROM folder f1 %s WHERE %s.org_id = ? AND %s.uid IN %s)", leftTable, leftTable, leftCol, strings.Join(joins, " "), t, t, permSelector))
|
||||
args = append(args, orgID, orgID)
|
||||
args = append(args, permSelectorArgs...)
|
||||
|
||||
prev = t
|
||||
|
||||
@@ -38,6 +38,7 @@ func (b *Builder) ToSQL(limit, page int64) (string, []any) {
|
||||
b.sql.WriteString("\n")
|
||||
|
||||
if b.Features.IsEnabledGlobally(featuremgmt.FlagNestedFolders) {
|
||||
// covered by UQE_folder_org_id_uid
|
||||
b.sql.WriteString(
|
||||
`LEFT OUTER JOIN folder ON folder.uid = dashboard.folder_uid AND folder.org_id = dashboard.org_id`)
|
||||
} else {
|
||||
|
||||
@@ -180,6 +180,7 @@ func TestBuilder_RBAC(t *testing.T) {
|
||||
},
|
||||
features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders),
|
||||
expectedParams: []any{
|
||||
int64(1),
|
||||
int64(1),
|
||||
int64(1),
|
||||
0,
|
||||
@@ -191,6 +192,7 @@ func TestBuilder_RBAC(t *testing.T) {
|
||||
2,
|
||||
int64(1),
|
||||
int64(1),
|
||||
int64(1),
|
||||
0,
|
||||
"Viewer",
|
||||
int64(1),
|
||||
@@ -255,6 +257,7 @@ func TestBuilder_RBAC(t *testing.T) {
|
||||
},
|
||||
features: featuremgmt.WithFeatures(featuremgmt.FlagNestedFolders, featuremgmt.FlagPermissionsFilterRemoveSubquery),
|
||||
expectedParams: []any{
|
||||
int64(1),
|
||||
int64(1),
|
||||
int64(1),
|
||||
0,
|
||||
@@ -266,6 +269,7 @@ func TestBuilder_RBAC(t *testing.T) {
|
||||
2,
|
||||
int64(1),
|
||||
int64(1),
|
||||
int64(1),
|
||||
0,
|
||||
"Viewer",
|
||||
int64(1),
|
||||
|
||||
Reference in New Issue
Block a user