Skip to content

Add write support: INSERT/UPDATE/DELETE/DDL/TCL execution#3

Merged
kwrkb merged 2 commits intomainfrom
feat/write-support
Feb 27, 2026
Merged

Add write support: INSERT/UPDATE/DELETE/DDL/TCL execution#3
kwrkb merged 2 commits intomainfrom
feat/write-support

Conversation

@kwrkb
Copy link
Copy Markdown
Owner

@kwrkb kwrkb commented Feb 26, 2026

Summary

  • database.py: _assert_read_only() を削除し、INSERT/UPDATE/DELETE/CREATE/DROP/BEGIN等すべての SQL 文を実行可能にした。QueryResultis_write_operationaffected_rows を追加。_classify_query()is_destructive_query() を追加
  • mainwindow.py: 書き込み結果の表示(N row(s) affected)、破壊的操作の確認ダイアログ、DDL/DML 後の自動リフレッシュ(_refresh_after_write())、テーブル選択の復元を実装
  • sql_highlighter.py: INSERT/UPDATE/DELETE/CREATE/DROP/BEGIN/COMMIT/ROLLBACK 等の書き込み系キーワード約50語を追加
  • tests/test_database.py: 書き込み系テスト(INSERT/DELETE/DDL/トランザクション/クエリ分類/破壊的操作検出)を追加。10テスト全 pass

Test plan

  • uv run python -m pytest tests/ -v — 10テスト全 pass を確認
  • GUI 起動後、INSERT INTO ... VALUES (...) が正常に実行されること
  • UPDATE ... SET ... 実行後、Data Preview が自動更新されること
  • DROP TABLE ... 実行時に確認ダイアログが表示されること
  • DELETE FROM ... (WHERE なし) 実行時に確認ダイアログが表示されること
  • CREATE TABLE ... 後、テーブルリストに新テーブルが追加されること
  • BEGIN → 変更 → ROLLBACK でロールバックされること

🤖 Generated with Claude Code

Extend SQLiteView from a read-only viewer to a full SQL client that
supports INSERT, UPDATE, DELETE, CREATE, DROP, BEGIN/COMMIT/ROLLBACK,
and other write operations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

このプルリクエストは、SQLiteViewを読み取り専用のビューアから、完全なSQLクライアントへと進化させます。これにより、ユーザーはデータベースの構造やデータを直接変更できるようになり、アプリケーションの有用性が大幅に向上します。変更はデータベース層、UI層、シンタックスハイライト、およびテストにわたって行われ、安全かつ効率的な書き込み操作を保証するための機能が追加されています。

