diff --git a/sqlite_utils/cli.py b/sqlite_utils/cli.py index 79103bc..0acb252 100644 --- a/sqlite_utils/cli.py +++ b/sqlite_utils/cli.py @@ -786,12 +786,25 @@ def insert_upsert_implementation( db[table].insert_all( docs, pk=pk, batch_size=batch_size, alter=alter, **extra_kwargs ) - except sqlite3.OperationalError as e: - if e.args and "has no column named" in e.args[0]: + except Exception as e: + if ( + isinstance(e, sqlite3.OperationalError) + and e.args + and "has no column named" in e.args[0] + ): raise click.ClickException( "{}\n\nTry using --alter to add additional columns".format(e.args[0]) ) - raise + # If we can find sql= and params= arguments, show those + variables = _find_variables(e.__traceback__, ["sql", "params"]) + if "sql" in variables and "params" in variables: + raise click.ClickException( + "{}\n\nsql = {}\nparams={}".format( + str(e), variables["sql"], variables["params"] + ) + ) + else: + raise if tracker is not None: db[table].transform(types=tracker.types) @@ -805,6 +818,18 @@ def _flatten(d): yield key, value +def _find_variables(tb, vars): + to_find = list(vars) + found = {} + for var in to_find: + if var in tb.tb_frame.f_locals: + vars.remove(var) + found[var] = tb.tb_frame.f_locals[var] + if vars and tb.tb_next: + found.update(_find_variables(tb.tb_next, vars)) + return found + + @cli.command() @insert_upsert_options @click.option( diff --git a/tests/test_cli.py b/tests/test_cli.py index e6f6683..319bd40 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1256,7 +1256,11 @@ def test_upsert_alter(db_path, tmpdir): cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id"] ) assert 1 == result.exit_code - assert "no such column: age" == str(result.exception) + assert ( + "Error: no such column: age\n\n" + "sql = UPDATE [dogs] SET [age] = ? WHERE [id] = ?\n" + "params=[5, 1]" + ) == result.output.strip() # Should succeed with --alter result = CliRunner().invoke( cli.cli, ["upsert", db_path, "dogs", json_path, "--pk", "id", "--alter"] @@ -2304,3 +2308,18 @@ def test_insert_detect_types(tmpdir, option_or_env_var): ) def test_flatten_helper(input, expected): assert dict(cli._flatten(input)) == expected + + +def test_integer_overflow_error(tmpdir): + db_path = str(tmpdir / "test.db") + result = CliRunner().invoke( + cli.cli, + ["insert", db_path, "items", "-"], + input=json.dumps({"bignumber": 34223049823094832094802398430298048240}), + ) + assert result.exit_code == 1 + assert result.output == ( + "Error: Python int too large to convert to SQLite INTEGER\n\n" + "sql = INSERT INTO [items] ([bignumber]) VALUES (?);\n" + "params=[34223049823094832094802398430298048240]\n" + )