Spaces:
Sleeping
Sleeping
Upload environment.py
Browse files- server/environment.py +56 -16
server/environment.py
CHANGED
|
@@ -210,31 +210,71 @@ class SQLQualityEnvironment:
|
|
| 210 |
"""
|
| 211 |
Handle a QUERY action.
|
| 212 |
|
| 213 |
-
Executes the SQL on the episode connection.
|
| 214 |
Returns a result preview in the observation. Does NOT end the episode.
|
| 215 |
Awards small step_reward (0.05) for queries that target the right area.
|
| 216 |
"""
|
| 217 |
sql = (action.sql or "").strip()
|
| 218 |
|
| 219 |
-
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
|
| 223 |
-
|
| 224 |
-
|
| 225 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 226 |
else:
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 232 |
step_reward = (
|
| 233 |
-
0.05 if _query_reveals_issue(
|
| 234 |
)
|
| 235 |
-
except sqlite3.Error as e:
|
| 236 |
-
result_preview = f"SQL Error: {e}"
|
| 237 |
-
step_reward = 0.0
|
| 238 |
|
| 239 |
# Add to trajectory
|
| 240 |
self._trajectory.append(
|
|
|
|
| 210 |
"""
|
| 211 |
Handle a QUERY action.
|
| 212 |
|
| 213 |
+
Executes the SQL on the episode connection (supports multi-statement).
|
| 214 |
Returns a result preview in the observation. Does NOT end the episode.
|
| 215 |
Awards small step_reward (0.05) for queries that target the right area.
|
| 216 |
"""
|
| 217 |
sql = (action.sql or "").strip()
|
| 218 |
|
| 219 |
+
# Split multiple statements by semicolon, but preserve semicolons in strings
|
| 220 |
+
statements = []
|
| 221 |
+
current = ""
|
| 222 |
+
in_string = False
|
| 223 |
+
string_char = None
|
| 224 |
+
i = 0
|
| 225 |
+
while i < len(sql):
|
| 226 |
+
char = sql[i]
|
| 227 |
+
if char in ("'", '"') and (i == 0 or sql[i-1] != "\\"):
|
| 228 |
+
if not in_string:
|
| 229 |
+
in_string = True
|
| 230 |
+
string_char = char
|
| 231 |
+
elif char == string_char:
|
| 232 |
+
in_string = False
|
| 233 |
+
string_char = None
|
| 234 |
+
if char == ";" and not in_string:
|
| 235 |
+
stmt = current.strip()
|
| 236 |
+
if stmt:
|
| 237 |
+
statements.append(stmt)
|
| 238 |
+
current = ""
|
| 239 |
else:
|
| 240 |
+
current += char
|
| 241 |
+
i += 1
|
| 242 |
+
# Add final statement
|
| 243 |
+
if current.strip():
|
| 244 |
+
statements.append(current.strip())
|
| 245 |
+
|
| 246 |
+
# If no statements found, treat as single statement
|
| 247 |
+
if not statements:
|
| 248 |
+
statements = [sql] if sql else []
|
| 249 |
+
|
| 250 |
+
result_preview = ""
|
| 251 |
+
step_reward = 0.0
|
| 252 |
+
last_error = None
|
| 253 |
|
| 254 |
+
for stmt in statements:
|
| 255 |
+
if not stmt:
|
| 256 |
+
continue
|
| 257 |
+
try:
|
| 258 |
+
cursor = self._original_conn.execute(stmt)
|
| 259 |
+
# Check if query returns rows (SELECT) or just modifies (INSERT/UPDATE/DELETE)
|
| 260 |
+
if cursor.description:
|
| 261 |
+
rows = cursor.fetchmany(5)
|
| 262 |
+
cols = [d[0] for d in cursor.description]
|
| 263 |
+
result_preview = str([dict(zip(cols, row)) for row in rows])[:300]
|
| 264 |
+
else:
|
| 265 |
+
# For INSERT/UPDATE/DELETE, show affected rows
|
| 266 |
+
result_preview = f"Query executed successfully. Rows affected: {cursor.rowcount}"
|
| 267 |
+
except sqlite3.Error as e:
|
| 268 |
+
last_error = str(e)
|
| 269 |
+
result_preview = f"SQL Error: {e}"
|
| 270 |
+
break # Stop on first error
|
| 271 |
+
|
| 272 |
+
# Small reward for targeted queries (only check first statement for relevance)
|
| 273 |
+
if statements and not last_error:
|
| 274 |
+
from server.graders import _query_reveals_issue
|
| 275 |
step_reward = (
|
| 276 |
+
0.05 if _query_reveals_issue(statements[0], self._ground_truth) else 0.01
|
| 277 |
)
|
|
|
|
|
|
|
|
|
|
| 278 |
|
| 279 |
# Add to trajectory
|
| 280 |
self._trajectory.append(
|