Про сервер MS SQL - которого нет ...

ODBC

Модератор: Andrew™

Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7373
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Про сервер MS SQL - которого нет ...

Сообщение Игорь Столяров »

Привет всем ! Есть вопрос по существу, точнее по MS SQL ...

Написана программа, которая периодически подключается к MS SQL серверу и что-то там забирает или записывает. Все очень хорошо, до тех пор пока SQL сервер доступен. Как только он исчезает из сети - прогамма вылетает, либо с ошибкой, либо с GPF при попытке получить доступ к БД ... :(
Пробовал открывать БД SQL и ABC классами и просто Open().

Отсюда вопрос - можно как-нибудь проверить наличие и готовность MS SQL сервера не подключаясь к БД. Т.е. просто отработать ситуацию - если сервер не доступен, то и не пытаться с ним работать ... Спасибо за любую подсказку !
Аватара пользователя
Andrew Listiev
Активист
Сообщения: 166
Зарегистрирован: 07 Июль 2005, 11:16
Откуда: Латвия, Рига

Сообщение Andrew Listiev »

Это как так вылетает при простом Open()?????? Не верю! Версия Клары и MS SQL в студию!
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7373
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Сообщение Игорь Столяров »

Clarion C63EE 9053 + MSSQL 2000 кажется SP1

Программа работает в циклической обработке, т.е. раз в минуту (например) пытается получить подключение к MS SQL и сделать нечто.
Какое-то время по Open(TableName); If ErrorCode then ... можно отлавливать "отваливший" сервер. Но через какое-то время работы - это заканчивается GPF ...
Проверено, к сожалению, не однократно и на разных сетях и серверах.
Отсюда и возникла идея - проверить наличие сервера и его доступность ДО обращения к нему, желательно без средств Clarion, может API есть ?. Мой опыт общения с MS SQL из Clarion - полгода, и опыта и готовых наработок нет.
Или, если можно, опишите ПРАВИЛЬНУЮ с точки зрения Clarion процедуру проверки наличия сервера и подключения к нему (есстественно не к самомму серверу, а БД на нем).
Может я просто козлю ? ;)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

Сообщение Дед Пахом »

Про MS SQL не скажу, а драйвера ODBC и Pervasive действительно при потере соединения при обращении к таблице вызывают моментальный gpf, причём это началось на C63 с первого же патча, ещё на C62 в такой ситуации было нормальное сообщение об ошибке и возможность работать дальше.
По поводу не-Clarion средств - наверно, и odbc api можно заюзать (проще всего), и что-то типа sql-dmo конкретно для ms sql.
С уважением, ДП
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7373
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Сообщение Игорь Столяров »

Ну с P.SQL - я как раз-таки разобраться могу. Там, как крайность, можно "в лоб" пробить список через Btrieve.
А вот с MS SQL, что-то странное. С63 - вообще преподносился как средство работы с MS SQL, и сразу вырубились ХП без параметров (в 9053 - исправили) + GPF при обращении ... :(
Ну не может такого быть. Может быть Clarion и его драйвера затачиваются уже под MS SQL 2005 ?!

А нет ли какого-нибудь примерчика с обращением к MS SQL через ODBC - я к сожалению это юзал последний раз - никогда ... ;)
За теми кто отстал - не возвращаться. (С) Кодекс
Аватара пользователя
StillZero
Ветеран
Сообщения: 454
Зарегистрирован: 06 Июль 2005, 2:17
Откуда: Хабаровск
Контактная информация:

Сообщение StillZero »

определить список серверов может через сокеты
у самого руки не дошли, так что только исходный текст

Код: Выделить всё

Перечислить все SQL сервера в системе.

public static void FindSqlServers (ISQLServerInfoCollection list, int timeout, int port)
       {
          EndPoint point = new IPEndPoint(IPAddress.Broadcast, port);

         Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
         socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            socket.Blocking = false;

            byte[] data = {0x02};
         socket.SendTo(data, point);

         byte[] buffer = new byte[512];

          Thread.Sleep(timeout);

          try
         {
              int size = socket.ReceiveFrom(buffer, ref point);
               while (size > 0)
             {
                  SQLServerInfoImpl info = new SQLServerInfoImpl(new string(Encoding.ASCII.GetChars(buffer, 0, size)));

                   if (!list.Contains(info))
                       list.Add(info);

                 size = socket.ReceiveFrom(buffer, ref point);
               }
          }
          catch {}
      }

public SQLServerInfoImpl (string reply)
       {
          string[] data = reply.Split(';', '\0');

            for (int index = 0; index < data.Length; index++)
            {
              if (data[index] == "InstanceName")
                {
                  _instanceName = data[index + 1];
                    index++;
                }

              if (data[index] == "ServerName")
              {
                  _hostName = data[index + 1];
                    index++;
                }

              if (data[index] == "tcp")
             {
                  _port = Convert.ToInt32(data[index + 1]);
                   index++;
                }
          }

          if (_instanceName == "MSSQLSERVER")
               _instanceName = null;
       }


