# Copyright Materialize, Inc. and contributors. All rights reserved. # # Use of this software is governed by the Business Source License # included in the LICENSE file at the root of this repository. # # As of the Change Date specified in that file, in accordance with # the Business Source License, use of this software will be governed # by the Apache License, Version 2.0. import logging import re from enum import Enum from pathlib import Path from typing import Any, cast import numpy as np import psycopg import sqlparse from . import Scenario, util class Dialect(Enum): PG = 0 MZ = 1 class Query: """An API for manipulating workload queries.""" def __init__(self, query: str) -> None: self.query = query def __str__(self) -> str: return self.query def name(self) -> str: """Extracts and returns the name of this query from a '-- name: {name}' comment. Returns 'anonymous' if the name is not set.""" p = r"-- name\: (?P.+)" m = re.search(p, self.query, re.MULTILINE) return m.group("name") if m else "anonoymous" def explain(self, timing: bool, dialect: Dialect = Dialect.MZ) -> str: """Prepends 'EXPLAIN ...' to the query respecting the given dialect.""" if dialect == Dialect.PG: if timing: return "\n".join(["EXPLAIN (ANALYZE, TIMING TRUE)", self.query]) else: return "\n".join(["EXPLAIN", self.query]) else: if timing: return "\n".join(["EXPLAIN WITH(timing)", self.query]) else: return "\n".join(["EXPLAIN", self.query]) class ExplainOutput: """An API for manipulating 'EXPLAIN ... PLAN FOR' results.""" def __init__(self, output: str) -> None: self.output = output def __str__(self) -> str: return self.output def optimization_time(self) -> np.timedelta64 | None: """Optionally, returns the optimization_time time for an 'EXPLAIN' output.""" p = r"(Optimization time|Planning Time)\: (?P