среда, 30 марта 2011 г.

Встроенный MySQL сервер

Для работы необходимы библиотеки libmysqld.lib и libmysqld.dll
Это минимальный вариант встроенного сервера. Взят с офф сайта.
Код:

#include "stdio.h"
#include "stdlib.h"
#include "stdarg.h"
#include "my_global.h"
#include "mysql.h"

#pragma comment(lib, "libmysqld.lib")

MYSQL *mysql;
MYSQL_RES *results;
MYSQL_ROW record;

static char *server_options[] = { "mysql_test",
 //"--defaults-file=.\\my.ini",
    "--basedir=.\\",
    "--datadir=.\\bases",
 "--default-character-set=latin1",
    NULL };
    
int num_elements = (sizeof(server_options) / sizeof(char *)) - 1;

static char *server_groups[] = { "test_MySQL_Embedded", "embedded", "server", NULL };

int main(void)
{
 int emb = 0;
 int affected = 0;

 printf("MySQL Embedded initializing . . .");
 emb = mysql_server_init(num_elements, server_options, (char **)server_groups);
 
 if (emb > 0)
 {
  printf("\nCan't init server\nPress any key to exit . . .");
  //system("pause");
  return 1;
 }
 mysql = mysql_init(NULL);
 mysql_options(mysql, MYSQL_READ_DEFAULT_GROUP, "client");
 mysql_options(mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, NULL);

 //printf("\nconnecting . . .\n");
 if (!mysql_real_connect(mysql, NULL, NULL, NULL, "const", 0, NULL, 0))
  printf("%s\n", mysql_error(mysql));

 //printf("query\n");
 if (mysql_query(mysql, "SELECT * FROM try") != 0)
 {
  printf("\n%s\n", mysql_error(mysql));
  //system("pause");
  return 1;
 }

 affected = (int)mysql_affected_rows(mysql);
 if (affected < 0)
 {
  printf("\nField count: %d\n", mysql_field_count(mysql));

  results = mysql_store_result(mysql);

  //printf("output data\n");
  while((record = mysql_fetch_row(results))) 
  {
   printf("%s - %s \n", record[0], record[1]);
  }
 }
 else
 {
  printf("\nAffected rows: %d\n", affected);
 }

 printf("MySQL Embedded stoping . . .");
 mysql_free_result(results);
 mysql_close(mysql);
 mysql_server_end();
 //system("pause");
 return 0;
}
//---------------------------------------------------------------------------
psycho-coder
(http://programmersforum.ru/showthread.php?t=59147&page=5)

вторник, 29 марта 2011 г.

1-я статья по взаимодействию с СУБД MySQL из программы на C++

Немного теории


Код:

// Дескриптор соединения. 
// Структура, содержащая HANDLE для одного подключения к серверу.
MYSQL mysql;
MYSQL_RES *res; // Дескриптор результирующей таблицы
MYSQL_ROW row; //  Массив полей текущей строки
// Структура, которая содержит всю информацию, 
// касающуюся отдельного поля таблицы
MYSQL_FIELD *field;
Функиции которые понабодятся:

Функция инициализации.
Код:

MYSQL *mysql_init(MYSQL *mysql);
Где соответственно host — компьютер, на котором запущена СУБД MySQL, user — имя юзера для подключения, passwd — пароль, db — название предполагаемой для использования базы данных, port — порт, unix_socket — сокет или pipe-канал, который необходимо использовать.
Код:

MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, 
                          const char *passwd, const char *db,
                          unsigned int port, const char *unix_socket, 
                          unsigned int client_flag);
client_ flag может принимать несколько значений:

CLIENT_COMPRESS — используется сжатие.
CLIENT_FOUND_ROWS — возвращать число найденных строк.
CLIENT_IGNORE_SPACE — делает все имена функций зарезервированными словами.
CLIENT_INTERACTIVE — разрешает interactive_timeout секунд бездействовать (вместо wait_timeout) перед закрытием подключения.
CLIENT_NO_SCHEMA — запрещает синтаксис вида "db_name.tbl_name.col_name" (имя_базы_данных.имя_таблицы.имя_ко лонки). Используется для ODBC.
CLIENT_ODBC — устанавливает то, что это клиент ODBC.
CLIENT_SSL — используется защищенный протокол SSL.

Мы флагами пользоваться не будем.

Функция выполняющая запрос
Код:

int mysql_query(MYSQL *mysql, const char *query);
Функция возвращающая строку с описанием ошибки
Код:

char *mysql_error(MYSQL *mysql);
Функция, которая получает все строки результата запроса и хранит их в буфере-клиенте
Код:

MYSQL_RES * mysql_store_result(MYSQL *mysql);
Функция получает количество строк в результате запроса
Код:

my_ulonglong mysql_num_rows(MYSQL_RES *res);
Функция получает количество полей (столбцов) в результате запроса
Код:

unsigned int mysql_num_fields(MYSQL_RES *res);
Функция заполняет массив полей для текущей строки
Код:

MYSQL_ROW mysql_fetch_row(MYSQL_RES *result);
Функция заполняет структуру для текущего поля (fieldnr)
Код:

MYSQL_FIELD *mysql_fetch_field_direct(MYSQL_RES *res, unsigned int fieldnr);
Начальная "настройка"

Для работы в Builder необходимо конвертировать libmysql.lib.
Для этого, нужно открыть консоль и набрать там это

Код:

C:\>"C:\Program Files\Borland\CBuilder6\Bin\coff2omf.exe" 
-lib:st "C:\Program Files\Borland\CBuilder6\Lib\libmysql.lib" 
"C:\Program Files\Borland\CBuilder6\Lib\libmysql_.lib"
Здесь "C:\Program Files\Borland\CBuilder6\Lib\libmysq l.lib" оригинальная библиотека,
а "C:\Program Files\Borland\CBuilder6\Lib\libmysq l_.lib" конвертированная