Более правильный вариант
SOCKET hSocket;
BOOL fBroadcast = TRUE;
Byte Data[]={0x02};
Byte Buf[65535];
int i,iBeg,tRes,tLenSA,tLenBufRecv,tFlagStep;
u_long tLenBufIOCTL;
TStringList *MyStr;
AnsiString S,S2,S3;

MyStr=new TStringList;

sockaddr_in saSQLSend,saSQLRecv;

ListBox1->Clear();
MyStr->Clear();


hSocket=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
if(hSocket==INVALID_SOCKET) return;


tRes=setsockopt(hSocket,SOL_SOCKET,SO_BROADCAST,(CHAR *)&fBroadcast,sizeof(BOOL));
if(tRes==SOCKET_ERROR) {closesocket(hSocket);return;}


saSQLSend.sin_family = AF_INET;
saSQLSend.sin_port= htons ( 1434 );
saSQLSend.sin_addr.s_addr = htonl ( INADDR_BROADCAST );
tRes=sendto(hSocket,Data,1,0,(SOCKADDR *)&saSQLSend,sizeof(SOCKADDR_IN));
if(tRes==SOCKET_ERROR) {closesocket(hSocket);return;}

Sleep(100);


tRes=ioctlsocket(hSocket,FIONREAD,&tLenBufIOCTL);
if(tRes==SOCKET_ERROR) {closesocket(hSocket);return;}


if(tLenBufIOCTL>0)
        {
        tFlagStep=0;
        tLenSA=sizeof(SOCKADDR_IN);
        saSQLRecv=saSQLSend;
        tLenBufRecv=recvfrom(hSocket,Buf,65535,0,(SOCKADDR *) &saSQLRecv,&tLenSA);
        if(tLenBufRecv==SOCKET_ERROR) {closesocket(hSocket);return;}
        iBeg=1;
        S2=(char *)(Buf+3);
        tLenBufRecv-=3;
        for(i=1;i<=tLenBufRecv;i++)
                {
                if(S2[i]==';')
                        {
                        S=S2.SubString(iBeg,i-iBeg);
                        if(tFlagStep==1) S3=S;
                        if(tFlagStep==2)
                                {
                                if(S!="MSSQLSERVER") S3+=("\\"+S);
                                MyStr->Add(S3);
                                ListBox1->Items->Add(S3);
                                S3="";
                                }
                        tFlagStep=0;
                        if(S=="ServerName") tFlagStep=1;
                        if(S=="InstanceName") tFlagStep=2;
                        iBeg=i+1;
                        }
                }
        }
closesocket(hSocket);
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение Andrew™ »

Игорь Столяров писал(а): А нет ли какого-нибудь примерчика с обращением к MS SQL через ODBC - я к сожалению это юзал последний раз - никогда ... ;)
проверить есть ли соединение с сервером можно воспользовавшись функцией:

Код: Выделить всё

    SQLDriverConnect(|
    LONG        hdbc,|
    UNSIGNED    hwnd,|
    *CSTRING      szConnStrIn,|
    SHORT       cbConnStrIn,|
    *CSTRING      szConnStrOut,|
    SHORT       cbConnStrOutMax,|
    *SHORT      pcbConnStrOut,|
    USHORT      fDriverCompletion),SHORT,RAW,PASCAL,NAME('SQLDRIVERCONNECT'),PROC!,DLL(1)
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7373
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Сообщение Игорь Столяров »

