Страница 1 из 2

Помогите научиться работать с SQL из Клариона

Добавлено: 23 Январь 2007, 19:06
AnDS
Задача следующая:

есть Access-ная база (MDB), в ней таблицы.
требуется выполнять несложные запросы (SELECT,UPDATE,INSERT) к этим таблицам.
словарь делать не нужно.

Начал решать -- посмотрел на пример работы с ADO (рукописный код) с сайта clarionlife.net -- понравилось (очень уж все просто -- запрос в виде строки, а результат - в очередь).

Написал программку, она работает. :-)

Но! Столкнулся с проблемами:
1.Строка запроса ограничена приблизительно 2мя килобайтами (2-3 кБ)
2.Результат тоже видимо ограничен (получаю аналогичное сообщение - что-то о слишком длинном поле)

И самое главное!!!
3.Жрет память. Когда запросов немного -- не заметно, когда начинаю в цикле выполнять несколько сотен запросов, то память отжирается (судя по диспетчеру задач) десятками и сотнями мегабайт. В конце-концов программе просто не хватает ресурсов и она умирает.

Отсюда вывод -- что-то я делаю не так.
Понять бы как делать "так"?

Поделитесь опытом, плз, как выполнять произвольный запрос, не привязываясь к словарям?

Привожу кусок кода, которым я пользуюсь:
строка коннекта к базе:

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