У каждого пути будут свои.
Также в папке с программой (или в "C:\Program Files\Borland\CBuilder6\Lib\") должны быть libmysql_.lib, а для VS libmysql.dll.
Заголовочные файлы можно бросить в папку с программой или в "C:\Program Files\Borland\CBuilder6\Include\".
Для VS "C:\Program Files\Microsoft Visual Studio Х.0\VC\include". Где Х - версия VS.
В среде MS VC++ можно использовать библиотеку без конвертации, т.е. libmysql.lib.
Все заголовочные файлы могут быть в папке с программой, но тогда нужно подключать их локально.

Есть замечания для VC++ WinForms.
Так как типы String^ и char[] несовместимы, то для конвертирования из String^ в char[] можно использовать следующие функции (взято из MySQL++):
Код:

private: String^ ToUCS2(const char* utf8)
{
     try
     {
  return gcnew String(utf8, 0, strlen(utf8), System::Text::Encoding::Default);
     }
     catch(...)
     {
  return "";
     }
}
private: Void ToUTF8(char* pcOut, int nOutLen, String^ sIn)
{
    try
    {
  array^ bytes = System::Text::Encoding::Default->GetBytes(sIn);
  nOutLen = Math::Min(nOutLen - 1, bytes->Length);
  System::Runtime::InteropServices::Marshal::Copy(bytes, 0, IntPtr(pcOut), nOutLen);
  pcOut[nOutLen] = '\0';
    }
    catch (...)
    {
  pcOut[nOutLen] = '\0';
    }
}
Пример использования
Код:

const int buf = 512;
char host[buf];
ToUTF8(host, buf, hostText->Text); // Перевод из String^ в char[]
String ^tmp = ToUCS2(mysql_error(&mysql)); // Перевод из char* в String^
 
 
 
psycho-coder
(http://programmersforum.ru/showthread.php?t=59147)

2-я статья по взаимодействию с СУБД MySQL из программы на С++

 Вывод в консоль

Вывод таблиц в консоли. Интерфейс правда не супер, но для практики думаю хватит.
В коде есть комментарии.

Код:

#define __LCC__ // Объявляем директиву без которой
// программа не может работать. Можно конечно поключить windows.h, 
// но это будет не красиво

#pragma comment(lib, "libmysql_.lib") // подключаем библиотеку
#include "mysql.h" // Заголовочный файл с описание функций
#include "stdio.h"
#include "conio.h"

void mysql(const char query[])
{
 MYSQL mysql; // Дескриптор соединения
 MYSQL_ROW row; // Массив полей текущей строки
 MYSQL_RES *res; // Дескриптор результирующей таблицы

 char host[] = "localhost"; // хост
 char user[] = "admin"; // пользователь
 char passwd[] = "admin"; // пароль
 char db[] = "library"; // название базы данных
 int port = 0; //  порт. Если порт у сервера MySQL не по умолчанию (3306), 
// то нужно указывать конкретный номер порта

 mysql_init(&mysql);  // Инициализация
 mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0); // соединение

 if (mysql_query(&mysql, query) > 0) // запорс. Если ошибок нет, то продолжаем работу
        {
   
   // Если была ошибка, ...
   printf("%s", mysql_error(&mysql));  // ... вывдем ее
   return; // и завершим работу
        } 

    res = mysql_store_result(&mysql); // Берем результат,
    int num_fields = mysql_num_fields(res); // количество полей
    int num_rows = mysql_num_rows(res); // и количество строк.

    for (int i = 0; i < num_fields; i++) // Выводим названия полей
    {
      field = mysql_fetch_field_direct(res, i); // Получение названия текущего поля
      printf("| %s |", field->name);
    }

    printf("\n");
 
    for (int i = 0; i < num_rows; i++) // Вывод таблицы
    {
      row = mysql_fetch_row(res); // получаем строку

      for (int l = 0; l < num_fields; l++)
        printf("| %s |", row[l]); // Выводим поля
  
      printf("\n");
    }
 
    printf("Count records = %d", num_rows); // Вывод информации о количестве записей
   mysql_free_result(res); // Очищаем результаты
 mysql_close(&mysql); // Закрываем соединение
}

int main()
{
  mysql("SELECT * FROM t_mid_author"); // Запрос
  getch(); // Ожидаем нажатие клавиши
  return 0;
}


Графический интерфейс
Очередная статья по взаимодействию с СУБД MySQL из программы на С++

Мутим простейший интерфейс

Кидаем на форму:
TLabel (5 шт.). В свойство Caption пишем хост, порт и т.д.
TEdit (5 шт.). Названия TEdit'ов: hostText, userText, passText, dbText и portText.
TButton (2 шт.). В свойства Caption пишем "Пошел!" и "Закрыть".
TMemo (1 шт.)
TStringGrid (1 шт.)

Подключаем заголовочные файлы, библиотеку и объявим одну константу


Код:

#define __LCC__
#include 
#pragma comment(lib, "libmysql_.lib") // Для Builder 6. см. в первой статье
#pragma comment(lib, "libmysql.lib") // Для MS VC++
// Для других сред программирования не пробовал (
const int buf = 512;
Обработчик кнопки "Закрыть" думаю понятен

А в обработчик копки "Пошел!" пишем следующее

Код:

/* Проверим что все данные были введены? в.ч. и сам запос (Memo1) */
  if (hostText->Text.IsEmpty() || userText->Text.IsEmpty() ||
      passText->Text.IsEmpty() || dbText->Text.IsEmpty() ||
      portText->Text.IsEmpty() || Memo1->Text.IsEmpty())
  {
    MessageBox(this->Handle, "Не все поля заполнены!", "Ошибка!",
      MB_OK | MB_ICONERROR);
    return;
  }

  // Тут Вам все должно быть знакомо
  MYSQL mysql;
  MYSQL_ROW row;
  MYSQL_RES *res;
  MYSQL_FIELD *field;

  /* Объявляем массивы для работы */
  char host[buf];
  char user[buf];
  char passwd[buf];
  char db[buf];
  char query[buf];
  int port = portText->Text.ToInt();
  int num_fields = 0;
  int num_rows = 0;

  /* Инициализируем имя хоста, пользователя, пароль и БД */
  strcpy(host, hostText->Text.c_str());
  strcpy(user, userText->Text.c_str());
  strcpy(db, dbText->Text.c_str());
  strcpy(passwd, passText->Text.c_str());
  strcpy(query, Memo1->Text.c_str()); //*/

  mysql_init(&mysql);
  if (!mysql_real_connect(&mysql, host, user, passwd, db, port, NULL, 0))
  { /* Пробуем подключиться, если кдето ошибка то сообщим об этом */
    MessageBox(this->Handle, mysql_error(&mysql), "Error!",
      MB_OK | MB_ICONERROR);
    return;
  }

  if (mysql_query(&mysql, query) > 0)
  { /* Пробуе выполнить запрос, если запрос не верен то сообщаем об ошибке,
       Выведем ее и выходим
    */
    MessageBox(this->Handle, mysql_error(&mysql), "Error!",
      MB_OK | MB_ICONERROR);
    return;
  }

  // Получаем результат
  res = mysql_store_result(&mysql);

  /* Устанавливаем кол-во строк в таблице и сохраняем кол-во строк */
  StringGrid1->RowCount = num_rows = mysql_num_rows(res);

  /* Устанавливаем кол-во полей и сохраняем это кол-во столбцов */
  StringGrid1->ColCount = num_fields = mysql_num_fields(res);
  StringGrid1->FixedRows = 1; // Фиксируем первую строку.

  for (int i = 0; i < num_fields; i++) // Выводим названия полей
  {
   field = mysql_fetch_field_direct(res, i);
   StringGrid1->Cells[i][0] = field->name;// В 1-ю строку
  }

  for (int i = 1; i < num_rows; i++) // Вывод результата запроса
  {
   row = mysql_fetch_row(res); // Получаем строку
   for (int l = 0; l < num_fields; l++)
     StringGrid1->Cells[l][i] = row[l]; // Выводим строку по ячейкам
  }

  mysql_free_result(res); // Освобождаем память
  mysql_close(&mysql); // Закрываем соединение
Вот и все. пишем запрос и "Пошел!".
psycho-coder
(http://programmersforum.ru/showthread.php?t=59147)

MySQL и C++. Простые решения

Загвоздка в том, что большинство примеров использования MySQL в Интернете посвящено именно веб-приложениям (оно, в принципе, и понятно — такова специфика). И это зачастую отпугивает программистов. Прямым конкурентом MySQL в нише небольших приложений на малых предприятиях, пожалуй, следует считать MsAccess. Пусть многие со мной не согласятся, но Access — это не совсем то, что следует использовать при наличии локальной сети в организации, пусть и база данных предполагает быть небольшой. Но ведь и в MicroSoft (не правда ли, звучит как насмешка: их программные продукты уже давно с бо-о-ольшой натяжкой можно назвать Micro:)) не сразу предполагали, что Windows будет занимать 1 Гб и более. Так что… А если данные используются не на одном компьютере, а сразу на нескольких, то синхронизация таблиц без централизованного сервера СУБД становится головной болью. (Встречаются извращения, когда каждый день в обязанности сотрудников входит "скачивание" с сетевого диска последней версии файла MsAccess. А теперь представьте себе ситуацию, когда данные были внесены некорректно — файл-то уже скачали.

Весело, не правда ли? В таких случаях можно просто установить на одной машине сервер, раздать пользователям логины с соответствующими правами и навсегда забыть о проблемах (не забывайте только почаще делать резервное копирование: мало ли что). Причем, если клиент для БД написан грамотно, у пользователей вообще будет полная иллюзия работы ТОЛЬКО на своей машине, и будет выполняться одно из самых часто нарушаемых правил совместной работы в локальной сети: все важные данные хранить на сервере. Так ведь легче и архивировать, и восстанавливать, если что. Итак, чем мы займемся? А займемся мы написанием приложения, которое будет работать с сервером MySQL без использования "продуктов сторонних разработчиков", web-сервера и т.п. Вообще если брать общий случай, когда база данных создана (под этим предлагаю понимать создание таблиц и связей, внесение в них данных, создание шаблонов запросов, а также раздачу привилегий пользователям), все готово для работы. Вместе с сервером версии 3.23.38 (который мы будем рассматривать) поставляется программка mysql.exe, которая может запросто работать по сети, но, правда, ТОЛЬКО в консоли:-). Но настоящих программистов вид консоли ведь не должен пугать? (Бывают и такие, с дипломами БГУ, причем:-)). Но для конечных пользователей это, я согласен, неприемлемо.

А посему рассмотрим, как можно использовать MFC для наших нужд. Если вы посмотрите на каталог, куда установлен ваш сервер (c:\mysql\ по умолчанию), вы увидите, кроме всего прочего, две интересные папки: include и lib. В первой из них вы найдете *.h-файлы, содержащие описание функций, которые мы будем использовать, а во втором каталоге лежит *.lib-файл, который нам тоже понадобится: libmySQL.lib (c:\mysql\lib\debug). Все эти файлы следует переписать в соответствующие директории, где находятся ваши заголовочные и библиотечные файлы (например, c:\Program Files\ Microsoft Visual Studio\Vc98\ Include и c:\Program Files\ Microsoft Visual Studio\Vc98\ lib, если VC устанавливался по умолчанию). Как видите, разработчики позаботились о том, чтобы нам с вами можно было как можно проще использовать их сервер в своих приложениях. Все описанные там функции отвечают за сетевое взаимодействие с сервером, отправку запросов, закрытие соединения т.п. Разработчику прикладных программ не нужно заботиться о сокетах и тому подобном. Еще нам понадобится dll-библиотека libmySQL.dll (c:\mysql\lib\ debug), которую следует копировать в каталог проекта, использующего функции, описанные в этих файлах. Но о создании приложения чуть попозже. Итак, как выглядит работа с MySQL-сервером из С\С++? На это можно посмотреть в примере, опять же, поставляемом вместе с сервером c:\mysql\examples\libmysqltest\. Там дан исходный код программы, использующий libmysql.dll для связи с сервером и получения данных от него. Но это консольное приложение. И, как я уже сказал, это нам не подходит. Итак, кратко расскажу, как мы будем из своего приложения получать данные от сервера. Сначала нужно к нему подключиться.

Для подключения к серверу необходимо вызвать функцию mysql_init(), которая проинициализирует HANDLE, а после собственно создаст подключение, вызвав mysql_real_connect().

