Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Мастера, подскажите как сделать так, чтобы [D6, MSSQL]


svt ©   (2006-10-17 09:45:00) 

Мастера, подскажите как сделать так, чтобы пользователь мог выбрать из списка ту базу с которой ему необходимо работать. База реализована на mssql. На сервере их 3-4 (базы). Как это сделать.... динамически сгенерировать строку подключения... короче говоря необходимо вывести список имеющихся баз и после этого строить строку ConnectionString в ADOConnection1.  заранее благодарен


MsGuns   (2006-10-17 10:52:00) [1]

Процедура опроса доступных в сети серверов не совершенна т.к. зависит от загрузки сети и "реактивности" скл-серверов. Иногда она возвращает неполный список (например, если некоторый шибко загруженный работой сервер не "успел" откликнуться за отведенную десятую секунды).
Я рекомендую  сверять полученный список с некоторой сохраненной ранее информацией о физическомналичии в сети скл-серверов и полученный список сверять с этими данными. Если обнаружится "отсутствующий", то выполнить любой запрос именно к нему в защищенном блоке, чтобы заставить "ленивого" откликнуться либо убедиться в его неактивности (либо отсутствии временно или постоянно).

Этот алгоритм полезен в случаях, когда полный список активных серверов достаточно критичен. Вообще же редко есть необходимость определять с клиента полный перечень активных серверов, т.к. работа идет с конкретной БД, расположенной на конкретном же сервере.


svt   (2006-10-17 10:25:00) [2]


> MsGuns ©   (17.10.06 10:11) [6]

Ну спасибо.... информации намного больше чем  я ожидал. благодарен.


Johnmen   (2006-10-17 10:15:00) [3]

Вот из фака
Список баз, доступных юзеру
=======================
select name from master.dbo.sysdatabases d
where d.status & ltrim(str(convert(int, 0x03e0), 11)) = 0
 and has_dbaccess(d.name) = 1


MsGuns   (2006-10-17 10:11:00) [4]

 // Дескриптор SQL колонки (поля)
 PSQLFieldDef = ^RSQLFieldDef;
 RSQLFieldDef = record
   FldName: string;
   PKey: boolean;
   AInc: boolean;
   IsNULL: boolean;
   FldType: string;
   FType: TFieldType;
   Length: word;
   Scale: byte;
   Description: string;
 end;

function SQLServ_GetTableFieldsList(SQLServer: PMSSQLServerDef; DataBase,TableName: string; ListFields: TList): boolean;
var
 i: integer;
 fd: PSQLFieldDef;

begin
 result := false;
 for i := 0 to ListFields.Count-1 do Dispose(PSQLFieldDef(ListFields[i]));
 ListFields.Clear;
 with TADODataSet.Create(nil) do
   try
    ConnectionString := 'Provider=SQLOLEDB;'+
                       ';Persist Security Info=false'+
                       ';User ID=sa'+
                       ';Data Source='+SQLServer.ServerName;
    CommandText := 'use '+DataBase+' Exec sp_columns '+TableName;
    Open;
    while not EOF do
      begin
       fd := NEW(PSQLFieldDef);
       fd.FldName := FieldByName('COLUMN_NAME').AsString;
       fd.PKey := false;
       fd.FldType := FieldByName('TYPE_NAME').AsString;
       fd.AInc := (Pos('IDENTITY',UpperCase(fd.FldType))>0);
       fd.IsNULL := (FieldByName('IS_NULLABLE').AsString='YES');
       fd.Length := StrToInt(FieldByName('LENGTH').AsString);
       fd.Scale := 0;
       if UpperCase(fd.FldType)='NUMERIC' then
          fd.Scale := StrToInt(FieldByName('SCALE').AsString);
       fd.Description := 'No Description';
       ListFields.Add(fd);
       Next;
      end;
    Close;
    // Извлечение описателей
    CommandText := 'use '+DataBase+' select sc.name, sp.value '+
                   'from sysobjects so, syscolumns sc, sysproperties sp '+
                   'where so.id=sc.id and so.id=sp.id and '+
                   'sp.smallid=sc.colorder and so.name='+QuotedStr(TableName);
    Open;
    for i := 0 to ListFields.Count-1 do
      if Locate(Fields[0].FieldName,PSQLFieldDef(ListFields[i]).FldName,[]) then
         PSQLFieldDef(ListFields[i]).Description := Fields[1].AsString;
    Close;
    result := true;
   finally
    Free;
   end;
