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.
xm_g/NotesDatabaseHelper.java

413 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.
*/
package net.micode.notes.data;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
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";
}
// 用于日志输出的标签方便在Logcat中查看该类相关的日志信息
private static final String TAG = "NotesDatabaseHelper";
// 采用单例模式,保存该类的唯一实例
private static NotesDatabaseHelper mInstance;
// 创建note表的SQL语句
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +
// 父级笔记的ID默认值为0表示没有父级
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
// 提醒日期默认值为0表示没有设置提醒
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +
// 背景颜色ID默认值为0
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +
// 创建日期,默认值为当前时间(以特定格式转换后的时间戳)
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
// 是否有附件默认值为0表示没有附件
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +
// 修改日期,默认值为当前时间(以特定格式转换后的时间戳)
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +
// 该笔记下的子笔记数量默认值为0
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +
// 笔记的摘要内容,默认值为空字符串
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +
// 笔记类型默认值为0
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +
// 小部件ID默认值为0
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +
// 小部件类型,默认值为 -1
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +
// 同步ID默认值为0
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +
// 本地是否修改默认值为0
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +
// 原始父级ID默认值为0
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +
// 与GTask相关的ID默认值为空字符串
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +
// 版本号默认值为0
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +
")";
// 创建data表的SQL语句用于存储笔记相关的具体数据信息
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +
// 数据的MIME类型不能为空
DataColumns.MIME_TYPE + " TEXT NOT NULL," +
// 关联的笔记ID默认值为0表示未关联笔记
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 ''," +
// 额外的数据字段1可为空整数类型
DataColumns.DATA1 + " INTEGER," +
// 额外的数据字段2可为空整数类型
DataColumns.DATA2 + " INTEGER," +
// 额外的数据字段3默认值为空字符串
DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," +
// 额外的数据字段4默认值为空字符串
DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," +
// 额外的数据字段5默认值为空字符串
DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" +
")";
// 创建基于data表中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语句定义用于实现特定的数据操作逻辑关联和自动化处理
* 当将笔记移动到文件夹时增加文件夹的笔记数量的触发器SQL语句
* 该触发器在更新note表的PARENT_ID字段后触发
*/
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语句
* 该触发器在更新note表的PARENT_ID字段后触发并且只有当文件夹的笔记数量大于0时才执行减少操作
*/
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语句
* 该触发器在向note表插入新记录后触发
*/
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语句
* 该触发器在从note表删除记录后触发并且只有当文件夹的笔记数量大于0时才执行减少操作
*/
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";
/**
* 当向data表插入类型为{@link DataConstants#NOTE}的数据时更新对应的笔记内容的触发器SQL语句
* 该触发器在向data表插入新记录后触发并且仅当插入的数据MIME类型是特定的笔记类型时执行更新操作
*/
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";
/**
* 当data表中类型为{@link DataConstants#NOTE}的数据发生更新时更新对应的笔记内容的触发器SQL语句
* 该触发器在更新data表记录后触发并且仅当更新前的数据MIME类型是特定的笔记类型时执行更新操作
*/
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";
/**
* 当从data表中删除类型为{@link DataConstants#NOTE}的数据时更新对应的笔记内容清空的触发器SQL语句
* 该触发器在从data表删除记录后触发并且仅当删除的数据MIME类型是特定的笔记类型时执行更新操作
*/
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";
/**
* 当从note表中删除笔记时删除该笔记关联的所有data表中的数据的触发器SQL语句
* 该触发器在从note表删除记录后触发
*/
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";
/**
* 当从note表中删除文件夹时删除该文件夹下所有笔记的触发器SQL语句
* 该触发器在从note表删除记录后触发
*/
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语句
* 该触发器在更新note表的PARENT_ID字段后触发并且仅当更新后的PARENT_ID是回收站文件夹的ID时执行移动操作
*/
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";
// 构造函数调用父类SQLiteOpenHelper的构造函数来初始化数据库相关信息传入上下文、数据库名称、游标工厂这里为null和数据库版本号
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
// 在给定的SQLiteDatabase对象中创建note表同时重新创建与note表相关的触发器、创建系统文件夹并输出日志表示note表已创建
public void createNoteTable(SQLiteDatabase db) {
// 执行创建note表的SQL语句
db.execSQL(CREATE_NOTE_TABLE_SQL);
// 重新创建与note表相关的触发器
reCreateNoteTableTriggers(db);
// 创建系统文件夹(此处方法未完整展示,推测是与数据库初始化相关的一些默认文件夹创建操作)
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
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);
}
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record foler for call notes
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* root folder which is default folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* temporary folder which is used for moving note
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* create trash folder
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
Log.d(TAG, "data table has been created");
}
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);
}
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
boolean reCreateTriggers = false;
boolean skipV2 = false;
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
}
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion
+ "fails");
}
}
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);
}
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
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");
// add a column for gtask id
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID
+ " TEXT NOT NULL DEFAULT ''");
// add a trash system folder
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);
}
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
}