Два года назад мне пришлось поучаствовать в большом проекте VFP ( клиент) - Oracle (сервер). Хотя до этого довольно долго игрался с персональным Оракл сервером, на первых порах каждый наш шаг при выполнении проекта добывался трудно и рассматривался как маленькая победа. После этого по горячим следам пришлось для других клиентов сделать еще проект. По прошествии времени все эти победы кажутся ничего не значащами мелочами. Но может кому понадобятся и эти поношенные вещи. Снова подчеркиваю, знатокам тут читать нечего. Информация в основном для начинающих.
1. Если комманда посланная на сервер Оракл дает Вам ошибку, проверьте ее в Oracle SQL sheet Interprise? Если она там не идет, бесполезно посылать ее через ФОКС. Никогда бы не давал бы этого совета, если бы не видел десятки раз, как проблему с посылкой команды часами ищут в ФОКСЕ.
2. В отличии от MS SQL Server вызов процедуры Оракл не порождает никаких курсоров на клиентской части ФОКСПРО. Это потому, что он не пораждает их и в самом Оракл. Их результат иногда возвращается в переменные Оракл. Чтобы узнать , что изменилось на сервере , пошлите на сервер соответсвующй SQL select command Между прочим , в отличии от MS SQL server, где достаточно послать только имя процедуры, вызов процедуры Оракл более сложен и имеет вид. sqlexec(con,'begin demo.procname; end;') Некоторые Оракл процедуры работают с переменными Оракл типа in-out, то есть пременными, которые передаются в процедуру, там изменяются и измененное значение возвращается из процедуры, Если передать значения в процедуру с клиентской стороны ничего не стоит, например через вопросительный знак, получить их изменившиеся значения на клиенте очень сложно. Например
HTML
m.var='first value'
sqlexec(con,'declare vr=?m.var begin demo.procname(vr) ; end ; select vr from dual ;')
. Переменная вернется к нам на ФОКС в курсоре , порожденном второй частью команды . Только там ее и можно достать.
3. Все объекты Оракл -таблицы, процедуры , тригера, функции живут там внутри так называемых схем. Схема совпадает с именем пользователя, заведшим эти объекты на Оракл. Поскольку с клиентской сторонымогут работать пользователи с разными именами, обращение к этим объектам должно включать имя схемы. Например [sqlexec(con,'select demo.tr() from dual')],
Поскольку в Оракл нелльзя вызвать SQL предложение без имени таблицы, а в вызове Оракл функций таковых может не быть, имя не существующей таблицы заменяется dual
sqlexec(con,'select sysdate from dual') Породит на ФОКСЕ курсор с системной датой .
Пример- вызов функции
Sqlexec(con,'select demo.func(1) as rtval from dual')
Часто на Оракл заводят одни и те же объекты в разных схемах, одной для тестирования еще не готовой программы, другие для боевой работы. Мы можем на этот случай в файле ФОКСА config.fpw поместить имя схемы и подставлять его в Фоксе при вызове серверных команд.
m.sql='insert into '+schema+tablename (fieldnames) values (values) В профессиональном руководстве по ФОКСУ есть совет- сделайте клиентское приложение на фоксовских таблицах, сделайте на них локальные представления , отладте приложение, затем мастером upsize импортируйте таблицы на сервер а локальные представления в удаленные. С моей точки зрения это сказка про белого бычка, таблицы конечно так можно на Оракл утащить, но работать все будет очень очень медленно и кучу проблем вовсе не решить. Проверьте сами. Создайте удаленное представление на Оракл и его прямой вызов через sqlexec, замерьте время выполнения- большая разница. Не забудьте настроить фокс на работу с разделяемым соединением, а иначе любое удаленное представление вызовет свою коннекцию и все они потратятся.
4. Обычно Оракл сервер ( куплен он или украден) расчитан на определенное число коннекций, которое в случае покупки оказывает прямое влияние на его цену. А пользователей хочется посадить побольше. Поэтому бедным и слаборазвитым вроде нас Россиян стоит побороться за коннекции. Простое наблюдение показывает, что во многих пользовательских интерфейсах люди извините за неприличные подробности ) вводят и редактируют данные и тратят на это достаточно много времени. Их коннекцией другие клиенты в это время могли бы воспользоваться , чтобы послать или получить что либо с сервера. Вообще не следует держать коннекцию открытыми без необходимости. При работе с ограниченным числом коннекций и закрытием их когда они не нужны, при их запросе нужно предусмотреть ситуацию с тем, что в данный момент коннекции нет, и ее нужно подождать .
HTML
sqlsetprop(0,'DispLogin',3)
do while sqlconnect('poracle','username','userpassword')<0
aerror(err)
if err[1]=1526 and err[4]=8008 ! ждем коннекцию некоторое время
endif
enddo
Иногда вызов команды или процедуры Оракл может идти долго. Такую коннекцию закрыть нельзя. Поэтому совет такой. На этот случай завести особую , долго не закрываемую коннекцию . Известные мне люди называют такуюстратегию-полторы коннекции. Одна коннекция есть, а другая то есть, а то нет. Такой де фокус делают при вызове асинхронной команды. Короткую во времени команду посылаем по синхронному протоколу , получаем результат, а долгую во времени посылаем по асинхронному протоколу, и время от времени проверяем, есть ли от нее результат.
5. Задача присвоения значений первичных ключей существует для любой базы данных. В Оракл для этой и других целей есть специальный оъект -последовательность, имеющий первичное значени и приращение. Первое, что приходит в голову , чтобы присвоить изначение ключа и узнать его , например, для присвоения его в детской таблице это код вроде ниже следующего
sqlexec(con,' insert into schemaname.tablename (primaryfiledname, ..) values (schemaname.seqtablename.nextval,...)')
sqlexec(con,'select schemaname. Seqtablename.curval as lstval from dual').
Но тогда нужно во всякой команде для всех таблиц при добавлении записей помнить значение последовательностей. Как минимум нужен некий автомат определение имени последовательности по имени таблицы, помещенный в библиотеку классов работы с сервером, чтобы при добавлении новых записей не беспокоится о присвоении ключей. К тому же не очень по науке вычислять ключ на клиенте и посылать его обратно на сервер. Можно сделать по другому , написать на фоксе процедуру, которая пойдется по таблицам, заведет для каждой из них последовательность и ссылающийся на нее тригер before insert , который автоматом при добавлении записи на сервере присвоит там ключ. Останется его только вернуть.
Тригер может иметь вид
HTML
declare runval number ; begin select DEMO. seqtablename.nextval into
runval from dual ; :new.CUSTOMER_ID:=runval ; insert into lstkey
(tbname,lstval,ses_id) values (tbname,runval, userenv(sessionid));
end ;
После создания новой записизначение ключа можно узнать как select DEMO. seqtablename.curval from dual А можно поступить по другому Присвоенное значение ключа можно хранить в спец таблице ( в тригере мы это делаем) , вроде того как мы делаем это в ФОКСЕ. Нужно только пометить, чей ключ какому клиенту принадлежит. Для этого можно применить Оракл переменную - В Оракл для этого есть переменная sessionid, уникальная для каждой коннекции, даже если несколько пользователей вошли с одинаковым именем. А ее узнают из функции userenv(sessionid)
6. Оракл имеет одну замечательную вещь, котарая отсутсвует во вногих серверах и языкаж баз данных. Положим есть таблица с неопорядоченными записями, которых очень много. Хочется получить результат с ограниченным числом записей, но упорядоченный.
Данные нужно вначале упорядочить в малой выборке, а торлько потом вернуть, не первые 100 записей, а первые 100 упорядоченных записей, скажем клиенты по алфавиту. Ведь Алексеев может быть каким нибудь десяти миллионным.
Вот тут то Ораклу можно сказать- сделай мне выборку по тому индексу, что у тебя есть , а не в физическом порядке записей. Не достает только чего нибудь, что ограничит число записей. Нужно отметить, что разработчики серверов здесь на редкось "логичны" С первой до последней страницы руководств они вдалбливают нам в мозги, что на серверах нет понятия номер записи. Но сами бес конца наталкиваются на введение чего то вроде этого номера ( или даже нескольких переменных) задним числом. Оракл не исключение - rownum ограничит число записей.
HTML
m.sql=m.sql+" SELECT DISTINCT "
m.sql=m.sql+" /*INDEX(TICK IND_NUM) */"
m.sql=m.sql+schema+"tick.NUM FROM "+schema+"tick "
m.sql=m.sql+" WHERE rownum<=100 order by num"
/* INDEX(TICK IND_NUM) */- здесь так называемый хинт Оракл, который говорит серверу использовать для упорядывачиния индекс а не таблицу. Номер записи они сказать не хотят. Но черта как ни поминай, он все равно вылезет .
7. Как сделать внешний джоин, то есть связать таблицы, когдамежду нимине всегда есть соответсвие
Select nvl(gdname,' ') as gdname from demo.goodsln, demo.goods Where goodsln.gd_id=goods.gd_id(+)
Таблица с плюсом- вроде справочника, на который не всегда есть ссылка, но нужно вернуть все записи основной таблицы, не зависимо от того есть там ссылка на справку или нет .
8. Хочешь не хочешь, а вот еще простецкий пример, когда нужно что то вроде номера записи, уникально ее определяющего. Хочется данные из одного поля перетащить в другое но в каждой записи. Цикл по записям делять не охота , Ну что же воспользуемся переменной "rowid." Вот тогда, как update заставит сработать "оптом"
HTML
sqlexec(con,'update demo.table set fielda=(select fieldb from demo.table tb1 where table.rowid=tb1.rowid)')
9. Вот вопрос, который имеет значение не только для Оракл , но и для всех серверов. Мне его часто в том или ином виде задают. Поэтому вот ответ
В фоксе есть два режима управления транзакциями сервера- явный и неявный. Их Смешивать нельзя- получите странные результаты. Если у Вас sqlprop('transaction',1) -каждая комманда автоматически коммитется, если только вы сами не напишете sqlexec(con,'begin transaction') команды sqlexec(con,'Commit')
Но если у Вас sqlprop('transaction',2) То для завершения транзакции нужно писать sqlcommit(con)
'begin transaction' и sqlexec(con,'Commit') писать внутри такой установки не следует .
10. В Оракл целая куча функций и комманд, которые не упомнишь, поэтому потратьте время на то , чтобвы перенести их вызов в соответсвующие методы библиотек на Фоксе. Сэкономите время.
11. Среди примеров, которые поставляются с ФОКСОм есть класс, который залезает в реестр(registry.prg ), Он в частности по имени ОДБС может узнать какой сервер имеется ввиду, и воспользоваться этим для написания веток
серверочувствительного кода.
12. Если хотите , чтобы запросы на Оракл работали быстро-постройте для входящих в них переменных индексы. На больших выборках разница в сотни раз. Все про это знают, но не все делают.
13. Ну это не совет, а хакерский трюк вроде фокуса.
Мы знаем, что удаленной представление можно сделать updateble А результаты sqlexec нет и отредактированные данные нужно нести на сервер самим. Но второй способ быстрее работает и для больших случаев годится. Оказывается можно скрестить коня и трепетную лань вместе Сделаем удаленное представление на Оракл и сделаем его updateble Запустим на нашу базу данных процедуру gendbc и выдерем весь код после определения представления. Теперь пошлем команду sqlexec с запросом представления на сервер, а получив на фоксовской стороне запустим тот кусок, что выдрали из кода Теперь изменем что нибудь в курсоре. Гляньте теперь на сервер- наши изменения там без комманд и упоминания полей!!!!