MYSQL *mysql_init(MYSQL *mysql), где MYSQL — структура, содержащая HANDLE для одного подключения к серверу.
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned int client_flag), где соответственно host — компьютер, на котором запущена СУБД MySQL, user — имя юзера для подключения, passwd — пароль, db — название предполагаемой для использования базы данных, port — порт, unix_socket — сокет или pipe-канал, который необходимо использовать. client_ flag может принимать несколько значений:

CLIENT_COMPRESS — используется сжатие.
CLIENT_FOUND_ROWS — возвращать число найденных строк.
CLIENT_IGNORE_SPACE — делает все имена функций зарезервированными словами.
CLIENT_INTERACTIVE — разрешает interactive_timeout секунд бездействовать (вместо wait_timeout) перед закрытием подключения.
CLIENT_NO_SCHEMA — запрещает синтаксис вида "db_name.tbl_name.col_name" (имя_базы_данных.имя_таблицы.имя_колонки). Используется для ODBC.
CLIENT_ODBC — устанавливает то, что это клиент ODBC.
CLIENT_SSL — используется защищенный протокол SSL.

Небольшой пример:

MYSQL mysql;
mysql_init(&mysql);
mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,"your_prog_name");
if (!mysql_real_connect(&mysql,"host", "user","passwd","database",0,NULL,0))
{
  fprintf("Ошибка соединения с сервером: Error: %s\n",
 mysql_error(&mysql));//О получении ошибок см. ниже
}

После того, как соединение установлено, с базой данных можно работать. Закрыть соединение можно при помощи mysql_close(): void mysql_close (MYSQL *mysql).
Еще полезной функцией является mysql_ping(). Она пингует сервер (вернее, проверяет, действительно ли текущее соединение, задаваемое получаемым параметром), и, если соединение потеряно, пытается переподключиться (иногда полезно проверять подключение, если предполагается, что программа может долгое время не использоваться юзером активно).

int mysql_ping(MYSQL *mysql)

Когда подключение создано, серверу можно отсылать запросы при помощи функций mysql_query() или mysql_real_ query(). Разница между ними в том, что первая функция в качестве запроса использует строку, заканчивающуюся нулевым символом. А вторая используется, если в запросе есть двоичные данные с содержанием множества нулевых символов.

int mysql_query(MYSQL *mysql, const char *query)

Возвращает ноль, если запрос выполнен удачно.
Если запрос не использует конструкцию SELECT, то количество измененных записей можно найти при помощи вызова mysql_affected_rows()
my_ulonglong mysql_affected_rows (MYSQL *mysql).
Существует два варианта работы с результатами запроса, возвращенных сервером. Первый из них состоит в том, чтобы использовать функцию mysql_store_result(), которая получает все строки результата запроса и хранит их в буфере-клиенте. Второй состоит в использовании mysql_use_re-sult(). Фактически эта функция не получает никаких строк от сервера. Она как бы инициализирует поиск.
MYSQL_RES *mysql_store_ result(MYSQL *mysql). Желательно использование этой функции для запросов, содержащих SQL конструкции SELECT, SHOW, DESCRIBE, EXPLAIN. Однако ничто вам не запрещает использовать ее и для других запросов (INSERT, например).

MYSQL_RES *mysql_use_ result(MYSQL *mysql). Эта функция не получает все данные от сервера сразу, поэтому не требуется хранить их во временном буфере клиента. Это может понадобиться, если вам нет необходимости выводить все результаты сразу, а нужно лишь показывать их "постранично". Однако вы не сможете использовать mysql_ data_seek(), mysql_row_seek(), mysql_row_tell(), mysql_num_ rows(), или mysql_affected_rows () с результатом, возвращенным mysql_use_result(), а также выполнять другие запросы, пока не "используете" все данные предыдущего. Кроме того, вы должны вызвать mysql_ free_result(), как только закончите работать с результатами запроса.
В обоих случаях получить доступ к записям, удовлетворяющим запросу, можно при помощи функции mysql_fetch_ row(). При ее использовании с mysql_store_result() вы получаете доступ к строкам, уже полученным от сервера, а при использовании с mysql_use_ result() вы фактически получаете доступ к записи на сервере. Информация относительно размера данных доступна при вызове mysql_fetch_lengths (). И вызывайте mysql_free_ result() для очистки памяти.

Преимущество mysql_store_ result() состоит в том, что при помощи этой функции вы получаете произвольный доступ к полученным данным, двигаясь по ним при помощи mysql_ data_seek () или mysql_row_ seek (). Вы можете также получить информацию о количестве строк, вызвав mysql_num_ rows (). Однако этот способ имеет и свои недостатки. При обработке больших объемов данных может возникнуть опасность переполнения буфера.
Преимущество mysql_use_ result() состоит в том, что к клиенту предъявляются более низкие требования по количеству используемой памяти (и производительности соответственно). Недостатком является то, что вы должны обрабатывать данные достаточно быстро, чтобы не потерять связь с сервером. Кроме того, вы не имеете произвольного доступа к результатам. И вы не можете узнать, сколько записей в ответе на запрос (пока не обработаете их все).
У всех бывают ошибки. Для получения информации об ошибках используются функции mysql_errno () и mysql_ error (). Первая возвращает номер ошибки, вторая — текстовое пояснение. Следует помнить, что они возвращают только ошибку, которую вызвала последняя выполненная вами функция.

unsigned int mysql_errno(MYSQL *mysql)
char *mysql_error(MYSQL *mysql).

Более подробное описание функций можно найти в мануале, поставляемом вместе с сервером (правда, на английском, но, я думаю, это для вас не проблема): c:\mysql\docs\ manual.html.
Итак, пишем наше клиентское приложение. Уметь оно будет немного, а конкретней, следующее: подключаться к базе данных, пинговать подключение и соответственно переподключаться если что, посылать запросы и выводить их результаты пользователю. Запросы будут набираться в командной строке. Создаем MFC-приложение с таким вот интерфейсом:


Приложение будет называться SQL_client.
Ниже в таблице представлены обработчики событий взаимодействия пользователя с интерфейсом, а также переменные, ответственные за хранение введенных данных:


Кнопку ОК оставим без изменений. Дополнительно следует объявить следующую функцию: void CSQL_clientDlg ::Add_str_in_box(), которая будет служить для вставки последней выполненной команды в Combo Box CMD.
Также следует объявить следующие переменные:
MYSQL mysql — эта структура будет хранить данные о подключении.
BOOL error_connect — флаг упешного подключения к серверу. Его следует проинициализировать "error_connect= FALSE;" в конце функции BOOL CSQL_clientDlg::OnInitDialog() что в SQL_clientDlg.cpp.
BOOL flg_msg_error_connect; — флаг потери соединения.

В заголовки файлов необходимо включить строку #in-clude для того, чтобы использовать функции, описываемые в *.h-файлах, о которых говорилось в начале статьи. В проект также следует включить libmysql.lib (щелкнув правой кнопкой по ветке SQL_client files на закладке FileView-> Add Files To Pro-ject…). Теперь создадим таймер. Заходим в ClssWizard и на закладке Message Map для Object Ids CSql_clientDlg задаем Message WM_TIMER и создаем функцию. Тело ее должно выглядеть следующим образом:

//Пингуем сервер
void CSQL_clientDlg::OnTimer(UINT nIDEvent)
{
  //В зависимости от установленных флагов сообщаем информацию пользователю
  int png=mysql_ping(&mysql);
  switch(png)
 {
  case 0:
     error_connect=TRUE;
     if(flg_msg_error_connect)
    {
     m_out+="Соединение с сервером восстановлено";
     UpdateData(FALSE);     flg_msg_error_connect=FALSE;    }   break;
  default:
    if(error_connect)
   {
     m_out+="ERROR. Соединение с сервером потеряно. Попытка переподключения...\r\n";     UpdateData(FALSE);     error_connect=FALSE;     flg_msg_error_connect=TRUE;   };
  break;
  };
 UpdateData(TRUE);
 CDialog::OnTimer(nIDEvent);
}

Эта функция выдает сообщение о потере соединения только при первом провале проверки подключения функцией mysql_ping(&mysql), а также при восстановлении соединения.
Кажется, все, подготовительный этап закончен.
Теперь осталось соответствующим образом изменить тела функций. Начнем по порядку. Добавление строчек в Combo-Box (только для удобства:-)). Это удобно в том случае, если вам нужно повторить длинную команду, а вы ее предусмотрительно не скопировали в буфер. Ведь это все же не настоящая консоль.

void CSQL_clientDlg::Add_str_in_box()
{
 //Вставляем в командную строку последнюю введенную команду
  CComboBox *Box;
 //Получаем указатель...
 Box = (CComboBox *)(this-> GetDlgItem(IDC_cmd));
 //Вставляем...
 Box-> AddString(m_cmd);
}

Подключаться к серверу будем специальной конструкцией, которую будем вызывать и в случае (если пользователь забыл подключиться сразу) попытки сделать запрос. Функция подключения к серверу выглядит следующим образом:

