You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
king/data/NotesDatabaseHelper.java

477 lines
20 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// 包声明,表明该类属于 net.micode.notes.data 包
package net.micode.notes.data;
// 导入用于存储键值对,通常用于数据库操作中插入数据
import android.content.ContentValues;
// 导入 Android 上下文类,用于获取应用程序的环境信息
import android.content.Context;
// 导入 SQLite 数据库操作类,用于对数据库进行读写操作
import android.database.sqlite.SQLiteDatabase;
// 导入 SQLite 数据库辅助类,用于管理数据库的创建和版本更新
import android.database.sqlite.SQLiteOpenHelper;
// 导入日志工具类,用于在开发和调试过程中记录信息
import android.util.Log;
// 导入 Notes 类中的 DataColumns 接口,用于引用数据列的常量
import net.micode.notes.data.Notes.DataColumns;
// 导入 Notes 类中的 DataConstants 类,用于引用数据相关的常量
import net.micode.notes.data.Notes.DataConstants;
// 导入 Notes 类中的 NoteColumns 接口,用于引用笔记列的常量
import net.micode.notes.data.Notes.NoteColumns;
/**
* NotesDatabaseHelper 类继承自 SQLiteOpenHelper用于管理笔记应用的 SQLite 数据库。
* 它负责创建数据库、表,以及处理数据库版本升级等操作。
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 数据库文件名
private static final String DB_NAME = "note.db";
// 数据库版本号
private static final int DB_VERSION = 4;
/**
* TABLE 接口定义了数据库中表的名称常量
*/
public interface TABLE {
// 笔记表的名称
public static final String NOTE = "note";
// 数据表的名称
public static final String DATA = "data";
}
// 日志标签,用于在日志中标识该类的信息
private static final String TAG = "NotesDatabaseHelper";
// 单例模式下的实例对象
private static NotesDatabaseHelper mInstance;
// 创建笔记表的 SQL 语句
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
// 创建数据表的 SQL 语句
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA1 + " INTEGER," +
DataColumns.DATA2 + " INTEGER," +
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";
// 创建数据表中 note_id 索引的 SQL 语句
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL =
"CREATE INDEX IF NOT EXISTS note_id_index ON " +
TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";
/**
* 当笔记移动到文件夹时,增加文件夹的笔记数量的触发器 SQL 语句
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_update "+
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* 当笔记从文件夹移出时,减少文件夹的笔记数量的触发器 SQL 语句
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_update " +
" AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0" + ";" +
" END";
/**
* 当新笔记插入到文件夹时,增加文件夹的笔记数量的触发器 SQL 语句
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER =
"CREATE TRIGGER increase_folder_count_on_insert " +
" AFTER INSERT ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" +
" WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" +
" END";
/**
* 当笔记从文件夹删除时,减少文件夹的笔记数量的触发器 SQL 语句
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER =
"CREATE TRIGGER decrease_folder_count_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN " +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" +
" WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID +
" AND " + NoteColumns.NOTES_COUNT + ">0;" +
" END";
/**
* 当插入类型为 {@link DataConstants#NOTE} 的数据时,更新笔记内容的触发器 SQL 语句
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER =
"CREATE TRIGGER update_note_content_on_insert " +
" AFTER INSERT ON " + TABLE.DATA +
" WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* 当类型为 {@link DataConstants#NOTE} 的数据更新时,更新笔记内容的触发器 SQL 语句
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER =
"CREATE TRIGGER update_note_content_on_update " +
" AFTER UPDATE ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT +
" WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" +
" END";
/**
* 当类型为 {@link DataConstants#NOTE} 的数据删除时,更新笔记内容的触发器 SQL 语句
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER =
"CREATE TRIGGER update_note_content_on_delete " +
" AFTER delete ON " + TABLE.DATA +
" WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.SNIPPET + "=''" +
" WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" +
" END";
/**
* 当笔记删除时,删除该笔记关联的数据的触发器 SQL 语句
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER =
"CREATE TRIGGER delete_data_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.DATA +
" WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 当文件夹删除时,删除该文件夹下的所有笔记的触发器 SQL 语句
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER =
"CREATE TRIGGER folder_delete_notes_on_delete " +
" AFTER DELETE ON " + TABLE.NOTE +
" BEGIN" +
" DELETE FROM " + TABLE.NOTE +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 当文件夹移动到回收站时,将该文件夹下的所有笔记也移动到回收站的触发器 SQL 语句
*/
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER =
"CREATE TRIGGER folder_move_notes_on_trash " +
" AFTER UPDATE ON " + TABLE.NOTE +
" WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" BEGIN" +
" UPDATE " + TABLE.NOTE +
" SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER +
" WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" +
" END";
/**
* 构造函数,用于初始化 NotesDatabaseHelper 实例
* @param context 应用程序上下文
*/
public NotesDatabaseHelper(Context context) {
// 调用父类 SQLiteOpenHelper 的构造函数,传入上下文、数据库名、游标工厂和数据库版本号
super(context, DB_NAME, null, DB_VERSION);
}
/**
* 创建笔记表,并设置相关触发器和创建系统文件夹
* @param db SQLite 数据库对象
*/
public void createNoteTable(SQLiteDatabase db) {
// 执行创建笔记表的 SQL 语句
db.execSQL(CREATE_NOTE_TABLE_SQL);
// 重新创建笔记表的触发器
reCreateNoteTableTriggers(db);
// 创建系统文件夹
createSystemFolder(db);
// 记录日志,表明笔记表已创建
Log.d(TAG, "note table has been created");
}
/**
* 重新创建笔记表的触发器
* @param db SQLite 数据库对象
*/
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
// 删除旧的触发器
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");
// 创建新的触发器
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
/**
* 创建系统文件夹,如通话记录文件夹、根文件夹、临时文件夹和回收站文件夹
* @param db SQLite 数据库对象
*/
private void createSystemFolder(SQLiteDatabase db) {
// 用于存储要插入的数据
ContentValues values = new ContentValues();
/**
* 创建通话记录文件夹
*/
// 设置文件夹的 ID
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
// 设置文件夹的类型为系统文件夹
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
// 插入数据到笔记表
db.insert(TABLE.NOTE, null, values);
/**
* 创建根文件夹
*/
// 清空之前存储的数据
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* 创建临时文件夹
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* 创建回收站文件夹
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
/**
* 创建数据表,并设置相关触发器和创建索引
* @param db SQLite 数据库对象
*/
public void createDataTable(SQLiteDatabase db) {
// 执行创建数据表的 SQL 语句
db.execSQL(CREATE_DATA_TABLE_SQL);
// 重新创建数据表的触发器
reCreateDataTableTriggers(db);
// 执行创建数据表中 note_id 索引的 SQL 语句
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
// 记录日志,表明数据表已创建
Log.d(TAG, "data table has been created");
}
/**
* 重新创建数据表的触发器
* @param db SQLite 数据库对象
*/
private void reCreateDataTableTriggers(SQLiteDatabase db) {
// 删除旧的触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");
// 创建新的触发器
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}
/**
* 获取 NotesDatabaseHelper 的单例实例
* @param context 应用程序上下文
* @return NotesDatabaseHelper 实例
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
// 检查实例是否为空
if (mInstance == null) {
// 如果为空,则创建新的实例
mInstance = new NotesDatabaseHelper(context);
}
// 返回实例
return mInstance;
}
/**
* 当数据库第一次创建时调用,用于创建笔记表和数据表
* @param db SQLite 数据库对象
*/
@Override
public void onCreate(SQLiteDatabase db) {
// 创建笔记表
createNoteTable(db);
// 创建数据表
createDataTable(db);
}
/**
* 当数据库版本升级时调用,根据旧版本和新版本进行相应的升级操作
* @param db SQLite 数据库对象
* @param oldVersion 旧的数据库版本号
* @param newVersion 新的数据库版本号
*/
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// 标记是否需要重新创建触发器
boolean reCreateTriggers = false;
// 标记是否跳过从版本 2 到版本 3 的升级
boolean skipV2 = false;
// 如果旧版本是 1
if (oldVersion == 1) {
// 升级到版本 2
upgradeToV2(db);
// 标记跳过从版本 2 到版本 3 的升级
skipV2 = true;
// 旧版本号加 1
oldVersion++;
}
// 如果旧版本是 2 且不跳过升级
if (oldVersion == 2 && !skipV2) {
// 升级到版本 3
upgradeToV3(db);
// 标记需要重新创建触发器
reCreateTriggers = true;
oldVersion++;
}
// 如果旧版本是 3
if (oldVersion == 3) {
// 升级到版本 4
upgradeToV4(db);
oldVersion++;
}
// 如果需要重新创建触发器
if (reCreateTriggers) {
// 重新创建笔记表的触发器
reCreateNoteTableTriggers(db);
// 重新创建数据表的触发器
reCreateDataTableTriggers(db);
}
// 如果旧版本号不等于新版本号,说明升级失败,抛出异常
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
/**
* 将数据库从版本 1 升级到版本 2
* @param db SQLite 数据库对象
*/
private void upgradeToV2(SQLiteDatabase db) {
// 删除旧的笔记表
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
// 删除旧的数据表
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
// 创建新的笔记表
createNoteTable(db);
// 创建新的数据表
createDataTable(db);
}
/**
* 将数据库从版本 2 升级到版本 3
* @param db SQLite 数据库对象
*/
private void upgradeToV3(SQLiteDatabase db) {
// 删除无用的触发器
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
// 为笔记表添加 gtask_id 列
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
// 创建回收站系统文件夹
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
/**
* 将数据库从版本 3 升级到版本 4
* @param db SQLite 数据库对象
*/
private void upgradeToV4(SQLiteDatabase db) {
// 为笔记表添加 version 列
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
}