getMaterializedViews returns the materialized views of the current database keyed by table name. Doris and StarRocks expose them through different catalogs, so the query and projection are engine-specific. The query is best-effort: an engine/version that does not support it is logged and yields an e
(ctx context.Context)
| 146 | // and projection are engine-specific. The query is best-effort: an engine/version that |
| 147 | // does not support it is logged and yields an empty set rather than failing the sync. |
| 148 | func (d *Driver) getMaterializedViews(ctx context.Context) (map[db.TableKey]*storepb.MaterializedViewMetadata, error) { |
| 149 | materializedViewMap := make(map[db.TableKey]*storepb.MaterializedViewMetadata) |
| 150 | |
| 151 | var query string |
| 152 | switch d.dbType { |
| 153 | case storepb.Engine_DORIS: |
| 154 | // Doris exposes materialized views via the mv_infos() table-valued function. |
| 155 | // https://doris.apache.org/docs/sql-manual/sql-functions/table-valued-functions/mv_infos |
| 156 | query = fmt.Sprintf(`SELECT Name, QuerySql FROM mv_infos("database"="%s")`, d.databaseName) |
| 157 | case storepb.Engine_STARROCKS: |
| 158 | // StarRocks exposes materialized views via information_schema.materialized_views. |
| 159 | // REFRESH_TYPE separates async MVs from synchronous rollups, which are excluded. |
| 160 | // IFNULL guards the bare-string scans below: database/sql errors on a NULL->string scan. |
| 161 | query = fmt.Sprintf(`SELECT TABLE_NAME, IFNULL(REFRESH_TYPE, ''), IFNULL(MATERIALIZED_VIEW_DEFINITION, '') FROM information_schema.materialized_views WHERE TABLE_SCHEMA = '%s'`, d.databaseName) |
| 162 | default: |
| 163 | return materializedViewMap, nil |
| 164 | } |
| 165 | |
| 166 | rows, err := d.db.QueryContext(ctx, query) |
| 167 | if err != nil { |
| 168 | // The catalog may be unavailable on older engine versions; log and continue. |
| 169 | slog.Debug("failed to query materialized views, might not be supported in this version", log.BBError(err)) |
| 170 | return materializedViewMap, nil |
| 171 | } |
| 172 | defer rows.Close() |
| 173 | |
| 174 | for rows.Next() { |
| 175 | materializedView := &storepb.MaterializedViewMetadata{} |
| 176 | if d.dbType == storepb.Engine_STARROCKS { |
| 177 | var refreshType string |
| 178 | if err := rows.Scan(&materializedView.Name, &refreshType, &materializedView.Definition); err != nil { |
| 179 | return nil, err |
| 180 | } |
| 181 | if isSyncRollup(refreshType) { |
| 182 | continue |
| 183 | } |
| 184 | } else if err := rows.Scan(&materializedView.Name, &materializedView.Definition); err != nil { |
| 185 | return nil, err |
| 186 | } |
| 187 | key := db.TableKey{Schema: "", Table: materializedView.Name} |
| 188 | materializedViewMap[key] = materializedView |
| 189 | } |
| 190 | if err := rows.Err(); err != nil { |
| 191 | return nil, util.FormatErrorWithQuery(err, query) |
| 192 | } |
| 193 | return materializedViewMap, nil |
| 194 | } |
| 195 | |
| 196 | // SyncDBSchema syncs a single database schema. |
| 197 | func (d *Driver) SyncDBSchema(ctx context.Context) (*storepb.DatabaseSchemaMetadata, error) { |
no test coverage detected