Всем привет!
Выдалось тут внезапно немного свободного времени и поюзал я SQLite3 и класс SQLiteType, что ВЧ поделился.
Вот и я решил от нечего делать (лежу на койке) поделиться своим опытом. Может кому пригодится.
Как я уже писал, оригинальный класс оставляет желать лучшего в части работы с кодовыми страницами.
Поэтому первая доработка касалась этого момента.
Я добавил в оригинальную декларацию свойство
CodePage Long
, объявил константу
CP_1251 EQUATE(1251)
, заменил в clw в коде методов CP_ACP на Self.CodePage, и добавил в конструктор инициализацию:
Self.CodePage = CP_1251
Все прекрасно заработало без привлечения Cstr. Есть только один момент.
При открытии БД (метод SQLiteType.OpenDB Procedure(String pDBName))
делается преобразование имени файла в UTF-8
Self.ACPtoUTF8(Self.DBName)
По видимому, это нужно для SQLite3.dll. И вот тут возникает ошибка если в спецификации файла есть кириллица.
Обнаружил случайно, и за ненадобностью, не копался.
Дальнейшую адаптацию SQLiteType к своим нуждам делал, как и всегда, через наследование.
Собственно, в работе с БД я придерживаюсь следующей идеи.
Базовый класс обеспечивает проблемно независимые операции, как-то, подключение и выполнение SQL DDL/DML.
А всю проблемную специфику (структура БД, проблемно ориентированные запросы,...) я локализую в наследном классе.
В этом смысле SQLiteType меня вполне устроил. Но тут всплыла еще одна грабля исходного кода.
В нем все константы определены в clw и нигде кроме этого clw не видны. Ес-но, я перенес все определения констант в inc.
Еще пара замечаний.
Для того, чтобы собрать класс в отдельную dll и пользовать его из dll, необходимо в декларацию класса добавить атрибут DLL и соответствующие параметы.
Перед выполнением операций не использующих SQL, свойство класса SQL лучше очистить, иначе могут возникать странные ошибки в SQLite3.
Именно поэтому у меня в SchLiteClass.CreateDB стоит:
self.SQL = ''
IF ~self.OpenDB(DBFile)
Фрагментарно мой наследный класс выглядит следующим образом:
schlite.inc:
============
OMIT('_EndOfInclude_',_SchLitePresent_)
_SchLitePresent_ EQUATE(1)
INCLUDE('SQLite.inc'),ONCE
SchLiteClass CLASS(SQLiteType),TYPE,MODULE('SchLite.clw'),LINK('SchLite.clw')
GetTableNums PROCEDURE(),LONG
GetTableName PROCEDURE(LONG Ind),STRING
GetTableDescription PROCEDURE(LONG Ind),STRING
CreateDB PROCEDURE(STRING DBFile),LONG
DropTables PROCEDURE(),LONG
CreateTables PROCEDURE(),LONG
CreateView PROCEDURE(),LONG
ExecSQL PROCEDURE(LONG TableInd),LONG
PrepareString PROCEDURE(STRING Text),STRING
InsertDay PROCEDURE(SHORT DaySeqNumber,STRING DayName),LONG
InsertLessonBell PROCEDURE(STRING LessonNo, STRING Begining, STRING Ending),LONG
! 8< Skip >8
END
_EndOfInclude_
schlite.clw:
============
Member
MAP
END
Include ('SchLite.inc')
!------------ Константы для БД Расписание 2000 ------------!
! NB. Таблицы д.б. перечислены в порядке их создания. Порядок их уничтожения будет обратный.
TableNameGroup GROUP
Days STRING('Учебные дни ')
LessonBell STRING('Звонки ')
! 8< Skip >8
END
TableName STRING(20),DIM(14),OVER(TableNameGroup)
TableGroup GROUP
STRING('Days ')
STRING('LessonBell ')
! 8< Skip >8
END
Tables STRING(12),DIM(14),OVER(TableGroup)
DropTable STRING('DROP TABLE IF EXISTS ')
DropView STRING('DROP VIEW IF EXISTS ')
Insert STRING('INSERT INTO ')
CreateDays STRING('CREATE TABLE Days (' |
& 'SeqNumber INTEGER PRIMARY KEY NOT NULL UNIQUE,' |
& 'Name TEXT NOT NULL' |
& ');')
CreateLessonBell STRING('CREATE TABLE LessonBell (' |
& 'LessonNo TEXT PRIMARY KEY NOT NULL UNIQUE,' |
& 'Begining TEXT NOT NULL,' |
& 'Ending TEXT NOT NULL' |
& ');')
! 8< Skip >8
!------------ SchLiteClass ------------!
SchLiteClass.GetTableNums PROCEDURE()
CODE
RETURN MAXIMUM(Tables,1)
SchLiteClass.GetTableName PROCEDURE(LONG Ind)
CODE
IF INRANGE(Ind, 1, MAXIMUM(Tables,1))
RETURN CLIP(Tables[Ind])
ELSE
RETURN ''
END
SchLiteClass.GetTableDescription PROCEDURE(LONG Ind)
CODE
IF INRANGE(Ind, 1, MAXIMUM(TableName,1))
RETURN CLIP(TableName[Ind])
ELSE
RETURN ''
END
SchLiteClass.PrepareString PROCEDURE(STRING Text)
ReturnValue ANY
CODE
ReturnValue = ''
j# = 0
LOOP i# = 1 TO LEN(CLIP(Text))
ReturnValue = SUB(ReturnValue & '', 1, j#) & Text[i#]
j# += 1
IF Text[i#] = ''''
ReturnValue = SUB(ReturnValue & '', 1, j#) & ''''
j# += 1
END
END
RETURN '''' & CLIP(ReturnValue & '') & ''''
SchLiteClass.CreateDB PROCEDURE(STRING DBFile)
CODE
IF EXISTS(DBFile)
IF self.hSQLite
self.CloseDB()
END
REMOVE(DBFile)
END
self.SQL = ''
IF ~self.OpenDB(DBFile)
MESSAGE('Ошибка открытия базы данных ' & DBFile & ' - ' & self.ReturnCodeMsg(self.LastReturnCode), 'SchLiteClass.CreateDB')
Return self.LastReturnCode
END
RETURN SQLITE_OK
SchLiteClass.DropTables PROCEDURE()
ind LONG
CODE
LOOP ind = MAXIMUM(Tables,1) TO 1 BY -1
self.SQL = DropTable & CLIP(Tables[ind]) & ';'
OK# = self.Exec()
IF ~OK#
MESSAGE('Ошибка уничтожения старой таблицы ' & CLIP(Tables[ind]) & ': ' & self.ReturnCodeMsg(self.LastReturnCode), 'SchLiteClass.CreateDB')
self.CloseDB()
RETURN self.LastReturnCode
END
END
RETURN SQLITE_OK
SchLiteClass.CreateTables PROCEDURE()
ind LONG
CODE
self.TablesProgressControl{PROP:RangeHigh} = MAXIMUM(Tables,1)
LOOP ind = 1 TO MAXIMUM(Tables,1)
IF self.CurrentTableControl > 0 THEN self.CurrentTableControl{PROP:Text} = self.GetTableDescription(ind) .
IF self.TablesProgressControl > 0 THEN self.TablesProgressControl{PROP:Progress} = ind .
DISPLAY
EXECUTE ind
self.SQL = CreateDays
self.SQL = CreateLessonBell
! 8< Skip >8
ELSE
BREAK
END
IF ~self.Exec()
MESSAGE('Ошибка создания таблицы ' & CLIP(Tables[ind]) & ': ' & self.ReturnCodeMsg(self.LastReturnCode), 'SchLiteClass.CreateDB')
self.CloseDB()
RETURN self.LastReturnCode
END
END
RETURN SQLITE_OK
SchLiteClass.ExecSQL PROCEDURE(LONG TableInd)
CODE
IF ~self.Exec()
MESSAGE('Ошибка операции с таблицей ' & self.GetTableDescription(TableInd) & ': ' & self.ReturnCodeMsg(self.LastReturnCode), 'SchLiteClass.CreateDB')
self.CloseDB()
RETURN self.LastReturnCode
END
RETURN SQLITE_OK
SchLiteClass.InsertDay PROCEDURE(SHORT DaySeqNumber, STRING DayName)
CODE
self.SQL = Insert & CLIP(Tables[1]) & ' (SeqNumber, Name) VALUES (' |
& DaySeqNumber & ', ' & self.PrepareString(DayName) |
& ');'
RETURN self.ExecSQL(1)
SchLiteClass.InsertLessonBell PROCEDURE(STRING LessonNo, STRING Begining, STRING Ending)
CODE
self.SQL = Insert & CLIP(Tables[2]) & ' (LessonNo, Begining, Ending) VALUES (' |
& self.PrepareString(LessonNo) & ', ' & self.PrepareString(Begining) & ', ' & self.PrepareString(Ending) |
& ');'
RETURN self.ExecSQL(2)
! 8< Skip >8