GLO:Conn&=sqlConnect('Provider=Microsoft.Jet.OLEDB.4.0;Data Source='&clip(loc:DBName)&';Jet OLEDB:Database Password=111111;',Err#)
запрос:

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

 sqlExecute(GLO:Conn,'INSERT INTO Firm ('&|
 '[Name],'&|
 '[Index],'&|
 '[Country],'&|
 '[Town],'&|
 '[Region],'&|
 '[Street],'&|
 '[House],'&|
 '[Korp],'&|

......................

 '[Deleted]'&|
 ') VALUES ('&|
 ''''&clip(QP:Name)&''','&|
 ''''&clip(QP:Index)&''','&|
 ''''&clip(QP:idCountry)&''','&|
 ''''&clip(QP:idTown)&''','&|
 ''''&clip(QP:idRegion)&''','&|
 ''''&clip(QP:idStreet)&''','&|
 ''''&clip(QP:House)&''','&|
 ''''&clip(QP:Korp)&''','&|

..........................

 ''''&(0)&''''&|
 ');')

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

sqlExecute           PROCEDURE  (pConn,sqlQuery,<queryQ>,<FlagPosition>) ! Declare Procedure
pRecordSet            &CRecordSet
pCommand              &CCommand
pFields               &CFields
pField                &CField

cstrCommandText       CSTRING(5120)
bEof                  SHORT
dwCount               LONG
bstrName              BSTRING

gVar                  LIKE(gVariant)
aVar                  VARIANT,OVER(gVar)

posCounter            LONG
CurrentQueueField     ANY
CurrentQueueFieldName STRING(64)

  CODE
 if ~omitted(3)
    free(queryQ)
 end

 if (GLO:xPCListConn&=NULL) then return.

 pRecordSet &= new(CRecordSet)
 Err#=pRecordSet.Init()
 Err#=pRecordSet.PutCursorLocation(adUseClient)
 pFields &= new(CFields)
 pField &= new(CField)

 pCommand &= new(CCommand)
 if ~(pCommand &=NULL)
    Err#=pCommand.Init()
    Err#=pCommand.PutRefActiveConnection(pConn)
    Err#=pCommand.PutCommandType(adCmdText)
    cstrCommandText=clip(sqlQuery)
    Err#=pCommand.PutCommandText(cstrCommandText)
    pRecordSet&=pCommand._Execute(,Err#)
    if ~Err# ! если все без ошибок
       if ~omitted(3)
         if NOT pRecordSet.GetEof(bEof) then
           if bEof<>-1 then
             do ProcessFields
             loop
                if pRecordSet.MoveNext() then break.
                if pRecordSet.GetEof(bEof) then break.
                if bEof=-1 then break.
                do ProcessFields
             end
           end
         end
       end
    end
 end

 !!!AnDS -- этого кода в примере не было, думал поможет память освободить -- не помогло :-(
 dispose(pField)
 dispose(pFields)
 pRecordSet.Destruct()
 !!!AnDS

ProcessFields routine
 pFields &= pRecordSet.GetFields(Err#)
 Err# = pFields.GetCount(dwCount)

 loop i#=0 to dwCount-1
    pField &= pFields.GetField(i#, Err#)
    Err#=pField.GetName(bstrName)
    Err#=pField.GetValue(gVar)
    case FlagPosition
       of sql:ByName
          posCounter=0
          loop
             posCounter+=1
             CurrentQueueFieldName=WHO(queryQ,posCounter)
             if clip(CurrentQueueFieldName)='' then break.
             if UPPER(clip(CurrentQueueFieldName))=UPPER(clip(bstrName))
                CurrentQueueField&=WHAT(queryQ,posCounter)
                if ~(CurrentQueueField&=NULL)
                   CurrentQueueField=aVar
                end
             end
          end
       of sql:ByPos
          CurrentQueueField&=WHAT(queryQ,i#+1)
          if ~(CurrentQueueField&=NULL)
             CurrentQueueField=aVar
          end
    end
 end
 if (dwCount) then add(queryQ). ! пропустим если пусто

Добавлено: 23 Январь 2007, 20:55
Дед Пахом
Не вдаваясь в подробности кода, просто что сразу увидел:
не уничтожаются pCommand и pRecordSet (явный вызов деструктора это не то). Сделай Dispose и им, может полегче будет?

Хмм...смотрю дальше и что-то не понимаю ничего. pRecordSet создаётся по NEW (выделяем память), а затем влёгкую забиваем на эту память и делаем pRecordSet &= pCommand._Execute(,Err#). Это точно нехилый memory leak.

ODBC API

Добавлено: 24 Январь 2007, 12:48
seawolf
Рекомендую поковыряться с ODBC API. Будет работать быстро безо всяких словарей.

Re: ODBC API

Добавлено: 24 Январь 2007, 16:27
AnDS
seawolf писал(а):Рекомендую поковыряться с ODBC API. Будет работать быстро безо всяких словарей.
Гм. А пример есть? Интересно было бы на пример взглянуть...

Добавлено: 24 Январь 2007, 16:40
AnDS
Дед Пахом писал(а):не уничтожаются pCommand и pRecordSet (явный вызов деструктора это не то). Сделай Dispose и им, может полегче будет?
В общем, память утекать перестала (вроде бы) -- спасибо за подсказку.

Еще бы ограничение на размер запроса снять, было бы здорово.
Да и по скорости не фонтан.
TPS работает быстрее на мой взгляд. :-)

Добавлено: 24 Январь 2007, 17:08
Andrew Listiev
И не удивительно :) У эксэсовского mdb начинаются жуткие тормоза, когда файл переваливает за 100 мег. Проверено на опыте.

Добавлено: 24 Январь 2007, 17:19
AnDS
Andrew Listiev писал(а):И не удивительно :) У эксэсовского mdb начинаются жуткие тормоза, когда файл переваливает за 100 мег. Проверено на опыте.
Гм. У меня была информация о гигабайте. :-(

На самом деле база пока пустая, но скорость при этом невысокая.
Что же будет дальше...

Добавлено: 24 Январь 2007, 17:47
Andrew Listiev
Многовато для mdb. Если планируються такие объемы, то лучше рассматривать полноценные SQL сервера.

Добавлено: 26 Январь 2007, 17:21
lsgsoftware
А причем здесь словарь?Если база чужая, то ее импорт в словарь даст возможность ее сходу посмотреть. Ведь словарь - это средство перетащить описание таблиц в Main-модуль и больше ничего.На скорость влияет не словарь, а правильная нормализация таблиц.

Добавлено: 26 Январь 2007, 20:53
Дед Пахом
Начал решать -- посмотрел на пример работы с ADO (рукописный код) с сайта clarionlife.net -- понравилось (очень уж все просто -- запрос в виде строки, а результат - в очередь).
Судя по одной-единственной приведенной функции - лучше про ADO забыть :cry: А хочется исполнять любые простые запросы - для этого есть прекрасное штатное средство Clarion -

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

myfile{prop:sql}='SELECT a,b,c FROM ' & myfile{prop:name} & ' WHERE d=' & x
и результат вытаскивается с помощью

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

LOOP
  NEXT(myfile)
  IF ERRORCODE() THEN BREAK END
END

Добавлено: 27 Январь 2007, 15:07
StillZero
прекрасное штатное средство Clarion
мое мнение, что наличие словаря для работы с SQl-ем не нужно, словарь лишний, надо работать на прямую с SQL-серваком

и всякие средства типо ADO и ODBC API позволяют это делать, что есть правильно

кстати ADO, я думаю, тебе разрулить на раз два
а ADO в отличие от ODBC API технология ПОНЯТНАЯ, а это мега плюс
занялся бы, а то SQL DMO :)

Добавлено: 27 Январь 2007, 21:37
AnDS
Дед Пахом писал(а): Судя по одной-единственной приведенной функции - лучше про ADO забыть :cry:
А чем плоха функция? Работает. Взята из примера.
Не понимаю.
Дед Пахом писал(а): прекрасное штатное средство Clarion -

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

myfile{prop:sql}='SELECT a,b,c FROM ' & myfile{prop:name} & ' WHERE d=' & x
Это все хорошо для случая, когда есть словарь.
А когда словаря нет?

Добавлено: 30 Январь 2007, 9:53
Дед Пахом
AnDS: А чем плоха функция? Работает. Взята из примера.
Не понимаю.
Наверно, это я искал утечку памяти.
AnDS: Это все хорошо для случая, когда есть словарь.
А когда словаря нет?
Причём тут словарь? Уже руками не можем написать

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

myfile FILE,DRIVER('ODBC'),NAME
...
END
StillZero: кстати ADO, я думаю, тебе разрулить на раз два
а ADO в отличие от ODBC API технология ПОНЯТНАЯ, а это мега плюс
занялся бы, а то SQL DMO
Так вроде разрулено в 6-ке, я где-то что-то применял, работало. А SQLDMO было на заказ, самому оно мне нахрен не нужно.

Добавлено: 30 Январь 2007, 11:13
AnDS
Дед Пахом писал(а):
AnDS: Это все хорошо для случая, когда есть словарь.
А когда словаря нет?
Причём тут словарь? Уже руками не можем написать

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

myfile FILE,DRIVER('ODBC'),NAME
...
END
Ну это все хорошо. Согласен, можно и так.
А для файла обязательно DSN настраивать? Или можно без настройки DSN?

Добавлено: 30 Январь 2007, 11:52
Дед Пахом
Если не ошибаюсь, ODBC без DNS никак