Проект создан переработкой консольного приложения, описанного ранее. В связи с использованием модуля MySQL50 вместо MySQL4 внесены коррективы. База данных состоит из трёх простейших таблиц и предназначена для анализа семейного бюджета (расходы):
CREATE TABLE User ( ID INT UNSIGNED NOT NULL AUTO_INCREMENT, Name VARCHAR( 30 ) NOT NULL, Pass VARCHAR( 10 ) NOT NULL, PRIMARY KEY ( ID ) , UNIQUE (Name)) Позже было добавлено поле Foto - для хранения фотографий (при помощи запроса ALTER TABLE): ALTER TABLE User ADD COLUMN Foto MEDIUMBLOB NULL AFTER Pass CREATE TABLE RASXOD ( ID INT UNSIGNED NOT NULL AUTO_INCREMENT, KTO INT UNSIGNED NOT NULL, STAT INT UNSIGNED NOT NULL, Rasxod double(8,2) UNSIGNED NOT NULL, PRIMARY KEY ( id ) ) CREATE TABLE STAT ( ID INT UNSIGNED NOT NULL AUTO_INCREMENT, STAT VARCHAR( 40 ) NOT NULL , PRIMARY KEY ( id ) , UNIQUE (STAT))
1. Комментарии к главному модулю. { --- Как и все примеры - эта программа - результат поисков и опытов --- Приложение демонстрирует работу с простейшей базой данных. Используются данные типа MediumBlob для хранения картинок - фото. Бинарные данные картинок кодируются MIME-base64 и хранятся в виде текста, а при просмотре - декодируются. На это тратится время и дополнительно 30% памяти, но похоже, по другому нельзя. Возможно, что лучше в таблице хранить имена файлов (*.jpg, *.png ), но полезно уметь хранить бинарные данные в таблице. 1. Главная форма: frmMySQL5, модуль - unmain1. Должен быть доступен MySQL. Например, у меня установлен Denwer3, при запуске которого доступнен MySQL5 (и PHP5). Для создания БД достаточно создать папку ..\mysql5\data\lab3_2\ Подключаюсь к БД MySQL и выполняю запрос, вписанный в окошко memSQL. (Для этого - жмём кнопку Connect + SQL). Процесс выполнения отображается в окне memLog, а результаты запроса - в окне SG1: TStringGrid; Т е на этой форме задаем параметры подключения и выполняем произвольные запросы. 2. Форма: frmZapros, модуль unzapros - для отображения примеров запросов и копирования их в окошко memSQL (где их можно подредактировать). Примеры запросов отображаются при щелчке по кнопке Запросы. Свои примеры Вы можете добавить в файл zaprosi.txt 3. Форма: frmUserShow, модуль unusershow - отображает записи таблицы User, показывая картинки (фото юзера) и позволяет редактировать каждую запись (при этом можно заменить картинку - из файла на диске). Можно также добавлять записи в эту таблицу и удалять (текущую запись). Дополнительные возможности: сохранить картинку их формы на диск, очистить картинку на форме, загрузить картинку (форматы: jpeg, png, bmp и др, но не gif) с диска, менять масштаб. Окошко Memo показывает MIME-base64 кодировку картинки - при обновлении и добавлении записи (вероятно, лучше это убрать). 4. Тексты исходников (*.pas, *.lfm) хранятся в кодировке UTF8. Лазарус может перекодировать в другие кодировки (прав щелчок в окне редактора | Параметры файла | Кодировка: установить кодировку. Затем выбрать в диалоге: изменить файл). Однако, если перекодировать, например, в ANSI (cp1251), то в *.pas придется применять функцию AnsiToUTF8 при выводе в Memo, диалоговые окна и другие контролы. Похоже, Лазарус предпочитает UTF8. Но кодировку UTF8 читает блокнот(WinXP), так что проблем с просмотром исходников быть не должно. 5. (Для запуска проекта (файла .exe) требуется библиотека libmysql.dll которая входит в MySQL_Foto_Full.rar (можно скачать). Для уменьшения размера полученного при компиляции .exe-файла в 15 раз создайте файл str.cmd: E:\lazarus\fpc\2.2.4\bin\i386-win32\strip.exe %1 E:\lazarus\fpc\2.2.4\bin\i386-win32\upx.exe %1 (отредактируйте путь к Лазарусу и выполните команду: str.cmd projmysql0.exe - при закрытом проекте.) } Текст процедуры ConnectPlusSQL (главного модуля) procedure TfrmMySQL5.ConnectPlusSQL; var ii,jj: integer; erik: longint; {Выполняет подключение к MySQL, запросы (2 или 3) и закрывает MySQL} procedure byby; begin // действия при выходе из MySQL mysql_free_result (recbuf); mysql_close(sock); end; begin SG1.DefaultColWidth:= StrToInt(edWidth.Text); memLOg.Clear; mysql_init(PMySQL(@qmysql)); Host:= PChar(edHost.Text); Login:= PChar(edLog.Text); DataBase:= PChar(edDB.Text); Pass:= PChar(edPass.Text); Query:= PChar(memSQL.Text); sock := mysql_real_connect(PMySQL(@qmysql),Host,Login,Pass, DataBase,0,nil,0); if sock=Nil then begin memLog.Lines.Append('Не могу подключиться к MySQL.'); memLog.Lines.Append('Ошибка: '+mysql_error(@qmysql)); byby; exit; end; memLog.Lines.Append('Подключние:'); memLog.Lines.Append('Host info : ' + mysql_get_host_info(sock)); memLog.Lines.Append('Server info: ' + mysql_stat(sock)); memLog.Lines.Append('Client info: ' + mysql_get_client_info); if mysql_select_db(sock,DataBase) < 0 then begin memLog.Lines.Append('Не могу выбрать базу данных'+Database); memLog.Lines.Append(mysql_error(sock)); byby; exit; end else memLog.Lines.Append('Выбрана база данных: ' + DataBase); memLog.Lines.Append('Выполняю запрос: '+ Query); erik:= mysql_query(sock,Query); if ( erik <> 0) then begin memLog.Lines.Append('<<-- Не могу выполнить этот запрос -->>'); memLog.Lines.Append('<<-- Ошибка: '+mysql_error(sock)+' -->>'); byby; exit; end else memLog.Lines.Append(' Запрос выполнен '); recbuf := mysql_store_result(sock); // результат выполнения запроса if RecBuf=Nil then begin memLog.Lines.Append('Query returned nil result.'); mysql_close(sock); byby; exit; end; NumRows1:= mysql_num_rows (recbuf); NumCols1:= mysql_num_fields(recbuf); memLog.Lines.Append('Результат: число строк = ' + IntToStr(NumRows1)); memLog.Lines.Append('Результат: число столбцов = ' + IntToStr(NumCols1)); SG1.RowCount:= NumRows1 + 1; SG1.ColCount:= NumCols1; for jj:= 0 to NumCols1 - 1 do // имена колонок запроса добываю SG1.Cells[jj,0]:= mysql_fetch_field_direct(recbuf,jj)^.name; rowbuf := mysql_fetch_row(recbuf); // 1-я строка результата ii:=1; while (rowbuf <>nil) do begin for jj:= 0 to NumCols1 - 1 do SG1.Cells[jj,ii] := rowbuf[jj]; rowbuf := mysql_fetch_row(recbuf); // следующая строка результата inc(ii); end; byby; end; - Показываю форму frmUserShow procedure TfrmMySQL5.btnUserClick(Sender: TObject); begin frmUserShow.ConnectUser(PChar(''),PChar('select * from user limit ' + intToStr(nacalo) + ',1'));; frmUserShow.ShowModal; // показываю форму frmUserShow модально end; procedure TfrmMySQL5.btnZaprosClick(Sender: TObject); begin frmZapros.Show; // показываю форму frmZapros немодально end;
Заголовки функций (mysql_real_connect, mysql_get_host_info и т п) несложно найти: подвести текстовый курсор (в редакторе Lazarus) к термину и щелкнуть мышкой, удерживая нажатой Ctrl. (но при этом модуль, содержащий описание термина, должен присутствовать в uses). Описания специфических типов данных ( MYSQL_ROW, PMYSQL_RES, PMYSQL, MYSQL ) находятся так же, но приходится проследить цепочку ссылок и учитывать директивы {$IFDEF **}
На форме frmUserShow для просмотра данных выполняется только 1 запрос: Query:= PChar('select * from user limit ' + IntToStr(nacalo) + ',1'); - для просмотра 1 записи - со смещением nacalo от начала таблицы. Поля этой записи хранятся в структуре rowbuf2 и выводятся в окошки Edit и (картинка - поле Foto) - в Image1. Почему-то rowbuf2[0] доступо только в методе Pokazz. Там копирую IDStr:= rowbuf2[0]; и в дальнейшем использую IDStr. Вероятно, со временем причина найдется.