MCPcopy Create free account
hub / github.com/bytebase/bytebase / resolveWriteTargets

Method resolveWriteTargets

backend/api/v1/sql_service.go:1917–1988  ·  view source on GitHub ↗

resolveWriteTargets returns the tables a DML/DDL statement writes/changes, using the same extractor plan-check trusts. Returns (nil, nil) when the engine has no extractor, the statement can't be parsed, or no targets are found — callers must then fall back to the database-level check (never fail ope

(
	ctx context.Context,
	instance *store.InstanceMessage,
	database *store.DatabaseMessage,
	statement string,
	requestSchema string,
)

Source from the content-addressed store, hash-verified

1915// records nothing and falls back to the request-database check. Object DDL the extractor does
1916// not model still resolves to zero targets → request-database fallback.
1917func (s *SQLService) resolveWriteTargets(
1918 ctx context.Context,
1919 instance *store.InstanceMessage,
1920 database *store.DatabaseMessage,
1921 statement string,
1922 requestSchema string,
1923) ([]writeTargetResource, error) {
1924 engine := instance.Metadata.GetEngine()
1925
1926 stmts, err := parserbase.ParseStatements(engine, statement)
1927 if err != nil {
1928 //nolint:nilerr // unparseable here → fall back to database-level check (already parsed once for the span)
1929 return nil, nil
1930 }
1931 asts := parserbase.ExtractASTs(stmts)
1932 if len(asts) == 0 {
1933 return nil, nil
1934 }
1935
1936 // Cache-first: GetQuerySpan already fetched and cached this database's metadata earlier in
1937 // the same request, so reuse it instead of issuing a second store query on the write path.
1938 dbMeta, err := s.store.GetDBSchemaSnapshot(ctx, common.GetWorkspaceIDFromContext(ctx), database.InstanceID, database.DatabaseName)
1939 if err != nil {
1940 return nil, err
1941 }
1942 if dbMeta == nil {
1943 return nil, nil
1944 }
1945
1946 changeSummary, err := parserbase.ExtractChangedResources(
1947 engine, database.DatabaseName, schemaForWriteTargetResolution(engine, database.DatabaseName, requestSchema), dbMeta, asts, statement,
1948 )
1949 if err != nil || changeSummary == nil || changeSummary.ChangedResources == nil {
1950 //nolint:nilerr // unsupported engine / no result → fall back to database-level check
1951 return nil, nil
1952 }
1953
1954 var targets []writeTargetResource
1955 databasesWithTableTarget := map[string]bool{}
1956 for _, db := range changeSummary.ChangedResources.Build().GetDatabases() {
1957 for _, sc := range db.GetSchemas() {
1958 schema := sc.GetName()
1959 // An unqualified target whose executed schema can't be determined here resolves
1960 // to the sentinel; treat it as unknown ("") so the schema_name attribute is
1961 // omitted (fail-closed for schema-scoped grants, still matches table-only ones).
1962 if schema == unresolvedSchemaSentinel {
1963 schema = ""
1964 }
1965 for _, tbl := range sc.GetTables() {
1966 databasesWithTableTarget[db.GetName()] = true
1967 targets = append(targets, writeTargetResource{
1968 database: db.GetName(),
1969 schema: schema,
1970 table: tbl.GetName(),
1971 })
1972 }
1973 }
1974 }

Callers 1

Calls 10

GetDBSchemaSnapshotMethod · 0.80
BuildMethod · 0.80
GetEngineMethod · 0.45
GetDatabasesMethod · 0.45
GetSchemasMethod · 0.45
GetNameMethod · 0.45
GetTablesMethod · 0.45

Tested by

no test coverage detected