Да, спасибо SQLDriverConnect (или SQLConnect) - это видимо то, что нужно.
Начал разбираться, но там куча предустановленных в заголовках C констант и флагов - не подскажите, есть ли в природе эти заголовки для Clarion (или хотя бы для C) ? :(
Аватара пользователя
Олег
Ветеран движения
Сообщения: 122
Зарегистрирован: 16 Июль 2005, 2:35
Откуда: Москва
Контактная информация:

Сообщение Олег »

До 2005 SQL`я все необходимые заголовочные файлы (*.h) шли вместе с дистрибутивом и устанавливались в его каталог. Сейчас глянул SQL-2005 Express - там всего несколько заголовочных файлов, в которых часть констант имеют немного измененные названия, а части просто нет! Так что - или искать дистрибутив старых версий SQL или идти на сайт MS и читать MSDN по ODBC-API.
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Сообщение Andrew™ »

Игорь Столяров писал(а):Да, спасибо SQLDriverConnect (или SQLConnect) - это видимо то, что нужно.
Начал разбираться, но там куча предустановленных в заголовках C констант и флагов - не подскажите, есть ли в природе эти заголовки для Clarion (или хотя бы для C) ? :(

Код: Выделить всё

SQL_HANDLE_ENV            EQUATE(1)
SQL_HANDLE_DBC            EQUATE(2)
SQL_NULL_HANDLE           EQUATE(0)        
SQL_DRIVER_COMPLETE_REQUIRED    EQUATE(3)
SQL_ERROR               EQUATE(-1)
SQL_SUCCESS             EQUATE(0)
SQL_SUCCESS_WITH_INFO   EQUATE(1)

Код: Выделить всё

    SQLAllocHandle(SHORT HandleType,LONG InputHandle,*LONG OutputHandle),SHORT,RAW,PASCAL,NAME('SQLAllocHandle'),PROC!,DLL(1)
SELF.henv и SELF.hdbc понятно из прототипа - LONG

Код: Выделить всё

 ! === Allocate environment handle
 SELF.retcode = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, SELF.henv)

Код: Выделить всё

 ! === Allocate connection handle
 SELF.retcode = SQLAllocHandle(SQL_HANDLE_DBC, SELF.henv, SELF.hdbc)
class_W - любое открытое окно, можно воспользоваться и 0
SELF.ConnectString.S - CSTRING - собслвенно строка соединения
SELF.ConnectString.Pos - LEN(SELF.ConnectString.S)
SELF.szOutConn - CSTRING(256) ! output
255 - LEN(SELF.szOutConn)
SELF.cbOutConn - SHORT
ну а последний параметр на усмотрение, надо тебе штатное логин окно DRIVERа при неправильных параметрах соединения или нет

Код: Выделить всё

 SELF.retCode = SQLDriverConnect(SELF.hdbc,class_W{PROP:Handle},SELF.ConnectString.S,|
        SELF.ConnectString.Pos,SELF.szOutConn, |
    255, SELF.cbOutConn, CHOOSE(NOT DefaultLogon,0,SQL_DRIVER_COMPLETE_REQUIRED))
SELF.retCode после каждого вызова проверяй на ошибку:

Код: Выделить всё

 IF ~(SELF.RetCode = SQL_SUCCESS OR SELF.RetCode = SQL_SUCCESS_WITH_INFO)
   ! ошибка
 END
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

Закрыть соединение

Сообщение Andrew™ »

забыл сказать ещё про одну функцию, соединение то открыли, но его надо бы и закрыть после этого

Код: Выделить всё

    SQLDisconnect(LONG hdbc),SHORT,RAW,PASCAL,NAME('SQLDISCONNECT'),PROC!,DLL(1)
а вообще, *.h* заголовочные файлы я взял от Microsoft Visual Studio и адаптировал под Clarion, удачи
Аватара пользователя
Andrew™
SQL профи
Сообщения: 651
Зарегистрирован: 05 Июль 2005, 16:32
Откуда: Москва, Зеленоград

ODBC32.DLL

Сообщение Andrew™ »

ещё забыл сказать, чтобы эти функции заюзать в проекте надо соответсвующий LIB подлинковать к проекту, который в свою очередь создаётся LIBMAKERом из ODBC32.DLL
Аватара пользователя
Игорь Столяров
Ветеран движения
Сообщения: 7373
Зарегистрирован: 07 Июль 2005, 10:19
Откуда: г. Ростов-на-ДоМу
Благодарил (а): 13 раз
Поблагодарили: 48 раз

Сообщение Игорь Столяров »

Видимо я совсем темный ... После первого вызова:

SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, SELF.henv)

в SELF.henv - будет адрес, а для второго вызова:

SQLAllocHandle(SQL_HANDLE_DBC, SELF.henv, SELF.hdbc)

Нужно вторым значением передавать не сам адрес переменной, а значение по этому адресу ... Или я не прав ?

Первый вызов отрабатывает нормально, а со второй возвращает ошибку - насколько я смог понять из-за описанной причины ... :(
Аватара пользователя
Дед Пахом
Старичок
Сообщения: 3133
Зарегистрирован: 07 Июль 2005, 16:51
Откуда: Москва, Россия
Благодарил (а): 10 раз
Поблагодарили: 28 раз
Контактная информация:

Сообщение Дед Пахом »

Есть такие (и много других) ODBC API-свойства:
PROP:hdbc
PROP:hstmt
PROP:henv

так что вызывай сразу

Код: Выделить всё

SELF.retCode = SQLDriverConnect(myfile{prop:hdbc},class_W{PROP:Handle},SELF.ConnectString.S,| 
        SELF.ConnectString.Pos,SELF.szOutConn, | 
    255, SELF.cbOutConn, CHOOSE(NOT DefaultLogon,0,SQL_DRIVER_COMPLETE_REQUIRED))
С уважением, ДП
Аватара пользователя
Andrew Listiev
Активист
Сообщения: 166
Зарегистрирован: 07 Июль 2005, 11:16
Откуда: Латвия, Рига

Сообщение Andrew Listiev »

А не должел ли быть открытым файл при использовании такой myfile{prop:hdbc} конструкции ?? :wink:
Ответить