end;


svt   (2006-10-17 10:11:00) [5]


> ЮЮ ©   (17.10.06 09:55) [1]


> MsGuns ©   (17.10.06 10:03) [2]

весьма благодарен


MsGuns   (2006-10-17 10:11:00) [6]

 // Дескриптор SQL колонки (поля)
 PSQLFieldDef = ^RSQLFieldDef;
 RSQLFieldDef = record
   FldName: string;
   PKey: boolean;
   AInc: boolean;
   IsNULL: boolean;
   FldType: string;
   FType: TFieldType;
   Length: word;
   Scale: byte;
   Description: string;
 end;

function SQLServ_GetTableFieldsList(SQLServer: PMSSQLServerDef; DataBase,TableName: string; ListFields: TList): boolean;
var
 i: integer;
 fd: PSQLFieldDef;

begin
 result := false;
 for i := 0 to ListFields.Count-1 do Dispose(PSQLFieldDef(ListFields[i]));
 ListFields.Clear;
 with TADODataSet.Create(nil) do
   try
    ConnectionString := 'Provider=SQLOLEDB;'+
                       ';Persist Security Info=false'+
                       ';User ID=sa'+
                       ';Data Source='+SQLServer.ServerName;
    CommandText := 'use '+DataBase+' Exec sp_columns '+TableName;
    Open;
    while not EOF do
      begin
       fd := NEW(PSQLFieldDef);
       fd.FldName := FieldByName('COLUMN_NAME').AsString;
       fd.PKey := false;
       fd.FldType := FieldByName('TYPE_NAME').AsString;
       fd.AInc := (Pos('IDENTITY',UpperCase(fd.FldType))>0);
       fd.IsNULL := (FieldByName('IS_NULLABLE').AsString='YES');
       fd.Length := StrToInt(FieldByName('LENGTH').AsString);
       fd.Scale := 0;
       if UpperCase(fd.FldType)='NUMERIC' then
          fd.Scale := StrToInt(FieldByName('SCALE').AsString);
       fd.Description := 'No Description';
       ListFields.Add(fd);
       Next;
      end;
    Close;
    // Извлечение описателей
    CommandText := 'use '+DataBase+' select sc.name, sp.value '+
                   'from sysobjects so, syscolumns sc, sysproperties sp '+
                   'where so.id=sc.id and so.id=sp.id and '+
                   'sp.smallid=sc.colorder and so.name='+QuotedStr(TableName);
    Open;
    for i := 0 to ListFields.Count-1 do
      if Locate(Fields[0].FieldName,PSQLFieldDef(ListFields[i]).FldName,[]) then
         PSQLFieldDef(ListFields[i]).Description := Fields[1].AsString;
    Close;
    result := true;
   finally
    Free;
   end;
end;


MsGuns   (2006-10-17 10:05:00) [7]

function SQLServ_GetServerDBList(SQLServer: PMSSQLServerDef; ListDB: TStrings): boolean;
// Создается объект TADOConnection с "пустой" БД (Initial Catalog)
// и User ID = 'sa'. Затем создается объект TADOQuery, привязывается к
// соединению и выполняющий зпрос к системной таблице sysdatabases
// Полученный НД сканируется и содержимое первого поля НД (имена Баз Данных)
// заполняет список ListDB
//  Возвращаемый результат содержит false, если соединение с указанным сервером
// не может быть установлено либо запрос не был выполнен нормально
begin
 result := true;
 ListDB.Clear;
 with TADODataSet.Create(nil) do
   try
     ConnectionString := 'Provider=SQLOLEDB;Persist Security Info=false'+
                        ';User ID=sa;Data Source='+SQLServer.ServerName;
     CommandText := 'use master select * from sysdatabases';
     try
       Open;
       while not EOF do
         begin ListDB.Add(Fields[0].AsString); Next; end;
       Close;
     except
      result := false;
     end;
   finally
     Free;
   end;