Highlights

  • 書き込み操作のサポート: SQLiteViewが読み取り専用から、INSERT、UPDATE、DELETE、CREATE、DROPなどの書き込みSQLステートメントを実行できるSQLクライアントに拡張されました。
  • データベース層の機能強化: database.pyにおいて、読み取り専用の制限が削除され、クエリ結果にaffected_rowsis_write_operationが追加されました。また、クエリを分類する_classify_query()と、破壊的な操作を検出するis_destructive_query()が導入されました。
  • UIの改善と安全性: mainwindow.pyでは、書き込み操作の結果表示(例: 「N行が影響を受けました」)、破壊的なクエリに対する確認ダイアログ、DDL/DML後のUIの自動リフレッシュ、およびテーブル選択の復元機能が実装されました。
  • SQLハイライトの拡張: sql_highlighter.pyに、INSERT、UPDATE、DELETE、CREATE、DROP、BEGIN、COMMIT、ROLLBACKなどの約50の書き込み関連キーワードが追加され、シンタックスハイライトが強化されました。
  • 包括的なテストカバレッジ: tests/test_database.pyに、INSERT、DELETE、DDL、トランザクション、クエリ分類、破壊的操作検出など、書き込み操作に関する新しいテストが追加され、すべてのテストがパスしています。

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • PLAN.md
    • SQLiteViewに書き込みサポートを追加するための計画を概説する新しいファイルが追加されました。
  • src/sqliteviewer/database.py
    • ドキュメント文字列が更新されました。
    • 読み取り、DML、DDL、TCLのキーワードセットが定義されました。
    • QueryResultデータクラスにaffected_rowsis_write_operationフィールドが追加されました。
    • DatabaseServiceのドキュメント文字列が更新されました。
    • execute_queryメソッドが書き込み操作を処理するように変更され、_assert_read_onlyの呼び出しが削除されました。
    • SQLステートメントを分類する_classify_queryメソッドが追加されました。
    • 潜在的に破壊的なクエリ(DROPやWHERE句のないDELETEなど)を検出するis_destructive_queryメソッドが追加されました。
    • _assert_read_onlyメソッドが削除されました。
  • src/sqliteviewer/mainwindow.py
    • クエリエディタのプレースホルダーテキストが「Write a read-only SQL query…」から「Write a SQL statement…」に更新されました。
    • _refresh_tablesメソッドが、テーブルリストをリフレッシュする前に現在選択されているテーブルを記憶し、リフレッシュ後に復元するように変更されました。
    • _run_queryメソッドが、破壊的なクエリの実行前に確認ダイアログを表示し、書き込み操作の結果(影響を受けた行数など)を処理するように変更されました。
    • 書き込み操作後にUIパネル(テーブルリスト、プレビュー、スキーマ)を自動的にリフレッシュする_refresh_after_writeメソッドが追加されました。
    • Aboutダイアログのバージョンが0.1.0から0.2.1に、説明が「A lightweight desktop viewer for SQLite databases.」から「A lightweight desktop client for SQLite databases.」に更新されました。
  • src/sqliteviewer/sql_highlighter.py
    • SQLキーワードのセットが拡張され、DML(INSERT, UPDATE, DELETEなど)、DDL(CREATE, ALTER, DROPなど)、TCL(BEGIN, COMMIT, ROLLBACKなど)、およびその他の関連キーワードや型名が追加されました。
  • tests/test_database.py
    • test_execute_query_restricts_writesテストがtest_execute_query_allows_writesに置き換えられ、書き込み操作が許可されることを検証するようになりました。
    • 新しいユーザーを挿入するtest_execute_query_insertテストが追加されました。
    • 既存のユーザーを削除するtest_execute_query_deleteテストが追加されました。
    • テーブルの作成と削除を検証するtest_execute_query_ddl_create_dropテストが追加されました。
    • トランザクションのロールバックを検証するtest_execute_query_transaction_rollbackテストが追加されました。
    • SQLクエリの分類機能を検証するtest_classify_queryテストが追加されました。
    • 破壊的なクエリの検出機能を検証するtest_is_destructive_queryテストが追加されました。
Activity
  • プルリクエストの作成者であるkwrkbが、SQLiteViewに書き込みサポートを追加する変更を実装しました。
  • 変更の概要、テスト計画、および実装状況に関する詳細な説明がプルリクエストの本文に提供されています。
  • すべてのユニットテストがパスしていることが確認されています。
  • Claude Codeを使用して、プルリクエストの説明の一部が生成されました。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

このプルリクエストは、SQLiteViewに書き込み機能を追加するための重要な変更を含んでいます。データベース層での書き込み許可、UIでの書き込み結果の表示や破壊的クエリの警告、SQLハイライトのキーワード追加など、多岐にわたる改善が行われています。全体として、機能追加は計画通りに進んでいるように見えます。いくつか改善点を提案します。まず、database.pyの破壊的クエリ検出ロジックには、コメントによってバイパスされる可能性がある脆弱性が存在します。次に、mainwindow.pyでは、カプセル化の原則に反するプライベートメソッドの呼び出しや、DML後のUI更新ロジックの堅牢性に改善の余地があります。最後に、ドキュメント内のコマンド例も、より汎用的にすると良いでしょう。これらの点を修正することで、より安全で保守性の高いコードになるでしょう。

Comment on lines +173 to +175
upper = sql.upper()
if "WHERE" not in upper:
return True, "DELETE without WHERE will remove all rows."
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

DELETE 文の WHERE 句の有無をチェックするロジックが、SQLコメント内に WHERE キーワードが含まれている場合に正しく機能しません。これにより、意図せずテーブルの全行が削除される危険な操作を許可してしまう可能性があります。

例えば、DELETE FROM users -- WHERE id = 1 のようなクエリは、コメント内に WHERE があるため安全と誤判定されますが、実際には全行を削除します。