void CSQL_clientDlg::connect()
{
 //Обработка незаполненных полей, заставляем пользователя заполнить все поля
 UpdateData(TRUE);
 mysql_init(&mysql);
 if(m_host=="" || m_user=="" || m_password=="" || m_bd=="")
 {
   MessageBox("Не все поля заполнены!");
   m_out+="Не все поля заполнены!";
  UpdateData(FALSE);
  return;
 }
 //Обрабатываем ошибки
 if (!mysql_real_connect(&mysql,m_host, m_user,m_password,m_bd,0,NULL,0))
{
  MessageBox("Error");
  //Выводим текст возможных ошибок.
  m_out+=mysql_error(&mysql);
}
//Сообщаем пользователю об успешном подключении
else
{
  MessageBox("OK");
 m_out+="Подключение к серверу MySQL прошло успешно!Теперь можно работать.\r\n";
 error_connect=TRUE;
 flg_msg_error_connect=FALSE;
}
//Запускаем таймер, по которому будет пинговаться сервер
SetTimer( 1, 5000, NULL );
UpdateData(FALSE);
return;
}
 

Осталось только отправить запрос на сервер и выдать результаты пользователю:
 

void CSQL_clientDlg::Ongo()
{
//Обьявляем переменные
CString tmp;
MYSQL_RES * res ;
MYSQL_FIELD* fd ;
MYSQL_ROW row ;
unsigned int i,num_fields;
unsigned long *lengths;
char buf[255];
my_ulonglong raws_nubm;
//Обновляем данные
UpdateData(TRUE);
//Добавляем строки в combo box
Add_str_in_box();
//Проверка подключения — подключены или нет
if(error_connect)
{
//Делаем запрос
mysql_query( &mysql, m_cmd );
tmp=mysql_error(&mysql);
m_out+=tmp;
m_out+="\r\n";
UpdateData(FALSE);
//Если есть ошибка, не выводим результаты
if(tmp=="")
{
//Получаем результаты запроса
res = mysql_store_result(&mysql);
//Получаем количество возвращенных записей
m_out+="Количество записей, удовлетворяющих запросу\r\n";
raws_nubm=mysql_num_rows(res);
//Сообщаем пользователю
itoa( raws_nubm, buf, 10 );
m_out+= (CString)&buf[0];
m_out+="\r\n";
UpdateData(FALSE);
num_fields = mysql_num_fields(res);
//Последовательно выводим все полученные данные, пока в структуре еще есть записи.
while ((row = mysql_fetch_row(res)))
{
lengths = mysql_fetch_lengths(res);
for(i = 0; i < num_fields; i++)
{
m_out+=row[i]; m_out+=" | ";
}
UpdateData(FALSE);
m_out+=("\r\n");
}
m_out+=tmp;
tmp="";
//Освобождаем память
mysql_free_result(res);
}
}
//Обрабатываем ошибки
else
 {
  m_out+="Error:Нет подключения к серверу. Попытка подключения...\r\n ";
  UpdateData(FALSE);
  connect();
  };
UpdateData(FALSE);
}

Работа приложения выглядит следующим образом. Пользователь вводит данные подключения, после чего можно нажать либо кнопку Connect, либо GO. При этом в любом случае вызывается функция CSQL_client Dlg::connect(), которая подключается к серверу MySQL и запускает таймер, который каждые 5 секунд проверяет наличие соединения (период пингования зависит от настроек сервера, т.е. времени, через которое он закрывает соединение, сети и т.д.). Теперь сервер может принимать и выполнять запросы. Запросы пользователь вводит в командной строке CMD, после чего они заносятся в список ComboBox'a. При нажатии на GO результаты запросов выводятся построчно через разделитель "|". Ну вот, пожалуй, и все. Только учтите: когда будете переносить свое приложение на другие машины, вам понадобятся некоторые dll-библиотеки (кроме прочих, "стандартных"). Все, конечно, зависит от конкретной системы, но в данном приложении используются следующие(WinXP Rus):

libmySQL.dll
MFC42D.DLL
MFC42LOC.DLL
MFCO42D.DLL
MSCTF.DLL
MSVCRT.DLL
MSVCRTD.DLL

Но рекомендую все же на всякий случай просмотреть, какие библиотеки использует данное приложение в вашей системе.
Найти их можно в c:\windows\system32 (кроме libmy SQL.dll, она есть в директории, в которую установлен сервер mysql). Как обычно, исходные тексты можно получить от меня по почте. И еще раз напоминаю, что данный пример является только примером, поэтому он ограничен по функциональности и не выделяется своей производительностью. Это уже ваша работа:-).
До свидания, и удачных вам коннектов!

Спичеков Александр aka MentAlzavR, Zavr6@mail.ru





четверг, 17 марта 2011 г.

Установка InterBase и Firebird вручную

  В этой статье пойдет речь об установке InterBase и Firebird на Windows, заранее приношу извинения пользователям Unix. Тем не менее, пользователи Unix могут извлечь для себя полезную информацию из этой статьи.

Кому будет полезна эта статья

* тем, кто хочет научиться устанавливать InterBase или Firebird в тех случаях, когда нет инсталлятора под рукой.
* тем, кто хочет восстановить "убитую" инсталляцию конкретной версии InterBase/Firebird, которая пострадала из-за установки другой версии.
* тем, кто хочет работать (одновременно или попеременно) с разными версиями этих серверов на одном компьютере
* тем, кто хочет узнать, что же именно на самом деле происходит при установке InterBase и Firebird.

Содержание

* Из каких файлов состоит сервер
* Установка вручную
o установка сервера
o установка только клиентской части
o запуск сервиса
* Установка или обновление "поверх"
* Установка серверов "рядом" и поочередный запуск
* Одновременный запуск
* Firebird 2.0, поочередный и одновременный запуск

Важные файлы

Начнем с того, что после установки Interbase или Firebird на диске образуется определенная структура каталогов с лежащими в них файлами. Я исключу всякие examples, ext, doc, sdk и упомяну только то, что нужно серверу для работы:
* корневой каталог установки. Конечно, это может быть C:\Program Files\Borland\InterBase\... Но может быть и проще - C:\IB75, D:\Firebird.... Дело вкуса. Здесь могут находиться
o файлы interbase.msg или firebird.msg. в них - сообщения сервера (в основном об ошибках). Файлы отличаются между версиями, поэтому если файл "не тот", то сообщения могут выглядеть бредово (несоответственно ситуации).
o файлы security.fdb (FB 1.5), security2.fdb (FB2), admin.ib (IB7 и выше), isc4.gdb (все остальные)- это база данных, где хранятся пользователи.
o файл firebird.conf (FB 1.5 и выше) или ibconfig (все остальные) - файл конфигурации сервера. Также aliases.conf для Firebird 1.5/2.0.
o только для платных версий InterBase - файлы ib_license.dat, borland.lic, node.tmp
* bin\
o собственно, все содержимое каталога bin можно считать важным. Назначение отдельных файлов будет дано дальше по ходу статьи.
* intl\
o файлы gdsintl.dll, fbintl.dll или ваши собственные dll с альтернативными наборами кодировок.
* UDF\
o каталог с User Defined Functions, важен только для ваших приложений, если они используют UDF явно в запросах или косвенно в триггерах и процедурах базы данных.
Все остальное - лишнее, то есть серверу для работы не нужно.

Ручная установка

Допустим, мы взяли корневой каталог сервера, и хотим из этих файлов получить рабочий сервер на другом компьютере. Сразу оговорюсь по поводу платных версий InterBase - во-первых, лицензия дает право установки сервера только на один компьютер; во-вторых, лицензии InterBase 7.1/7.5 "привязываются" к операционной системе, поэтому файлы этих серверов просто так перенести нельзя.
примечание: у InterBase 7.1/7.5 есть возможность "молчаливой установки" - Silent Install. Опции инсталлятора для такой установки описаны в документе.
Создадим на новом компьютере каталог C:\Server. Скопируем в него все содержимое корневого каталога той самой установки, о которой было рассказано выше. Теперь при помощи Start/Run открываем окно cmd.

cd \
cd Server\bin
instreg install c:\Server

И правда, в каталоге bin есть утилита instreg.exe. Она прописывает необходимую информацию в реестр Windows, указывая умолчательное расположение остальных файлов сервера. В версии Firebird 1.5 указывать путь к корневому каталогу не нужно, утилита сама "соображает" откуда она запущена, и прописывает в реестр правильную информацию. Не надо только копировать instreg куда попало и пытаться зарегистрировать сервер оттуда.
У instreg могут быть дополнительные параметры, они не важны, и вы можете увидеть их если запустите instreg без параметров (это безопасно, instreg выводит только информацию о параметрах).
примечание: InterBase 7.5/2007 допускает так называемую multi-instance установку, т.е. возможность установить несколько независимых экземпляров сервера на один компьютер. Такие серверы в сервисах и реестре идентифицируются по имени. Именем по умолчанию (при первой установке) является gds_db. Не смотря на то, что это имя похоже на имя порта в файле services, оно абстрактно и с реальным именем порта не имеет ничего общего. Например, для повторной регистрации IB 2007 в реестре требуется выполнить команду
instreg install c:\ib2007 gds_db
для "разрегистрации" сервера также необходимо указывать имя экземпляра IB:
instreg remove gds_db
После регистрации сервера утилитой instreg можно сразу проверить работоспособность сервера в режиме приложения. Начиная с InterBase 6 все "наследники" (Firebird, Interbase, Yaffil) поддерживают ключ командной строки -a для запуска сервера в режиме приложения. В том же окне cmd выполним команду:

