Про сервер MS SQL - которого нет ...
Модератор: Andrew™
Правила форума
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
При написании вопроса или обсуждении проблемы, не забывайте указывать версию Clarion который Вы используете.
А так же пользуйтесь спец. тегами при вставке исходников!!!
- Игорь Столяров
- Ветеран движения
- Сообщения: 7373
- Зарегистрирован: 07 Июль 2005, 10:19
- Откуда: г. Ростов-на-ДоМу
- Благодарил (а): 13 раз
- Поблагодарили: 48 раз
Про сервер MS SQL - которого нет ...
Привет всем ! Есть вопрос по существу, точнее по MS SQL ...
Написана программа, которая периодически подключается к MS SQL серверу и что-то там забирает или записывает. Все очень хорошо, до тех пор пока SQL сервер доступен. Как только он исчезает из сети - прогамма вылетает, либо с ошибкой, либо с GPF при попытке получить доступ к БД ...
Пробовал открывать БД SQL и ABC классами и просто Open().
Отсюда вопрос - можно как-нибудь проверить наличие и готовность MS SQL сервера не подключаясь к БД. Т.е. просто отработать ситуацию - если сервер не доступен, то и не пытаться с ним работать ... Спасибо за любую подсказку !
Написана программа, которая периодически подключается к MS SQL серверу и что-то там забирает или записывает. Все очень хорошо, до тех пор пока SQL сервер доступен. Как только он исчезает из сети - прогамма вылетает, либо с ошибкой, либо с GPF при попытке получить доступ к БД ...
Пробовал открывать БД SQL и ABC классами и просто Open().
Отсюда вопрос - можно как-нибудь проверить наличие и готовность MS SQL сервера не подключаясь к БД. Т.е. просто отработать ситуацию - если сервер не доступен, то и не пытаться с ним работать ... Спасибо за любую подсказку !
- Andrew Listiev
- Активист
- Сообщения: 166
- Зарегистрирован: 07 Июль 2005, 11:16
- Откуда: Латвия, Рига
- Игорь Столяров
- Ветеран движения
- Сообщения: 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 процедуру проверки наличия сервера и подключения к нему (есстественно не к самомму серверу, а БД на нем).
Может я просто козлю ?
Программа работает в циклической обработке, т.е. раз в минуту (например) пытается получить подключение к 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.
По поводу не-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 - я к сожалению это юзал последний раз - никогда ...
А вот с MS SQL, что-то странное. С63 - вообще преподносился как средство работы с MS SQL, и сразу вырубились ХП без параметров (в 9053 - исправили) + GPF при обращении ...
Ну не может такого быть. Может быть Clarion и его драйвера затачиваются уже под MS SQL 2005 ?!
А нет ли какого-нибудь примерчика с обращением к MS SQL через ODBC - я к сожалению это юзал последний раз - никогда ...
За теми кто отстал - не возвращаться. (С) Кодекс
- StillZero
- Ветеран
- Сообщения: 454
- Зарегистрирован: 06 Июль 2005, 2:17
- Откуда: Хабаровск
- Контактная информация:
определить список серверов может через сокеты
у самого руки не дошли, так что только исходный текст
у самого руки не дошли, так что только исходный текст
Код: Выделить всё
Перечислить все 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);
проверить есть ли соединение с сервером можно воспользовавшись функцией:Игорь Столяров писал(а): А нет ли какого-нибудь примерчика с обращением к 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 раз
- Олег
- Ветеран движения
- Сообщения: 122
- Зарегистрирован: 16 Июль 2005, 2:35
- Откуда: Москва
- Контактная информация:
До 2005 SQL`я все необходимые заголовочные файлы (*.h) шли вместе с дистрибутивом и устанавливались в его каталог. Сейчас глянул SQL-2005 Express - там всего несколько заголовочных файлов, в которых часть констант имеют немного измененные названия, а части просто нет! Так что - или искать дистрибутив старых версий SQL или идти на сайт MS и читать MSDN по ODBC-API.
Игорь Столяров писал(а):Да, спасибо 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)
Код: Выделить всё
! === 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)
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))
Код: Выделить всё
IF ~(SELF.RetCode = SQL_SUCCESS OR SELF.RetCode = SQL_SUCCESS_WITH_INFO)
! ошибка
END
Закрыть соединение
забыл сказать ещё про одну функцию, соединение то открыли, но его надо бы и закрыть после этого
а вообще, *.h* заголовочные файлы я взял от Microsoft Visual Studio и адаптировал под Clarion, удачи
Код: Выделить всё
SQLDisconnect(LONG hdbc),SHORT,RAW,PASCAL,NAME('SQLDISCONNECT'),PROC!,DLL(1)
ODBC32.DLL
ещё забыл сказать, чтобы эти функции заюзать в проекте надо соответсвующий 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)
Нужно вторым значением передавать не сам адрес переменной, а значение по этому адресу ... Или я не прав ?
Первый вызов отрабатывает нормально, а со второй возвращает ошибку - насколько я смог понять из-за описанной причины ...
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
так что вызывай сразу
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
- Откуда: Латвия, Рига