この問題を解決するには、WHERE の存在をチェックする前に、SQLクエリからコメントを削除する処理を追加することを強く推奨します。正規表現や簡単なパーサーを実装することで、より堅牢なチェックが可能になります。

PLAN.md Outdated

```bash
# ユニットテスト実行
cd /home/yugosasaki/code/SQLiteView && uv run python -m pytest tests/ -v
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

コマンド例に、ハードコードされたユーザー固有の絶対パス(/home/yugosasaki/code/SQLiteView)が含まれています。これにより、他の開発者がコマンドを直接コピー&ペーストして使用することができません。プロジェクトのルートディレクトリからコマンドを実行するように指示するか、cd部分を削除してコマンドをシンプルにすることを推奨します。

Suggested change
cd /home/yugosasaki/code/SQLiteView && uv run python -m pytest tests/ -v
uv run python -m pytest tests/ -v

def _refresh_after_write(self, sql: str) -> None:
"""Refresh UI panels after a write operation."""

query_type = self.database_service._classify_query(sql)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

DatabaseService のプライベートメソッドである _classify_query (アンダースコアで始まる)を MainWindow から直接呼び出しています。これはカプセル化の原則に違反し、DatabaseService の内部実装の変更が MainWindow に影響を与える可能性があるため、コードの保守性を低下させます。

_classify_queryDatabaseService の公開APIの一部として意図されている場合は、メソッド名を classify_query に変更して公開メソッドにすることを検討してください。

Suggested change
query_type = self.database_service._classify_query(sql)
query_type = self.database_service.classify_query(sql)

selected_items = self.table_list.selectedItems()
if selected_items:
table_name = selected_items[0].text()
if table_name.lower() in sql.lower():
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

DML操作後にデータプレビューを更新する現在のロジックは、単純な部分文字列チェック(table_name.lower() in sql.lower())に依存しています。このアプローチは堅牢ではなく、以下のような場合に意図しない動作を引き起こす可能性があります。

  • テーブルがエイリアスで参照されている場合に更新されない。
  • SQLクエリ内の文字列リテラルやコメントにテーブル名が含まれている場合に誤って更新される。
  • 別のテーブルへの操作にもかかわらず、選択中のテーブル名がクエリ内に偶然含まれている場合に誤って更新される。

より信頼性の高いアプローチとして、SQLを簡易的に解析して、操作対象のテーブル名をより正確に特定することを検討してください。例えば、正規表現を用いて INSERT / UPDATE / DELETE 文からテーブル名を抽出する方法が考えられます。

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b064d2d16

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +282 to +283
if result.is_write_operation:
self.query_result_view.setModel(None)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reset cached query results after write statements

When a write statement succeeds, _run_query clears only the table view model but leaves self.query_result untouched. If the user previously ran a SELECT, then runs INSERT/UPDATE/DELETE, the UI shows no result rows yet Export Results still exports the old SELECT dataset from memory, which can silently produce incorrect exports.

Useful? React with 👍 / 👎.

Comment on lines +173 to +174
upper = sql.upper()
if "WHERE" not in upper:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Detect full-table DELETEs using parsed SQL, not text search

The destructive-query guard decides whether a DELETE is safe by checking if the raw SQL text contains the substring WHERE, so comments or string literals can bypass the warning (for example, DELETE FROM users /* WHERE id=1 */ still deletes all rows but will not trigger confirmation). This weakens the new safety prompt and can lead to accidental data loss for users relying on it.

Useful? React with 👍 / 👎.

- CIエラー修正: build_deb.sh のパッケージ名を sqliteviewer→sqliteview、
  バージョンを 0.1.0→0.2.1 に更新し、control/実行ファイルにも変数を使用
- セキュリティ修正: DELETE の WHERE チェック前に SQL コメントを除去する
  _strip_sql_comments() を追加し、コメントによるバイパスを防止
- バグ修正: write 操作後に self.query_result を None にリセットし、
  古い SELECT 結果が Export で誤出力されないよう修正
- カプセル化改善: _classify_query を classify_query に公開化し、
  MainWindow からの呼び出しを適切な公開 API 経由に変更
- ドキュメント改善: PLAN.md のハードコードパスを削除

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kwrkb kwrkb merged commit 361e7dc into main Feb 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant