Страница 1 из 3
					
				Про сервер MS SQL - которого нет ...
				Добавлено: 19 Июнь 2006, 19:02
				 Игорь Столяров
				Привет всем ! Есть вопрос по существу, точнее по MS SQL ...
Написана программа, которая периодически подключается к MS SQL серверу и что-то там забирает или записывает. Все очень хорошо, до тех пор пока SQL сервер доступен. Как только он исчезает из сети - прогамма вылетает, либо с ошибкой, либо с GPF при попытке получить доступ к БД ... 
 
Пробовал открывать БД SQL и ABC классами и просто Open().
Отсюда вопрос - можно как-нибудь проверить наличие и готовность MS SQL сервера не подключаясь к БД. Т.е. просто отработать ситуацию - если сервер не доступен, то и не пытаться с ним работать ... Спасибо за любую подсказку !
 
			 
			
					
				
				Добавлено: 19 Июнь 2006, 20:39
				 Andrew Listiev
				Это как так вылетает при простом Open()?????? Не верю! Версия Клары и MS SQL в студию!
			 
			
					
				
				Добавлено: 19 Июнь 2006, 21:15
				 Игорь Столяров
				Clarion C63EE 9053 + MSSQL 2000 кажется SP1
Программа работает в циклической обработке, т.е. раз в минуту (например) пытается получить подключение к MS SQL и сделать нечто.
Какое-то время по Open(TableName); If ErrorCode then ... можно отлавливать "отваливший" сервер. Но через какое-то время работы - это заканчивается GPF ... 
Проверено, к сожалению, не однократно и на разных сетях и серверах.
Отсюда и возникла идея - проверить наличие сервера и его доступность ДО обращения к нему, желательно без средств Clarion, может API есть ?. Мой опыт общения с MS SQL из Clarion - полгода, и опыта и готовых наработок нет. 
Или, если можно, опишите ПРАВИЛЬНУЮ с точки зрения Clarion процедуру проверки наличия сервера и подключения к нему (есстественно не к самомму серверу, а БД на нем). 
Может я просто козлю ? 

 
			 
			
					
				
				Добавлено: 19 Июнь 2006, 21:34
				 Дед Пахом
				Про MS SQL не скажу, а драйвера ODBC и Pervasive действительно при потере соединения при обращении к таблице вызывают моментальный gpf, причём это началось на C63 с первого же патча, ещё на C62 в такой ситуации было нормальное сообщение об ошибке и возможность работать дальше.
По поводу не-Clarion средств - наверно, и odbc api можно заюзать (проще всего), и что-то типа sql-dmo конкретно для ms sql.
			 
			
					
				
				Добавлено: 19 Июнь 2006, 22:30
				 Игорь Столяров
				Ну с P.SQL - я как раз-таки разобраться могу. Там, как крайность, можно "в лоб" пробить список через Btrieve. 
А вот с MS SQL, что-то странное. С63 - вообще преподносился как средство работы с MS SQL, и сразу вырубились ХП без параметров (в 9053 - исправили) + GPF при обращении ... 

Ну не может такого быть. Может быть Clarion и его драйвера затачиваются уже под MS SQL 2005 ?!
А нет ли какого-нибудь примерчика с обращением к MS SQL через ODBC - я к сожалению это юзал последний раз - никогда ... 

 
			 
			
					
				
				Добавлено: 20 Июнь 2006, 1:52
				 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);
 
			 
			
					
				
				Добавлено: 20 Июнь 2006, 8:44
				 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)
 
			 
			
					
				
				Добавлено: 20 Июнь 2006, 17:46
				 Игорь Столяров
				Да, спасибо SQLDriverConnect (или SQLConnect) - это видимо то, что нужно.
Начал разбираться, но там куча предустановленных в заголовках C констант и флагов - не подскажите, есть ли в природе эти заголовки для Clarion (или хотя бы для C) ? 

 
			 
			
					
				
				Добавлено: 21 Июнь 2006, 3:15
				 Олег
				До 2005 SQL`я все необходимые заголовочные файлы (*.h) шли вместе с дистрибутивом и устанавливались в его каталог. Сейчас глянул SQL-2005 Express - там всего несколько заголовочных файлов, в которых часть констант имеют немного измененные названия, а части просто нет! Так что - или искать дистрибутив старых версий SQL или идти на сайт MS и читать MSDN по ODBC-API.
			 
			
					
				
				Добавлено: 21 Июнь 2006, 8:07
				 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
 
			 
			
					
				Закрыть соединение
				Добавлено: 21 Июнь 2006, 8:18
				 Andrew™
				забыл сказать ещё про одну функцию, соединение то открыли, но его надо бы и закрыть после этого
Код: Выделить всё
    SQLDisconnect(LONG hdbc),SHORT,RAW,PASCAL,NAME('SQLDISCONNECT'),PROC!,DLL(1)
а вообще, *.h* заголовочные файлы я взял от Microsoft Visual Studio и адаптировал под Clarion, удачи
 
			 
			
					
				ODBC32.DLL
				Добавлено: 21 Июнь 2006, 8:20
				 Andrew™
				ещё забыл сказать, чтобы эти функции заюзать в проекте надо соответсвующий LIB подлинковать к проекту, который в свою очередь создаётся LIBMAKERом из ODBC32.DLL
			 
			
					
				
				Добавлено: 21 Июнь 2006, 10:25
				 Игорь Столяров
				Видимо я совсем темный ... После первого вызова:
SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, SELF.henv)
в SELF.henv - будет адрес, а для второго вызова:
SQLAllocHandle(SQL_HANDLE_DBC, SELF.henv, SELF.hdbc)
Нужно вторым значением передавать не сам адрес переменной, а значение по этому адресу ... Или я не прав ?
Первый вызов отрабатывает нормально, а со второй возвращает ошибку - насколько я смог понять из-за описанной причины ... 

 
			 
			
					
				
				Добавлено: 21 Июнь 2006, 10:59
				 Дед Пахом
				Есть такие (и много других) 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))
 
			 
			
					
				
				Добавлено: 21 Июнь 2006, 11:06
				 Andrew Listiev
				А не должел ли быть открытым файл при использовании такой myfile{prop:hdbc} конструкции ??  