end;

function SQLServ_GetServerTableList(SQLServer: PMSSQLServerDef; DataBase: string; ListTables: TStrings): boolean;
begin
 ListTables.Clear;
 with TADODataSet.Create(nil) do
   try
     ConnectionString := 'Provider=SQLOLEDB;'+
                         ';Persist Security Info=false'+
                         ';User ID=sa'+
                         ';Data Source='+SQLServer.ServerName;
     CommandText := 'use '+DataBase+' select * from sysobjects where xtype='+QuotedStr('u');
     try
       Open;
       while not eof do
         begin
          ListTables.Add(Fields[0].AsString);
          Next;
         end;
       Close;
       result := true;
     except
       result := false;
     end;
   finally
     Free;
   end;
end;


MsGuns   (2006-10-17 10:03:00) [8]

 // Дескриптор SQL-сервера
 PMSSQLServerDef = ^RMSSQLServerDef;
 RMSSQLServerDef = record
   ServerName: string;          // Имя сервера
   InstanceName: string;        // Установочный ид-р сервера
   IsClustered: boolean;        // Флаг включения в серверный кластер
   Version: RSQLServerVersion;  // Версия сервера
   Port: integer;               // Коммуникационный порт
   Path: string;                // Путь к серверу в сети
 end;

procedure SQLServ_GetServersList(SQLServerList: TList);
//  Процедура посылает по сети широковещательный запрос по порту 1434 и ждет
//  100 мс, затем буфер сокета, просматривается на наличие "ответов" от MS SQL Server
//  Кажый пакет извлекается в буфер в виде строки, парсируется и информация
//  заполняет декскриптор TMSSQLServerDef, который добавляется в список,
//  адрес которого указан вх.параметром
var
 hSocket: TSocket;
 WSAData: TWSAData;
 Buf: array[0..65535] of byte;
 i, tRes, tLenSA, tLenBufRecv: integer;
 tLenBufIOCTL: u_long;
 S: AnsiString;
 saSQLSend, saSQLRecv: sockaddr_in;
 Data: byte;
 ServDef: PMSSQLServerDef;
 ls: TStrings;

const
 fBroadcast: boolean = True;