ibserver -a

Конечно, имя сервера может быть другим. Для Firebird это fbserver (SuperServer) и fb_inet_server (Classic), главное чтобы вы поняли идею. Сразу после указанной команды вы увидите иконку сервера в TaskBar, и сервер почти готов к работе.
В отношении InterBase подобный запуск полезен тем, что в случае отсутствия файла лицензии можно увидеть ошибку "License file is missing or corrupt" (в отличие от "приложения" сервис сообщит об этом только в interbase.log, а его еще надо открыть и посмотреть). Также, в taskbar-меню запущенного как приложение InterBase можно увидеть (в Properties) установленные лицензии.
замечание: некоторые версии InterBase и Firebird молча запускаются во втором экземпляре, даже если они уже работают (как сервис или как приложение). Соответственно, если в конфигурации для второго экземпляра не изменен номер порта, то он работать не будет, т.к. первый экземпляр уже перехватил порт tcp. Будьте внимательны при запуске разных серверов на компьютере - вполне может быть, что в момент запуска Firebird как приложения, уже работает InterBase (или наоборот). Если при этом открыть базу, которая совместима по ODS с обоими серверами, то можно "случайно испортить" метаданные (или blr триггеров и процедур), открыв базу "не тем" сервером.

Если все-таки при выдаче этой команды произошла ошибка, или сервер не реагирует на попытки подсоединения к нему, то нужно искать ее причину. Скорее всего проблема может быть в двух местах:
1. серверу закрыт Firewall-ом порт 3050, или вообще на компьютере не установлен ни dialup adapter, ни драйвер tcp, ни tcp loopback adapter (если нет ни сетевой карточки ни модема). В этом случае ошибка не выдается, сервер запускается, и "молчит". Опасная ситуация, если на этом компьютере уже запущена альтернативная версия InterBase или Firebird - кто запустился первым, тот и будет обрабатывать все запросы по сети.
2. сервер не нашел одну из runtime-библиотек. Такое случается на "чистых" Windows, где никакое другое ПО (особенно от Microsoft) еще не устанавливалось. Проще всего недостающие файлы обнаруживаются при помощи утилиты filemon с сайта www.sysinternals.com. Скачиваете ее, запускаете, вводите в окне фильтра incude имя exe, который запускаете (в данном случае ibserver.exe, fbserver.exe и т.п.), повторяете команду ibserver -a и смотрите в лог какие файлы пытается загрузить сервер.
* Для InterBase 7.x/2007 это может быть файл libborland_lm.dll. Он находится в каталоге bin, поэтому обычно проблем нет.
* Для Firebird 1.5 и выше это как правило библиотеки msvcp60.dll, msvcrt.dll, для Firebird 2.0 - msvcp71.dll, msvcr71.dll, для Firebird 2.1 - msvcp80.dll, msvcr80.dll - то есть Microsoft Visual C++ Runtime той версии, которой скомпилирована конкретная версия Firebird. Вернитесь на компьютер с работающим сервером Firebird, скопируйте оттуда эти библиотеки (они могут находиться в разных местах, желательно искать их в системных каталогах Windows, а не по всему диску. Еще лучше, скачать редистрибутив для Visual Studio нужной версии с www.microsoft.com), и поместите в каталог bin нашей "скопированной установки". Повторите запуск fbserver -a еще раз, чтобы убедиться, что теперь все нужные файлы для его работы есть.
! Список редистрибутивов Visual C++ Runtime
o FB 2.1 - VC 8 (VS 2005), Runtime. Рекомендуется этот рантайм устанавливать, а не копировать файлы msvc?80.dll
o рантаймы VC 7.1 (VS2003) и VS 6 мне на сайте microsoft.com обнаружить не удалось

Кроме сервера, возможно, вам потребуется обеспечить работу клиентских приложений на этом же компьютере. Для этого приложениям нужна клиентская часть - gds32.dll. Эта библиотека находится в том же подкаталоге bin. И ее (gds32.dll) нужно скопировать в каталог, где клиентские приложения могут ее находить. Если приложение всего одно, то gds32.dll можно положить прямо в каталог приложения. Если приложений несколько, то gds32.dll нужно поместить в PATH. Проще всего gds32.dll скопировать в системный каталог Windows (C:\Windows, C:\WinNT, C:\WinXP или как там у вас).

У Firebird 1.5 и выше название библиотеки клиентской части отличается от остальных версий InterBase и Firebird 1.0. Вместо gds32.dll есть fbclient.dll. Этот файл можно переименовать в gds32.dll, однако при этом есть риск, что не заработают или будут работать "криво" приложения или компоненты, которые ориентируются на версию gds32.dll (например, может не работать services api). Специальная утилита instclient.exe (см. дальше). позволяет сделать из fbclient.dll файл gds32.dll с правильной версией (6.3).

Проверьте теперь работу клиентских приложений с этим сервером. Работают? Ну и хорошо.
Не работают ? Тогда вам придется искать ответ в другой статье...
Только клиентская часть

Небольшое отступление по поводу клиентской части. Если речь идет не об установке сервера, а об установке клиентской части на "пустой" компьютер, то разумеется, нам потребуются
instreg.exe, firebird.msg/interbase.msg, gds32.dll.

Все это можно сложить в одну папку, и запустить оттуда instreg (если это instreg от Firebird 1.5, то он сам прописывает в реестр путь на 1 подкаталог выше. То есть, его надо запускать из специального подкаталога bin, или просто прописать нужный ключ в реестре самостоятельно). Если в реестре не будет информации о местонахождении файла msg, то клиентская часть постоянно будет сообщать что этот файл не найден. При этом, однако, путь к gds32.dll все равно должен быть в PATH, для того чтобы приложения могли найти эту библиотеку.
Кроме того, в Firebird 1.5 есть утилита instclient.exe. Она очень полезна в нескольких смыслах

* позволяет установить клиентскую часть Firebird одной командой.
* позволяет установить клиентскую часть как fbclient.dll либо как gds32.dll
Например, instclient i -f g перезаписывает безусловно текущую версию gds32.dll на компьютере, и также меняет версию в установленной gds32.dll с той целью, чтобы компоненты IBX обнаруживали в ней функции Services API (IBX проверяет это по версии gds32.dll)
* позволяет проверить наличие установленной библиотеки fbclient или gds32
instclient q f или instclient q g соответственно

Помните, что gds32.dll от всех версий InterBase требует наличия в файле services записи
gds_db 3050/tcp
то есть, клиент обращается к серверу только по имени порта, а не по номеру. Клиент Firebird не требует данной настройки начиная с версии Firebird 1.0. Теоретически можно использовать клиентскую часть от Firebird для работы с сервером InterBase, если вы не хотите редактировать файл services. Однако это крайне не рекомендуется, особенно в отношении самых последних версий InterBase и Firebird (несовместимость в протоколах).
Если устанавливать клиентскую часть InterBase стандартным инсталлятором (включая опцию Silent Install), то инсталлятор самостоятельно прописывает нужную строку. Однако, если на компьютере производятся манипуляции с поддержкой tcp, например удаление протокола и его повторная установка, то файл services при переустановке протокола будет заменен на новый, и клиент InterBase перестанет обращаться к серверу. Проблему придется исправлять повторным прописыванием указанной строки в services. Причем, если такая строка является последней в файле services, то необходимо добавить в конец файла пустую строку, иначе подсистема tcp не обнаружит эту запись.
 
Запуск сервиса

Мы запустили сервер "как приложение", но это нормально (и удобно) только на машине разработчика. На сервере, в смысле "сервер, который обслуживает клиентские приложения", более правильным является запуск InterBase или Firebird в виде сервиса. Сделать это, разумеется, можно только на тех версиях Windows, которые поддерживают сервисы

C:\Server\bin\instsvc install C:\Server

