@@ -70,6 +70,7 @@ def __init__(
70
70
self .dbdata_dpath = self .dbdata_parent_dpath / f"dbdata{ self .pgport } "
71
71
72
72
self ._conn : Optional [psycopg .Connection [Any ]] = None
73
+ self .hint_check_failed_with : Optional [str ] = None
73
74
74
75
def get_kv_connstr (self ) -> str :
75
76
return get_kv_connstr (self .pgport )
@@ -79,6 +80,21 @@ def conn(self) -> psycopg.Connection[Any]:
79
80
self ._conn = psycopg .connect (
80
81
self .get_kv_connstr (), autocommit = True , prepare_threshold = None
81
82
)
83
+
84
+ def hint_check_notice_handler (notice : psycopg .errors .Diagnostic ) -> None :
85
+ """
86
+ Custom handler for raising errors if hints fail.
87
+ """
88
+ if (
89
+ notice .message_detail is not None
90
+ and "hint" in notice .message_detail .lower ()
91
+ ):
92
+ self .hint_check_failed_with = notice .message_detail
93
+
94
+ # We add the notice handler when the _conn is created instead of before executing a
95
+ # query to avoid adding it more than once.
96
+ self ._conn .add_notice_handler (hint_check_notice_handler )
97
+
82
98
return self ._conn
83
99
84
100
def disconnect (self ) -> None :
@@ -137,17 +153,6 @@ def time_query(
137
153
did_time_out = False
138
154
explain_data = None
139
155
140
- # def hint_notice_handler(notice) -> None:
141
- # """
142
- # Custom handler for database notices.
143
- # Raises an error or logs the notice if it indicates a problem.
144
- # """
145
- # logging.getLogger(DBGYM_LOGGER_NAME).warning(f"Postgres notice: {notice}")
146
- # if "hint" in notice.message.lower():
147
- # raise RuntimeError(f"Query hint failed: {notice.message}")
148
-
149
- # self.conn().add_notice_handler(hint_notice_handler)
150
-
151
156
try :
152
157
if query_knobs :
153
158
query = f"/*+ { ' ' .join (query_knobs )} */ { query } "
@@ -158,10 +163,16 @@ def time_query(
158
163
), "If you're using add_explain, don't also write explain manually in the query."
159
164
query = f"explain (analyze, format json, timing off) { query } "
160
165
166
+ # Reset this every time before calling execute() so that hint_check_notice_handler works correctly.
167
+ self .hint_check_failed_with = None
168
+
161
169
start_time = time .time ()
162
170
cursor = self .conn ().execute (query )
163
171
qid_runtime = (time .time () - start_time ) * 1e6
164
172
173
+ if self .hint_check_failed_with is not None :
174
+ raise RuntimeError (f"Query hint failed: { self .hint_check_failed_with } " )
175
+
165
176
if add_explain :
166
177
c = [c for c in cursor ][0 ][0 ][0 ]
167
178
assert "Execution Time" in c
0 commit comments