SQLite 报 col -1 和 no such column,用 TaoToken 让 Codex 查行不行
1. 从一次 Android SQLite 查询崩溃说起Couldnt read row 0, col -1 from CursorWindow和no such column: xxx这两个报错几乎是每个写 Android 本地数据库的人都会撞上的坎。它们的共同点是建表、插数据全都正常偏偏一到getAllUsers()这种查询方法就炸。更让人迷惑的是把.db文件导出来用工具打开肉眼看着字段明明没问题可代码就是读不到。这个场景的核心矛盾在于cursor.getColumnIndex(name)返回的是-1而-1被直接传给了getString()于是 CursorWindow 在读取第 0 行第 -1 列时直接抛异常。换句话说报错本身不是数据库坏了而是代码里的字段名和表结构里的字段名对不上。原文作者第二天才发现表里叫name代码里写的是username改完就好了——但整个过程靠的是反复导出 db 文件人工比对效率很低。这篇就按排障视角来写怎么用 TaoToken 给 Codex 配一条请求通道把报错堆栈和建表语句一起丢给它让它帮你逐项核对字段名把「导出 db 文件肉眼比对」这一步省掉。需要先说清楚TaoToken 只负责 Codex 的请求通道SQLite 查数据、改代码仍然在你本地完成它不碰你的数据库。适合谁看正在写 Android SQLite、被col -1或no such column卡住、又不想每次都手动导库核对字段的开发者。下面从环境准备讲到可复制配置再到验证和排错尽量让你跟着做就能跑通。2. 用 TaoToken 给 Codex 配一条请求通道在动手改 SQLite 代码之前先把 Codex 的请求通道配好。这一步的目的很简单让 Codex 能正常收发请求你才能把报错贴进去让它分析。TaoToken 在这里扮演的角色就是 Codex 的 Base URL 提供方不参与你本地的数据库操作。先打开 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_end 注册并创建一个 API Key。创建入口在控制台的 API Keys 页面直接访问 https://taotoken.net/api-keys 也能到。Key 生成后复制保存后面配置要用。这里有个容易踩的坑Base URL 填https://taotoken.net/api不要加/v1。很多人习惯性补上/v1结果请求路径拼出来是/api/v1/...直接 404。Codex 这类工具在内部会自己拼接具体路径你只需要给到/api这一层。配置项对照如下配置项填写值说明Base URLhttps://taotoken.net/api结尾不加/v1不加斜杠API Key控制台创建的 Key形如sk-开头的一串Model按 Codex 要求填具体模型名以文档为准如果你用的是 Claude Code 这类 Anthropic 风格的客户端接入方式略有不同可以参考 https://taotoken.net/doc 里的说明或者直接看 ClaudeCodeAnthropic 对应的配置页。核心逻辑一样Base URL 指向 TaoTokenKey 用你创建的那把。配好之后先别急着贴 SQLite 报错先确认通道是通的。下一节给可复制的配置和验证方法。3. 可复制配置Codex 接入与字段核对流程3.1 Codex 侧的环境变量配置Codex 一般通过环境变量读取 Base URL 和 Key。在终端里这样设置Linux/macOSexport OPENAI_BASE_URLhttps://taotoken.net/api export OPENAI_API_KEYsk-你的KeyWindows PowerShell 用$env:OPENAI_BASE_URLhttps://taotoken.net/api $env:OPENAI_API_KEYsk-你的Key设置完可以用echo $OPENAI_BASE_URL确认一下确保结尾没有多余的/v1或斜杠。这一步看着简单但实际排障里有一半的「连不上」都是这里多写了路径。3.2 把报错和建表语句整理成一段可分析的输入通道通了之后关键是把信息给全。Codex 要判断col -1的根因至少需要三样东西完整的报错堆栈、建表 SQL、出问题的查询代码。整理成下面这种格式贴进去报错 android.database.CursorWindowAllocationException: Couldnt read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it. at android.database.CursorWindow.nativeGetString(Native Method) at android.database.CursorWindow.getString(CursorWindow.java:438) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51) at com.example.app.UserDao.getAllUsers(UserDao.java:42) 建表语句 CREATE TABLE user ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, password TEXT ); 查询代码 Cursor cursor sqLiteDatabase.query(user, null, null, null, null, null, name); while (cursor.moveToNext()) { String username cursor.getString(cursor.getColumnIndex(name)); String password cursor.getString(cursor.getColumnIndex(password)); users.add(new User(username, password)); }贴的时候注意建表语句里的字段名要和实际数据库一致别凭记忆写。如果你不确定表结构可以在代码里临时加一句打印把cursor.getColumnNames()的结果也贴进去这样 Codex 能直接看到真实字段列表。3.3 让 Codex 逐项核对字段名把上面这段发给 Codex 后可以明确要求它做字段比对比如加一句「请对比建表语句字段和查询代码里用到的字段名列出不一致的地方」。它通常会输出类似这样的结论建表字段是name查询里getColumnIndex(name)是对的但变量名叫username容易误导如果查询里写的是getColumnIndex(username)那就会返回 -1。这一步的价值在于它把「导出 db 文件、用工具打开、肉眼找字段」变成了「贴文本、让它比对」。你不需要离开编辑器也不需要装额外的数据库查看工具。3.4 本地修正与防御性写法拿到比对结果后回到本地改代码。除了改对字段名建议加一层防御避免以后再出现-1直接传给getString()int nameIndex cursor.getColumnIndex(name); if (nameIndex -1) { Log.e(UserDao, 字段 name 不存在请检查表结构); return users; } String username cursor.getString(nameIndex);这样即使字段名又写错日志里会明确告诉你哪个字段找不到而不是抛一个让人摸不着头脑的col -1。另外原文提到「SQL 语句尽量大写」这个习惯本身没问题但要注意字段名的大小写在 SQLite 里通常不敏感真正敏感的是你代码里getColumnIndex传的字符串要和建表时一致。大写关键字是风格问题字段名一致才是根因。4. 验证请求确认通道通、字段对配置改完后分两步验证。第一步验证 Codex 通道。在终端里发一个最小请求确认能拿到返回curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d { model: 按文档填写的模型名, messages: [{role: user, content: ping}] }注意这里的路径是/api/v1/chat/completions是因为 curl 手动拼了完整路径而你在 Codex 里配置 Base URL 时只填https://taotoken.net/api剩下的由 Codex 自己拼。这两者不矛盾别混淆。如果返回里带choices字段说明通道正常。第二步验证字段核对结果。改完代码后重新跑getAllUsers()观察日志。正常情况下不再出现col -1users列表能拿到数据。如果还想更稳可以在查询前打印一次真实字段名Cursor cursor sqLiteDatabase.rawQuery(SELECT * FROM user LIMIT 1, null); String[] cols cursor.getColumnNames(); for (String c : cols) { Log.d(UserDao, 真实字段: c); } cursor.close();把打印出来的字段名和你代码里getColumnIndex用的字符串对一遍一致就说明修对了。这一步比导出 db 文件快得多而且不用离开 IDE。5. 本篇常见错排查排障过程中下面这几个错误出现频率最高逐个说清楚。错误一Base URL 多写了/v1。现象是请求 404 或路径拼接异常。原因前面说过Codex 会自己拼路径你给到/api就行。检查方法echo $OPENAI_BASE_URL确认结尾是/api而不是/api/v1。错误二Key 没生效或复制时带了空格。现象是 401。检查方法重新从 https://taotoken.net/api-keys 复制一次注意别把首尾空格带进去。环境变量设置后最好新开一个终端窗口再试。错误三getColumnIndex返回 -1 但没判断。这是col -1的直接来源。防御写法见 3.4 节。记住getColumnIndex找不到字段时返回 -1不会抛异常异常是在getString(-1)时才抛的。错误四表结构和代码字段名不一致但导出 db 文件看着「没问题」。这是原文作者踩的坑。原因是导出工具可能对字段做了显示处理或者你看的是另一张表。最可靠的办法是在代码里打印getColumnNames()以运行时的真实字段为准。错误五no such column出现在 rawQuery 里。这种通常是 SQL 字符串里字段名拼错或者表名写错。把完整的 rawQuery 字符串和建表语句一起贴给 Codex让它逐字比对比你自己盯着看快。错误六改了字段名但没重新安装 App。SQLite 数据库文件在 App 首次创建时就固定了如果你改了建表语句但没卸载重装旧库还在字段还是旧的。排障时先卸载 App 再跑或者手动删掉数据库文件。6. 把通道和排障流程固定下来走到这里col -1和no such column的处理链路已经完整了TaoToken 提供 Codex 的请求通道你把报错、建表语句、查询代码贴进去让它逐项核对字段名本地改完加防御判断再验证。几个可以固定下来的习惯Base URL 永远只写到https://taotoken.net/api每次改完表结构先卸载重装 AppgetColumnIndex的结果一定判 -1不确定字段名时先打印getColumnNames()。这几条做到这类报错基本不会再让你卡半天。如果你后面要长期用 Codex 做编码和 Agent 任务可以了解下 Coding Plan路径更省心只是偶尔查个报错用 API Keys 加接入文档就够了。模型对话入口适合快速验证模型是否正常接入文档则把各种客户端的配置都列全了。按自己的使用频率选就行。