Утилита instsvc.exe записывает, удаляет или меняет информацию о запуске сервера в базе сервисов операционной системы. После этой команды, открыв список сервисов, вы обнаружите там InterBase или Firebird. Некоторые могут спросить - а где guardian? Дело в том, что специальный сервис, который бы в случае сбоя сервера мог его перезапускать, не нужен в Windows 2000 и 2003 - эта функциональность отлично настраивается в свойствах сервиса, на закладке Recovery.
Настройте сервис так, как вам нужно - автоматический или ручной запуск, и т.п. Можете его стартовать прямо сейчас, только нужно завершить работу сервера в виде приложения (на иконке в Taskbar нажать правую кнопку, выбрать меню shutdown).
Точно так же как и instreg утилита instsvc без параметров показывает все свои возможные параметры. Кроме того, этой утилитой можно управлять запуском и остановкой сервера-сервиса.
Для Firebird требуется специальное указание instsvc, если вы инсталлируете Classic (fb_inet_server.exe) - ключ -с. По умолчанию регистрируется сервис суперсервера (fbserver.exe).
После установки сервиса рекомендуется проверить, установлена ли галочка Allow service interact with desktop в свойствах сервиса. Если нет, то может не работать "локальный" коннект - дело в том, что только в последних версиях Yaffil и Firebird протокол локального коннекта изменен (и например, для Classic он вообще не работает до версии Firebird 1.5.2), а ранее он был реализован через shared memory, что не позволяет "видеть" сервис сервера из другого сервиса (или иногда даже из приложения). Собственно, если вдруг с локальным коннектом есть проблемы - забудьте про него и используйте протокол tcp, например localhost:c:\dir\data.gdb. Все это уже давно описано в FAQ.
замечание:чем же так "неудобен" сервер в виде сервиса на компьютере разработчика: его "не видно", неудобно останавливать и запускать, может не работать локальный протокол, невозможно отлаживать udf, не видно число активных коннектов и открытых баз, при его остановке не будет выдано предупреждение об открытых базах. Достаточно?
Установка или обновление "поверх"
Вы теперь умеете устанавливать вручную сервер Firebird или InterBase на новый компьютер. Давайте рассмотрим случай, когда поверх Firebird 1.5.0 нужно установить версию 1.5.2, или установить InterBase 7.5.1 поверх InterBase 7.5.0.
замечание: устанавливать Firebird 2.0 поверх Firebird 1.5 или 1.0 (и тем более любой версии InterBase) категорически не рекомендуется.
Самое первое и главное правило - это перед подобными действиями скопировать куда-нибудь весь корневой каталог существующей установки сервера. В случае чего вы сможете удалить неудачный эксперимент, и вернуть весь каталог сервера в его исходном виде обратно. Этим вы избавите себя от необходимости переустановки сервера в случае проблем или неверных действий.
Скопировали? Отлично.
Для Firebird новые версии всегда выпускаются в двух вариантах - как инсталлятор, и как набор файлов. Инсталлятор нас в данном случае не интересует, а вот набор файлов - то что нужно. Это zip, содержащий внутри как раз корневой каталог новой версии сервера! Например,
http://www.ibase.ru/firebird/Firebird-1.5.2.4731_win32_files.zip
При его распаковке нужно быть внимательным:
1. zip содержит подкаталоги, поэтому нужно распаковывать файл с опцией Use folder names, причем не сразу в каталог установки, а в какой-нибудь временный каталог, откуда нужные файлы уже можно перенести в каталог установленного сервера.
2. zip содержит файл конфигурации (firebird.conf/aliases.conf или ibconfig) и файл базы пользователей (security.fdb, admin.ib или isc4.gdb). Переписав эти файлы поверх ваших текущих вы лишитесь не только сделанных настроек, но и списка пользователей сервера. Поэтому эти файлы желательно сразу удалить во временном каталоге, куда вы распаковали zip следуя указаниям в пункте 1.
Теперь можно просто весь корневой каталог новой версии скопировать поверх существующего корневого каталога установленного сервера. Если сервер в этот момент запущен, то разумеется, переписать ibserver.exe, fbserver.exe или fb_inet_server.exe не удастся. Остановите сервер, и перепишите файлы.
Далее, после переписывания новых файлов имеет смысл скопировать новую gds32.dll/fbclient.dll в системный каталог, для того чтобы клиентская часть, используемая приложениями, точно соответствовала версии сервера.
Для InterBase действия немного отличаются, т.к. Borland в последнее время выпускает обновления только в виде полных дистрибутивов. Увы, даже для обновления InterBase 7.5.0 на 7.5.1 вам придется качать с borland.com дистрибутив размером ~60 мегабайт (обновление 7.5.1 SP1 содержит только файлы, и может быть легко установлено "поверх").
Скачали? Теперь выясните, где в вашей текущей операционной системе находится каталог TEMP. Это можно сделать в том же самом окне cmd, откуда производился запуск insreg и других утилит. Выдайте команду
set temp
и операционная система вам покажет его расположение. Теперь, зная имя каталога, зайдите туда обычным Проводником (Explorer) и удалите все старые файлы и остатки от прошлых инсталляций другого ПО. Каталог temp нам нужен чистым (все файлы удалить не удастся, т.к. наверняка будут такие, которые открыты запущенными в данный момент приложеняими. Это не помешает).
Запустите инсталлятор - нужен ib_install.exe, то есть инсталлятор на Java. Инсталлятор install_windows.exe, находящийся в корне установки InterBase может запустить win32- или java-инсталлятор в зависимости от версии 7.1, 7.5 или 7.5.1. В дистрибутиве java-инсталлятор можно найти в папке \Disk1\InstData\Windows\VM. Если у вас ничего кроме win32-инсталлятора нет, то определять, какие файлы куда он записывает, можно только с помощью FileMon (sysinternals.com).
Запустили инсталлятор? Жмите смело Install Borland InterBase 7.5 - в этот момент инсталлятор распакует нужные файлы в temp, мы их скопируем, а саму инсталляцию производить не будем.
Итак, в TEMP у нас образовался каталог I1126692368 (у вас может быть любое другое имя). В нем находятся подкаталоги InstallerData и Windows. Нас интересует InstallerData/Disk1/InstData. Там находится файл Resource1.zip. Собственно, при других именах каталогов или файлов описываемый метод позволяет примерно на 90% обеспечить успешный результат.
Открываем файл Resource1.zip. А еще лучше его скопировать куда-нибудь, распаковать (с подкаталогами!!!), а инсталлятору InterBase 7.5 сказать Cancel и закрыть его.
Теперь смотрите в каталоги, распакованные из Resource1.zip - здесь как раз все то, что нам нужно для "обновления поверх". C_\IB7.5\win32\Server. Не забудьте про admin.ib и ibconfig - лучше их сотрите в этом каталоге, чтобы случайно не переписать аналогичные файлы в вашей текущей установке.
Поскольку лицензионная информация для этого сервера не менялась, сервер остается работоспособным без необходимости его переустановки.
Еще раз обращаю внимание на необходимость копирования исходного каталога сервера перед всеми этими действиями. Только так вы сможете вернуть серверу работоспособное состояние в случае ошибки.
 
Установка серверов "рядом" и поочередный запуск

Изложенный выше вариант годится, если вам надо на конкретном сервере действительно обновить его версию, и все. Разумеется, речь идет об обновлении так называемых "минорных" версий, а не Firebird 1.0 "довести" до Firebird 1.5, или InterBase 7.0 обновить до InterBase 7.5.
Например, у InterBase 7.0 и 7.5 разные лицензии, и безусловно, разная функциональность. У Firebird 1.0 файл конфигурации называется ibconfig, а у FB 1.5 - firebird.conf, отличаются файлы пользователей, и тоже разная функциональность. Кроме того, может элементарно потребоваться проверка новой версии сервера - как она вообще работает, и есть ли смысл обновлять даже InterBase 7.5.0 до 7.5.1 (сразу скажу - смысл ЕСТЬ)? А если работа идет на Firebird 1.5 и хочется посмотреть на InterBase 7.5.1 на этой же машине?
В этом случае вам нужно устанавливать серверы рядом, то есть "параллельно". Стандартные инсталляторы в силу исторических причин могут "перебивать" друг-друга, а даже если сервера и отличаются как Firebird 1.5 от InterBase 7.5, запустить их одновременно не получится (потому что они слушают по умолчанию один и тот же порт tcp). Так что без ручных манипуляций не обойтись.
Допустим, на сервере установлен Firebird 1.5 (или мы устанавливаем его первым, не важно). Надо установить InterBase 7.5, и работать с ними поочередно (можно и параллельно). Последовательность действий следующая:
1. Останавливаем текущий сервер (как приложение или сервис), и убираем в конфигурации сервисов его старт как "автоматический" (меняем на "ручной").
2. Устанавливаем InterBase 7.5 в отдельный каталог (например C:\IB75), как положено, триальную версию или полную с лицензиями.
3. Останавливаем сервис InterBase, как и в пункте 1.
Теперь на компьютере 2 сервера, причем "центральной точкой входа" у них является gds32.dll, не так ли?
Значит для запуска того или иного сервера нам нужно проделывать следующие действия
* разрегистрировать в реестре сервер, который установлен в данный момент
это делается при помощи команды instreg remove
* зарегистрировать в реестре сервер, который нам нужен для работы
это делается при помощи команды instreg install
* переписать правильный gds32.dll в системный каталог
Автоматизировать данные действия можно при помощи cmd-файлов. Вот пример одного из файлов, используемых у меня на компьютере
fb15.cmd

d:\ib75\bin\instreg remove
d:\ib71\bin\instreg remove
d:\intrbase\bin\instreg remove
d:\ya\bin\instreg remove
d:\firebird\bin\instreg install
d:\firebird\bin\fbserver -a