begin
 // Очистка списка серверов
 for i := 0 to SQLServerList.Count-1 do
   Dispose(PMSSQLServerDef(SQLServerList[i]));
 SQLServerList.Clear;
 Data := $02;
 WSAStartup(MakeWord(2,2), WSAData);    // Инициализация Win DLL версии 2.2. (WS2_32.DLL)
 //Получение дескриптора сокета UDP
 hSocket := Socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if (hSocket = INVALID_SOCKET) then exit;
 //Установка опций сокета
 tRes := setsockopt(hSocket, SOL_SOCKET{IPPROTO_TCP}, SO_BROADCAST, @fBroadcast, sizeof(BOOL));
 if (tRes = SOCKET_ERROR) then begin closeSocket(hSocket); exit; end;
 //Установка данных служебной структуры  sockaddr_in
 saSQLSend.sin_family  := AF_INET;
 saSQLSend.sin_port := htons(1434);
 saSQLSend.sin_addr.s_addr := htonl(INADDR_BROADCAST);
 //Посылка широковещательного сообщения
 tRes := sendto(hSocket, Data, 1, 0, saSQLSend, sizeof(SOCKADDR_IN));
 if (tRes = SOCKET_ERROR) then begin closeSocket(hSocket); exit; end;
 Sleep(100);  // Ожидание ответа на пакет-запрос
 tRes := ioctlSocket(hSocket,FIONREAD,tLenBufIOCTL);  // Опрос состояния сокета
 if (tRes = SOCKET_ERROR) then begin closeSocket(hSocket); exit; end;
 if (tLenBufIOCTL>0) then // В буфере сокета (порта) есть данные
   begin
    tLenSA := sizeof(SOCKADDR_IN);
    saSQLRecv := saSQLSend;
    while tLenBufIOCTL>0 do  // Пока не просмотрен весь буфер
      begin
       // Чтение очередного пакета из буфера сокета
       tLenBufRecv := recvfrom(hSocket, Buf, 65535, 0, saSQLRecv, tLenSA);
       // Уменьшение буфера на длину считанных данных (типа удаление пакета из буфера)
       tLenBufIOCTL := tLenBufIOCTL-tLenBufRecv;
       if(tLenBufRecv=SOCKET_ERROR) then begin closeSocket(hSocket); exit; end;
       // Содержимое пакета -> строку
       s := ''; for i := 3 to tLenBufRecv-3 do s := s+Chr(Buf[i]);
       // Парсинг полученной информации и упаковка ее в структуру
       ls := TStringList.Create;
       // Строку порезать на строки (разделитель ';')
       while Length(s)>0 do
         begin
          i := Pos(';',s);
          if i>0 then
            begin ls.Add(Trim(Copy(s,1,i-1))); Delete(s,1,i); end
          else
            begin ls.Add(s); s := ''; end;
         end;
         // Разбор списка строк, где нечетная содержит ключ, а четное - его значение
         if ls.IndexOf('ServerName')>-1 then
           begin
            // Создание нового дескриптора
            ServDef := NEW(PMSSQLServerDef);
            // Имя сервера
            if ls.Count>(ls.IndexOf('ServerName')+1) then
               ServDef.ServerName := ls[ls.IndexOf('ServerName')+1];
            // Установочный идентификатор
            if (ls.IndexOf('InstanceName')>-1) and
               (ls.Count>(ls.IndexOf('InstanceName')+1)) then
               ServDef.InstanceName := ls[ls.IndexOf('InstanceName')+1];
            // Флаг принадлежности к кластеру
            if (ls.IndexOf('IsClastered')>-1) and
               (ls.Count>(ls.IndexOf('IsClastered')+1)) then
               ServDef.IsClustered := not (ls[ls.IndexOf('IsClastered')+1]='No');
            // Версия сервера
            if (ls.IndexOf('Version')>-1) and
               (ls.Count>(ls.IndexOf('Version')+1)) then
              begin
               S := ls[ls.IndexOf('Version')+1];
               // Найти первую точку
               i := Pos('.',S);
               if i>0 then
                 begin
                  ServDef.Version.VersNum := Copy(S,1,i-1);
                  ServDef.Version.ModNum := Copy(S,i+1,Length(S)-i);
                 end
               else
                 begin
                  ServDef.Version.VersNum := S;
                  ServDef.Version.ModNum := '';
                 end;
              end;
            // Адрес коммуникационного порта
            if (ls.IndexOf('tcp')>-1) and
               (ls.Count>(ls.IndexOf('tcp')+1)) then
                ServDef.Port := StrToIntDef(ls[ls.IndexOf('tcp')+1],0);
            // Сетевой путь к серверу
            if (ls.IndexOf('np')>-1) and
               (ls.Count>(ls.IndexOf('np')+1)) then
                ServDef.Path := ls[ls.IndexOf('np')+1];
            SQLServerList.Add(ServDef);
           end;
      end;
   end;
 closeSocket(hSocket);
 WSACleanup;
end;


ЮЮ   (2006-10-17 09:55:00) [9]

А посмотреть имеющуюся статическую ConnectionString и найти в ней место БД, конечно, религия не позволяет?

function BuildConnectionStringForMSSQL(
 const AServer, ADatabase, AUser, APassword: string
): string;
begin
 Result :=
   'Provider=SQLOLEDB.1;Persist Security Info=False;';
 if (AUser = '') and (APassword = '') then
   Result := Result + 'Integrated Security=SSPI;'
 else
   Result := Result + 'User ID=' + AUser + ';Password=' + APassword + ';';
 Result := Result +
   'Initial Catalog=' + ADatabase + ';' +
   'Data Source=' + AServer;
end;


Наверх

Титульная страница Поиск, карта сайта Написать письмо