Как видите, параллельно сосуществуют InterBase 7.5, 7.1, Firebird 1.0, Yaffil и Firebird 1.5. Для них сделаны такие же cmd-файлы. Раньше, правда, было еще хуже, т.к. в каталоге d:\intrbase\bin находятся порядка 15-ти разных версий ibserver.exe (в том числе и от IB 6.0, для технических целей). И запуск нужной версии был сделан как параметр, а файлы именовались ibserver_6010, ibserver_6016, 6505 и т.п. (в загашнике есть еще "неавтоматизированные" версии InterBase 4.0/4.1/4.2).
То есть, путем несложных манипуляций можно организовать попеременный запуск любых серверов на одном компьютере. Поскольку в данном случае надо четко видеть, какая именно версия interbase или firebird запущена, то никакая инсталляция или запуск сервера как сервиса не производится (в скрипте видите instsvc?). Версию сервера можно увидеть наведя мышь на иконку сервера в TaskBar.
замечание: если кто-нибудь повторит такое даже в минимальном объеме с целью тестирования, не забудьте пройтись по файлам конфигураций, и установить там одинаковые параметры (например, временный каталог, размер кэша и т.п. Иначе тест будет некорректен.
Будьте предельно внимательны при поочередной работе с серверами. Вы можете открыть базу "не тем сервером", в результате чего или база будет обновлена до недопустимой версии ODS, или вы испортите метаданные (несовместимый blr).
Возвращаемся к gds32.dll. В примере командного файла нет команды copy, которая бы копировала правильный gds32.dll в системный каталог. Дело в том, что как правило на компьютере разработчика в момент смены сервера уже запущены программы, загрузившие gds32.dll. Тогда их придется выгружать, заменять файл, и загружать снова. Чтобы этого не делать, можно
* если вся работа идет в IBExpert - для каждого алиаса БД указать свою (правильный) клиентскую библиотеку (см. настройки алиаса БД).
* если выработать привычку к своим базам всегда коннектиться через localhost, а не через "локальный протокол", то смена gds32.dll может потребоваться только при серъезных отличиях между версиями. К примеру, gds32.dll от InterBase 7.5 прекрасно работает с Firebird 1.5 и 1.0.
* конкретному приложению "подложить" рядом правильную gds32.dll.

Одновременный запуск

Сервер - это не только ценный мех и пачка файлов. У сервера есть
* каталог по умолчанию, прописываемый в реестре (instreg)
* файл конфигурации, находящийся в каталоге по умолчанию
* именованные системные объекты (мютексы и т.п.) которые сервер использует при своей работе
Если перечисленные 3 пункта не конфликтуют между собой у двух отдельно взятых серверов, то их можно запустить одновременно на одном компьютере. Кроме того, Firebird 1.5 и InterBase 7.5 могут быть сконфигурированы так, что две этих версии могут быть запущены одновременно, в любом количестве их воплощений.
Зачем это может понадобиться? Вариантов много. У вас может быть "старая" задача, которую нецелесообразно или сложно переводить на новый сервер, и одновременно "новая" задача, которую нужно реализовать на новой версии сервера. Могут быть две базы, к которым надо давать доступ через свой экземпляр сервера, для повышения надежности. И так далее.
Для обоих серверов (и между собой) для осуществления одновременного запуска нужно соблюдать некоторые правила.
Основное правило - это разведение серверов по разным портам tcp. Для старых серверов InterBase 6.0 и ниже изменить порт сервера можно только при помощи модификации записи gds_db в файле SERVICES. Причем для их же клиента изменить номер порта для соединения с сервером можно только таким же способом. Клиент Firebird 1.0 и выше - напротив, позволяет указать номер порта в строке коннекта с сервером. Для InterBase 7.5 придется конфигурировать SERVICES, добавляя альтернативные строки gds_db - в этой версии серверу можно указать, какое имя порта (не номер) использовать для работы. Сервер Firebird 1.5 позволяет указать номер порта tcp в конфигурационном файле. Таблица совместимости, то есть возможности одновременного запуска, выглядит так:
 
InterBase <=7.1,
Firebird 1.0 Firebird 1.5 InterBase 7.5 Firebird 2.0
InterBase <=7.1,
Firebird 1.0 нет да да да
Firebird 1.5 да см. дальше да см. дальше
InterBase 7.5 да да да да
Firebird 2.0 да да да да

Дальше описано конфигурирование для запуска Firebird 1.5 и InterBase 7.5 как альтернативного сервера относительно уже работающего на компьютере сервера InterBase или Firebird любых версий. При этом подразумевается, что конфигурация серверов InterBase 7.1 и ниже или Firebird 1.0 никак не модифицируется.
Firebird
Разные экземпляры сервера должны быть скопированы в разные каталоги, и запускаться из них. instreg в этом случае для FB 1.5/2.0 запускать нельзя, если вы хотите стартовать одновременно более одного экземпляра FB 1.5 (или несколько штук FB 2.0), в противном случае все запускаемые экземпляры FB 1.5 (или 2.0) будут "видеть" только один каталог сервера.
Механика этого процесса следующая. Допустим, на компьютере установлен FB 2.0 в двух разных каталогах. У одного в конфиге прописан порт (см. дальше) 3052, а у другого - 3050. При этом в реестре запись DefaultInstance указывает на папку, где установлен сервер с конфигом измененным на порт 3052.
При этом на этой же машине подсоединение по умолчанию (без указания порта) будет идти к серверу на порту 3052. Потому что
* клиент будет искать запись в реестре, указывающую на расположение конфига
* клиент возьмет конфиг по пути реестра, и возьмет оттуда порт по умолчанию (а он изменен на 3052
Таким образом, главный момент - удаление записи о пути расположения Firebird в реестре. Далее -
Открываем firebird.conf, ищем параметр CreateInternalWindow (только в FB 1.5). Его надо установить в 0.
Не забудьте, что символ # в файле конфигурации - это символ комментария. И для того, чтобы изменение параметра вступило в силу, его надо раскомментировать, то есть убрать # перед параметром.
RemoteServiceName - Firebird-у как таковому уже давно (с версии 1.0) для работы клиента или сервера не требуется наличие записи gds_db в файле SERVICES операционной системы. Вы и так можете указать нужное имя порта в строке коннекта.
RemoteServicePort - по умолчанию 3050. То есть, основной сервер будет слушать этот порт, а альтернативный сервер - какой-нибудь другой. Например 3100. Меняем параметр, и для всех приложений, которым надо присоединиться к этому, к имени сервера добавляем /3100.
Отдельно имя сервера будет выглядеть так: server/3100
Целиком строка коннекта может выглядеть так: server/3100:c:\dir\data.gdb
Этот параметр можно не менять, если Firebird запускается как приложение. Достаточно указать в командной строке

> fbserver.exe -a -p 3070

и сервер будет слушать порт 3070, а не 3050 по умолчанию.
RemoteAuxPort - это номер порта, по которому идут события (регистрируемые компонентами вроде IBEventAlerter). Если события используются, то порт надо указать явно. Главное - не забудьте открыть этот порт в Firewall, если таковой есть у вас на сервере (и где уже открыт порт 3050, и где будет открыт порт 3100 из предыдущего примера). Выбрать надо что-нибудь не конфликтующее с работающими приложениями. Помочь может утилита tcpview опять же с www.sysinternals.com.
На этом этапе все Ok. Теперь, если речь идет об установке двух Firebird 1.5, то сложным моментом является идентичность имен сервисов и ключей в реестре, которые прописывают instreg и instsvc. Информацию instreg надо убрать (instreg remove), и придется самостоятельно создавать альтернативный сервис в базе сервиса. Сделать это можно используя примеры программ управления сервисами из командной строки и интерактивного.
InterBase 7.5
В этой версии появился режим запуска Muti-Instance, то есть возможность стартовать одновременно несколько экземпляров сервера на одной машине. Однако, Borland внедрил в клиентскую часть возможность добавления не номера порта к имени сервера, а добавление имени порта, что в определенном смысле усложняет конфигурирование одновременного запуска. Кроме того, при инсталляции сразу должна быть указана возможность использования режима Milti-Instance, как для первой установки так и для остальных.
Подробно настройки Multi-instance описаны в OpGuide.pdf, здесь можно отметить следующее:
* кроме настройки серверов на разные имена портов, существует возможность маршрутизации подключений к базам данных (re-routing) при помощи таблицы DB_ROUTE, находящейся в базе admin.ib. Таблица маршрутизации настраивается для сервера, который "слушает" базовый порт gds_db 3050. Именно он будет переадресовывать запросы к указанным в таблице базам на другой сервер, прослушивающий другой порт. Это позволяет избавиться от редактирования файла services, и направлять "старых" клиентов на нужный экземпляр сервера.
* дополнительная таблица DB_ALIAS в admin.ib позволяет создавать алиасы баз данных (как в Firebird 1.5, aliases.conf). Алиасы управляются или напрямую редактированием этой таблицы, или ключами -alias_* утилиты gsec.
Firebird 2.0, поочередный и одновременный запуск
В Firebird 2.0 изменилась схема аутентификации пользователей. Собственно, с внешней стороны все осталось как было, но
* новая база пользователей и паролей называется security2.fdb
* сервер запрещает подсоединение к security2.fdb
кроме этого, шифрование паролей в security2.fdb при включении параметра LegacyHash 0 производится MD5, а не DES, как это было во всех версиях IB/FB. По умолчанию используется совместимый способ (DES).
Тем не менее, при установке вручную нет никаких проблем, так же как и с параллельной установкой и запуском серверов других версий. Можно использовать instreg - информация в реестре для FB 1.5 и 2.0 не пересекается.
Например, вполне успешно работает одновременный запуск FB 1.5 и 2.0 в конфигурации
* Firebird 1.5, instreg, без изменений в firebird.conf
* Firebird 2.0, instreg, в firebird.conf RemoteServicePort изменен на 3070
При установке двух FB 2.0 на разных портах, как было указано ранее, необходимо удалить запись о корневом каталоге Firebird из реестра.
Итог
Теперь вы знаете практически все тонкости ручной установки InterBase и Firebird. В статье опущен ряд подробностей, например, ключи реестра, которые прописывает instreg - оставлю это в виде "домашнего задания", тем более что на www.sysinternals.com есть утилита regmon, которая очень похожа на filemon, уже упомянутый в этой статье. Также пропущен Firebird Embedded - собственно, никаких отличий от установки "только файлы" здесь нет, разве что не требуется запуск instreg.
Дерзайте, пробуйте. Надеюсь, эта статья облегчит использование серверов Firebird и InterBase на вашем компьютере, а значит вы сможете уделить больше внимания качеству своих приложений.
 
Благодарности

* Спасибо компании Borland за InterBase
* Спасибо разработчикам Firebird, а также Firebird Foundation за финансовую поддержку проекта Firebird
* Спасибо Владу Хорсуну и Дмитрию Еманову за замечания и поправки.

вторник, 1 марта 2011 г.

Бесплатные видео-плееры для веб-сайта или блога

01. Flowplayer
Flowplayer представляет собой видео-плеер для веб, который распространяется с исходным кодом. Вы можете использовать его для того, чтобы встраивать видео в собственные веб-сайты. Приложение разработано специально для владельцев сайтов, разработчиков и серьезных программистов. Используя данное приложение, вы сможете создать плеер с индивидуальным оформлением, и разместить его на вашем веб-сайте.

Свойства:

* бесплатный
* возможность разработки собственного плеера за несколько минут
* Плавный как шелк – плеер оптимизирован на работу в среде веб. Строка прогресса перемещается очень быстро и плавно. Также есть два эффекта автоскрытия: «исчезание» и «скольжение».
* Возможность прогонять поток различными способами – протоколы RTMP или HTTP со многими сервисами типа lighttpd, Apache, nginx или IIS; или прогоняйте свои видео-файлы посредством сетей Akamai, Amazon Cloudfront, Highwinds, HDDN, SimpleCDN и многих других.
* Расширенные веб-стандарты – Flowplayer разработан при помощи технологии Flash, что гарантирует то, что 90% пользователей сети Интернет смогут просматривать ваши видео-файлы. Также в плеере встроен уникальный API JS, который может менять способ взаимодействия с Flash.

02. Video LightBox
Video LightBox представляет собой JS-приложение, с помощью которого вы без труда сможете встроить видео в ваше веб-сайт, веб-страницу или блог. Вся работа требует нескольких кликов, и вам даже не обязательно разбираться в коде.

Video LightBox распространяется абсолютно бесплатно, если будет использовано не в коммерческих целях. Для использования на коммерческих веб-сайтах вам придется заплатить незначительную сумму за лицензию. Video LightBox Business Edition также предоставляет вам возможность удаления водного знака с указанием источника.

Свойства:

* возможность внедрения файлов flv, mp4, 3gp
* возможность добавления видео с Youtube, Facebook, Google Video, Metacafe, Vimeo, MySpace
* версии для Mac и Windows
* соответствие с XHTML
* автоматическое создание миниатюр
* возможность добавления описания
* многочисленные темы оформления
* встроенный сервер FTP

03. JW Player
JW Player представляет собой гибкий flash-видео-плеер. Он поддерживает почти любой формат FLV, H.264, MP4, MP3, AAC, JPG, PNG и GIF. Он также поддерживает различные потоки и форматы плей-листов (RMTP, HTTP и так далее), а также расширенный API javascript.

Свойства:

* Вы можете менять внешний вид плеера
* Хорошая система плагинов – с помощью плагинов вы можете реализовать почти все. Вы можете разрабатывать собственные плагины посредством Developer SDK и дополнительных ресурсов, или ознакомиться с уже готовыми плагинами типа Analytics, Viral, Adtonomy, Rate It и так далее
* Легкое управление видео

04. GDD FLVPlayer

GDD FLVPlayer представляет собой бесплатную функцию проигрывания FLV/mp4 (MPEG-4 файлы, оптимизированные для работы во flash) файлов. С помощью GDD FLVPlayer вы с легкостью сможете проигрывать видео-файлы, и вам не потребуется каких-либо дополнительных знаний в области инструментов разработки Flash.

Свойства:

* полностью настраиваемая панель управления
* возможность разместить свои файлы FLV или mp4 за несколько кликов
* добавляйте видео в любые Flash-проекты за секунду
* возможность добавления собственного интро или рекламных знаков
* возможность использовать собственный логотип в плеере
* возможность устанавливать любой размер видео
* все абсолютно бесплатно
* не нужны специальные знания программинга

05. MC Media Player
MC Media Player представляет собой медиа-плеер, разработанный на Flash, с помощью которого вы сможете встраивать видео, аудио и даже изображения в ваши веб-страницы. Приложение бесплатно как для коммерческих, так и для личных целей.

В данный момент доступны 2 версии плеера: MC Classic (ранее известный как версия 720*360) и MC Altair (бета).

MC Altair – версия представляет собой один файл плеер, который очень просто настроить и оформить. Он поддерживает форматы FLV и H.264 (прогрессивное скачивание и поток RTMP).
MC Classic – изначально был только этот проект, но сейчас он уже приостановлен и вряд ли когда-то будет разрабатываться дальше.

Свойтсва:

* настраиваемый интерфейс
* может работать как на сервере MC Media Player, так и на вашем собственном
* возможность масштабирования

06. Video Player Pro
Video Player Pro представляет собой еще один полезный бесплатный инструмент, который легко настроить и добавить на собственный сайт. Он бесплатен, если вы будете использовать его в личных целях.

Свойства:

* совмещает в себе все ваши видео и представляет их одной привлекательной коллекцией
* Video Player Pro поставляется в различных версиях, которые отличаются функциями, требуемыми на вашем личном сайте
* просматривайте видео в том виде, в котором их удобнее всего просматривать
* не требуется знаний в программировании Flash

07. VISCOM Web Player
VISCOM Web Player – это бесплатная платформа независимого веб-видео-плеера, который вы без труда сможете внедрить в собственный веб-сайт, блог, форум, или аккаунт на myspace и так далее.

Свойства:

* поддержка проигрывания видео в формате flv на вашем сайте
* поддержка плей-листа в формате xml, так что вы можете добавлять несколько видео
* включение/отключение списка миниатюр
* поддержка полноэкранного режима
* поддержка автоперехода к следующему видео в плей-листе
* поддержка управления соотношением сторон дисплея
* не требуется специальных знаний программирования
* включены шкуры оформления высокого качества

08. SS4UPlayer
SS4UPlayer представляет собой гибкий видео-плеер для веб-страниц, который поддерживает проигрывание прямо с потока, или метод прогрессивного скачивания. Работает как на системах Windows, так и на Linux. Поддерживает форматы FLV, 264, MP4, MP3. Плеер обладает множеством настроек flashvar, которыми можно управлять посредством JS. Вы можете полностью изменить внешний вид посредством системы тем оформления на основе XML.

Свойства:

* старт/пауза, строка прогресса, таймер, полноэкранный режим, уровень громкости, предварительный просмотр
* вы можете загрузить персональный логотип
* полноценный Flash AS3 с классами и пакетами
* возможность загрузки видео посредством flashvars в JS или посредством файла XML
* плей-листы на основе XML
* поддержка как потокового проигрывания, так и прогрессивного скачивания
* возможность оформления по собственным предпочтениям

09. Anarchy Media Player
Anarchy Media Player разработан специально для тех, кто привык к удобству и простоте в использовании. С его помощью вы без труда разместите видео или аудио на своем сайте, и это содержимое можно будет воспроизвести прямо со страниц сайта. Приложение распространяется по лицензионному соглашению GNU General Public License.

10. SublimeVideo
SublimeVideo представляет собой HTML5-видеоплеер, с помощью которого вы без труда сможете внедрить видео в любую веб-страницу, руководствуясь самыми современными веб-стандартами.

Разработчики браузеров все еще ведут работу над разработкой полноценной поддержки спецификации видео HTML5, так что данный браузер пока что является экспериментальным и будет работать не во всех браузерах. Но в будущем его точно можно будет применять во всех браузерах.

SublimeVideo вскоре будет выпускаться абсолютно бесплатно (по крайней мере, версия, предназначенная для некоммерческих целей).

Свойства:

* возможность масштабирования по всему размеру окна просмотра в браузере
* полноэкранный режим
* преимущества видео HTML5 – никаких плагинов, никакой зависимости от Flash. Вы также можете перейти к любому фрагменту видео без задержки на загрузку буфера
* отдельная библиотека javascript

11. Uppod Player
Свойства:
* online-генератор настроек
* работа во всех популярных браузерах
* возможность использовать заставку
* все файлы на вашем сервере
* малый вес — около 20Кб
* темы оформления (скины)
* приятный дизайн
* выбор цвета
* развитие проекта

12. TarantinovFLV2
Универсальный Flash FLV плеер с поддержкой RTMP соединений, для организации online видео на cайте