Этапы Использования Хранимых Процедур
После установки соединения с БД этапы использования хранимой процедуры в Вашем приложении несколько различаются для разных БД:
(Только DB2) Хранимая процедура регистрируется в соответствующих системных таблицах. (Это выполняется вне JavaScript.)
(DB2, ODBC и Sybase) Определяется прототип для Вашей хранимой процедуры.
(Все БД) Выполняется хранимая процедура.
(Все БД) Создаётся resultSet -объект и получаются данные из этого объекта.
(DB2, ODBC и Sybase) Выполнение завершается доступом к return-значению.
(DB2, ODBC, Oracle и Sybase) Выполнение завершается получением параметров вывода.
Заметьте, что для разных БД Вы можете завершить выполнение Вашей хранимой процедуры получением return-значения или доступом к параметрам вывода. После того как одно их этих двух действий выполнено, Вы не можете больше работать с результирующим набором, созданным при выполнении хранимой процедуры.
В следующих разделах эти этапы рассматриваются по отдельности.
Как Работает Hello World?
Это приложение демонстрирует две важные вещи: обслуживание различных клиентских статусов нескольких клиентов и обслуживание существующего статуса приложения. Оно выполняет следующие функции:
Выводит IP-адрес клиента, выполнившего запрос.Выводит имена, введённые ранее, и форму для ввода имени пользователя.
Выводит число - количество предыдущих запросов пользователя к странице и общее количество посещений страницы всеми клиентами.
При первом посещении страницы пользователем значения обоих имён не определены. Количество предыдущих посещений пользователя равно 0; общее количество посещений также равно 0.
Введите своё имя и нажмите Enter. Страница теперь показывает введённое имя и текст "This time you are." Оба числа посещений увеличиваются на 1. Эта акция иллюстрирует простейшую обработку данных формы. Введите другое имя и нажмите Enter. Страница теперь показывает новое имя и текст "This time you are", а предыдущее имя с - текстом "Last time you were." И вновь оба числа посещений увеличиваются.
Если Вы выполните доступ к приложению из другого экземпляра Navigator'а (или с другого компьютера), страница покажет общее число посещений и количество посещений каждого экземпляра Navigator'а, а не только одного данного экземпляра.
Классы и Объекты
Для поддержания различных задач, выполняемых на каждой стороне, JavaScript имеет классы и предопределённые объекты, которые работают на клиенте, но не на сервере, и другие классы и предопределённые объекты, которые работают на сервере, но не на клиенте.
Важно!
Названия этих объектов зарезервированы для JavaScript. Не создавайте Ваши собственные объекты, используя эти имена.
Ядро языка JavaScript предоставляет классы, описанные в следующей таблице. Детальную информацию обо всех этих объектах см. в книге
.
Array |
Массив. | |
Boolean |
Булево значение. | |
Date |
Дата. | |
Function |
Специфицирует строку кода JavaScript, компилируемую как функция. | |
Math |
Предоставляет основные математические константы и функции; например, свойство PI содержит значение pi. | |
Number |
Примитивные числовые значения. | |
Object |
Базовая функциональность всех объектов JavaScript. | |
Packages |
Пакет Java в JavaScript. используется вместе с LiveConnect. | |
String |
Строка JavaScript. |
Серверный JavaScript включает классы ядра, но не классы клиентского JavaScript. Серверный JavaScript имеет свой набор дополнительных классов для поддержки необходимой функциональности, как показано в следующей таблице.
Connection |
Одиночное соединение с БД из пула соединений. (См. ). | |
Cursor |
Курсор БД. (См. ). | |
DbPool |
Пул соединений с базами данных. (См. ). | |
Stproc |
Хранимая процедура БД. (См. ). | |
Resultset |
Представляет информацию, возвращаемую хранимой процедурой БД. (См. .) | |
File |
Предоставляет доступ к файловой системе сервера. (См. .) | |
Lock |
Предоставляет функциональность для безопасного совместного использования/sharing данных запросами, клиентами и приложениями. (См. .) | |
SendMail |
Предоставляет функциональность для отправки электронной почты из вашего приложения JavaScript. (См. .) |
Кроме того, серверный JavaScript имеет предопределённые объекты, описанные в следующей таблице. Эти объекты доступны для каждого HTTP-запроса. Вы не можете создать дополнительные экземпляры какого-либо из этих объектов.
database | Соединение с базой данных. (См. ) |
client | Инкапсулирует информацию о паре клиент/приложение, позволяя хранить эту информацию дольше, чем в течение одного HTTP-запроса. (См. ) |
project | Инкапсулирует информацию о приложении, которая хранится, пока приложение не прекратит работу на сервере. (См. .) |
request | Инкапсулирует информацию об отдельном HTTP-запросе. (См. .) |
server | Инкапсулирует глобальную информацию о сервере, которая хранится, пока сервер не остановится. (См. .) |
Клиентская Техника
Есть два вида клиентской техники:
Клиентские кукиКлиентское кодирование URL
Сравнение этих видов техники см. в разделе .
Когда приложение использует клиентские виды техники, машина выполнения кодирует свойства объекта client в ответ на клиентский запрос в шапке/header ответа (для клиентской куки) или в URLs в теле ответа (для клиентского кодирования URL).
Поскольку реальные имена и значения свойств пересылаются между клиентом и сервером, рестарт сервера не вызывает потери клиентской информации. Однако отправка этой информации вызывает увеличение сетевого трафика.
Клиентский JavaScript
Web-браузеры, такие как Navigator (2.0 и более поздние версии) могут интерпретировать операторы клиентского JavaScript, внедрённые в HTML-страницу. Когда браузер (или клиент) запрашивает такую страницу, сервер высылает клиенту по сети полное содержимое документа, включая HTML и операторы JavaScript. Браузер читает страницу сверху вниз, отображая результат работы HTML и выполняя операторы JavaScript по мере их обнаружения. Этот процесс, проиллюстрированный на рисунке, производит результат, который видит пользователь.
Рисунок 1.2Клиентский JavaScript
![](image/klientskij-javascript_1.gif)
Операторы клиентского JavaScript, встроенного в HTML-страницу, могут реагировать на пользовательские события, такие как щелчок мыши, ввод данных в форму и навигация по страницам. Например, Вы можете написать функцию JavaScript для проверки ввода пользователем правильной информации в форму, запрашивающую телефонный номер или zip-код. Без передачи по сети внедрённый JavaScript на HTML-странице может проверить введённые данные и вывести диалоговое окно, если пользователь ввёл неверные данные.
Разные версии JavaScript работают со специфическими версиями Navigator'а. Например, JavaScript 1.2 работает с Navigator 4.0. Некоторые возможности JavaScript 1.2 недоступны в JavaScript 1.1 и поэтому недоступны в Navigator 3.0. Информацию о версиях JavaScript и Navigator см. в разделе .
Кодирование Информации в URL
Вы можете вручную кодировать свойства объекта request в URL, по которому выполняется доступ к странице Вашего приложения. При создании URL используется следующий синтаксис:
URL?varName1=value1[&varName2=value2...]
Здесь URL это базовый URL, каждое varNameN это имя свойства, каждое valueN это соответствующее свойству значение (с мнемониками специальных символов). В этой схеме после базового URL идёт знак вопроса (?), после которого, в свою очередь, идут пары имён свойств и их значений. Каждая пара отделяется амперсандом (&). Когда машина выполнения на сервере получает результирующий URL в качестве клиентского запроса, она создаёт свойство объекта request под названием varNameN для каждой переменной.
Например, следующий HTML определяет гиперссылку на страницу, инстанциирующую свойства объекта request i и j в 1 и 2, соответственно. Операторы JavaScript в refpage.html могут затем обратиться к эти переменным request.i и request.j.
<A HREF="refpage.html?i=1&j=2">Click Here</A>
Вместо использования статической URL-строки, как в предыдущем примере, Вы можете использовать операторы серверного или клиентского JavaScript для динамической генерации URL, кодирующего значения свойств. Например, Ваше приложение может включать страницу:
<HTML>
<HEAD>
<SCRIPT>
function compute () {
// ... заменить подходящими расчётами, // которые возвращают строку поиска ...
return "?num=25";
}
</SCRIPT>
</HEAD><BODY>
<a HREF="refpage.htm" onClick="this.search=compute()">
Click here to submit a value.</a></p></BODY>
</HTML>
В данном случае, если пользователь щёлкнет на ссылке, машина выполнения на клиенте запустит на выполнение обработчик события onClick. Этот обработчик устанавливает часть поиска из URL в ссылке в какую-нибудь строку, возвращённую функцией compute. Когда машина выполнения на сервере получит этот запрос, она создаст свойство num объекта request и установит его значение в 25.
В качестве второго примера Вы можете добавить свойства объекта request в URL, созданный в серверном скрипте. Это особенно применимо, если Вы перенаправляете клиентский запрос на новую страницу. Чтобы добавить свойства объекта request в серверный скрипт, Вы можете использовать такой оператор:
<A HREF=`"refpage.html?i=" + escape(i) + "&j=" + escape(j)`>
Click Here</A>
Если вы создаёте URL в операторе серверного JavaScript, свойства объекта client не добавляются автоматически. Если Вы используете технику на основе URL для объекта client, используйте функцию addClient для генерирования окончательного URL. В этом примере оператор может быть таким:
<A HREF=`addClient("refpage.html?i=" + escape(i)
+ "&j=" + escape(j))`>Click Here</A>
Об использовании addClient см. .
Функция escape ядра JavaScript даёт возможность кодировать имена или значения, присоединённые к URL, включая специальные символы. Вообще, если приложению необходимо генерировать имена и значения собственных свойств в URL запроса, Вы должны использовать escape, чтобы гарантировать корректную интерпретацию всех значений. Дополнительно см. книгу .
Помните, что URL не изменяется, если пользователь перезагружает его, хотя содержимое страницы может измениться. Любые свойства, высланные в оригинальном URL, восстанавливают свои значения в URL, имевшиеся на момент его первой отправки, независимо от любых возможных изменений, сделанных при обработке. Например, если пользователь щёлкнул кнопку Reload для перезагрузки URL в предыдущем примере, i и j снова установятся в 1 и 2, соответственно.
Когда Использовать Эти Виды Техники
В большинстве случаев ясно, когда использовать тэг SERVER, а когда - обратные кавычки. Иногда, однако можно достичь того же результата другим путём ("Мы пойдём..."). В общем, лучше использовать обратные кавычки для внедрения значений JavaScript в тэги HTML, а в других случаях - тэг SERVER.
Например, в Hangman вместо
<IMG SRC=`"images\hang" + client.num_misses + ".gif"`>
можно записать
<SERVER>
write("<IMG SRC=\"images\hang");
write(client.num_misses);
write(".gif\">");
</SERVER>
Обратите внимание, что обратная наклонная черта (backslash) даёт возможность ввести знак кавычки внутри литеральной строки. Хотя результирующий HTML - тот же самый, в этом случае обратные кавычки предпочтительнее, поскольку исходник легче читать и редактировать.
Когда Можно Использовать Результирующие Наборы
Объект resultSet не является бесконечно действующим. Вообще, когда хранимая процедура стартует, не допускается никакое взаимодействие между клиентом БД и сервером БД, пока хранимая процедура не завершит выполнение. Есть три ситуации, когда результирующий набор является недействующим:
- Если Вы создаёте результирующий набор как часть транзакции, Вы обязаны закончить использование результирующего набора в течение выполнения этой транзакции. Если Вы подтвердили транзакцию или выполнили её откат, Вы не сможете получать данные из результирующего набора и не сможете получить дополнительные результирующие наборы. Например, следующий код не допускается:database.beginTransaction();
spobj = database.storedProc("getcusts");
resobj = spobj.resultSet();
database.commitTransaction();
// Неверно! Результирующий набор больше не действует!
col1 = resobj[0];
Для Sybase, ODBC и DB2 Вы обязаны запросить resultSet -объекты до вызова методов returnValue или outParameters объекта хранимой процедуры. Если Вы вызвали один из этих методов, Вы не сможете больше получать данные из результирующего набора и не сможете получить дополнительные результирующие наборы. См. о работе этих методов раздел .spobj = database.storedProc("getcusts");
resobj = spobj.resultSet();
retval = spobj.returnValue();
// Неверно! Результирующий набор больше не действует!
col1 = resobj[0];
Для Sybase Вы обязаны запросить resultSet -объекты до вызова методов cursor или SQLTable ассоциированного соединения. Как только Вы вызовете cursor или SQLTable, результирующий набор станет недоступен. Например, следующий код неверен:spobj = database.storedProc("getcusts");
resobj = spobj.resultSet();
curobj = database.cursor ("select * from orders");
// Неверно! Результирующий набор больше не доступен!
col1 = resobj[0];
Для ODBC соблюдаются несколько иные ограничения. Вы также обязаны работать с resultSet -объектами до вызова методов cursor или SQLTable ассоциированного соединения. В ODBC, если Вы получаете курсор, выполняете доступ к результирующему набору, а затем используете курсор, Cursor -объект становится недоступным. Например, следующий код неверен:spbobj = database.storedProc("getcusts");
resobj = spobj.resulSet();
curobj = database.cursor ("select * from orders");
col1 = resobj[0]; // Неверно! Курсор больше не доступен.
curobj.next();
Компиляция Приложения
Вы компилируете приложение JavaScript, используя компилятор приложений JavaScript, jsac. Компилятор создаёт web-файл из исходных файлов на языках HTML и JavaScript.
Примечание
Netscape Enterprise Server 4.0 поддерживает компилятор JavaScript Application Compiler версии 24.13. Заметьте, что приложение, скомпилированное с использованием "=" в качестве операции Equal, не сможет использовать новый компилятор. Вы обязаны использовать "==" в качестве операции Equal (==).
Для облегчения доступа к компилятору Вам может понадобиться добавить директорию, в которой он установлен, в переменную окружения PATH. От том, как это сделать, см. раздел в
Вам нужно также добавить директорию <server_root>/bin/httpd/lib в LD_LIBRARY_PATH (или LIBPATH, или SHLIB_PATH на Unix-платформах), либо <server_root>/bin/https/bin в PATH на Windows NT-платформах.
Вам нужно компилировать только те страницы, которые содержат серверный JavaScript или оба - клиентский и серверный JavaScript. Вам не нужно компилировать страницы, содержащие только клиентский JavaScript. Вы, конечно, можете сделать это, но скорость работы будет выше, если Вы оставите страницы с клиентским JavaScript без компиляции.
Компилятор доступен из командной строки. Используйте следующий синтаксис командной строки для компиляции и компоновки приложений JavaScript на сервере:
jsac [-h] [-c] [-v] [-d] [-l]
[-o outfile.web]
[-i inputFile]
[-p pathName]
[-f includeFile]
[-r errorFile]
[-a 1.2]
script1.html [...scriptN.html] [funct1.js ... functN.js]
Элементы в квадратных скобках не обязательны. Синтаксис дан на нескольких строках для большей ясности. Файлы scriptN.html и functN.js это входные файлы для компилятора. Должен быть как минимум один HTML-файл. По умолчанию файлы HTML и JavaScript ищутся в текущей директории. Специфицируемые Вами файлы обязаны быть JavaScript- или HTML-файлы; Вы не можете специфицировать другие файлы, такие, например, как .GIF.
На всех платформах Вы можете использовать тире (-) или слэш (/) для обозначения опций командной строки. То есть, следующие строки эквивалентны:
jsac -h
jsac /h
Заметьте, что, поскольку слэш обозначает опции командной строки, входной файл не может начинаться с символа / (слэш) для обозначения абсолютного пути (в Unix). Таким образом, следующий вызов неверен:
jsac -o myapp.web /usr/vpg/myapp.html
Это ограничение не распространяется на путь, который Вы предоставляете как аргумент командной строки; только на входные файлы. В NT Вы можете использовать обратный слэш (\) для указания абсолютного пути во входном файле, как в следующем вызове:
jsac -o myapp.web \usr\vpg\myapp.html
В Unix Вы обязаны использовать опцию командной строки -i для специфицирования абсолютного пути, как описано ниже.
Доступны следующие опции командной строки:
-h: Помощь по синтаксису компилятора. Если Вы используете эту опцию, не указывайте никаких других.
-c: Синтаксис только проверяется; web-файл не генерируется. Если эта опция указана, опцию -o указывать не нужно.
-v: (Verbose) Выводит информацию о работе компилятора.
-d: Выводит генерируемое JavaScript-содержимое.
-l: Специфицирует набор символов, используемый при компиляции (такой как iso-8859-1, x-sjis или euc-kr).
-o outfile: Создаёт web-файл в формате байт-кода с именем outfile.web. Если эта опция не указана, компилятор не генерирует web-файл. (Опускайте эту опцию только тогда, когда используете опцию -c для проверки синтаксиса или -h для получения помощи.)
-i inputFile: Позволяет специфицировать входной файл с полным путём, а не с относительным путём. Для этой опции может быть задано только имя файла. Если Вам нужно специфицировать несколько файлов с полным путём, используйте опцию -f.
-p pathName: Специфицирует корневую директорию для всех относительных путей, используемых при компиляции. (Используйте перед опцией -f.) Для этой опции можно указать только один путь.
-f includeFile: Специфицирует файл, который является списком входных файлов, что позволяет обойти ограничение на количество символов, вводимых в командной строке. Для этой опции можно указать только одно имя файла. Файлы в списке входных файлов в includeFile разделены пробелами. Если имя файла содержит пробел, Вы обязаны заключить имя файла в двойные кавычки.
-r errorFile: Перенаправляет стандартный вывод (включая сообщения об ошибках) в специфицированный файл. В этой опции можно указать только одно имя файла.
-a 1.2: Устанавливает версию в 1.2 для обеспечения обратной совместимости.
Например, следующая команда компилирует и компонует две HTML -страницы с JavaScript, main.html и hello.html, и файл серверного JavaScript, support.js, создавая двоичный исполняемый файл с именем myapp.web. Кроме того, в процессе компиляции компилятор печатает в командной строке информацию о ходе компиляции.
jsac -v -o myapp.web main.html hello.html support.js
В следующем примере команда компилирует файлы, перечисленные в файле looksee.txt, в бинарный исполняемый файл под названием looksee.web:
jsac -f looksee.txt -o looksee.web
Здесь looksee.txt может содержать:
looksee1.html
looksee2.html
\myapps\jsplace\common.js
looksee3.html
Конфигурирование Среды
Прежде чем Вы сможете запустить эти приложения, необходимо сделать незначительные изменения в исходных файлах и создать базу данных для видео. В данном разделе указывается, какие файлы Вы обязаны изменить и какие процедуры выполнить, чтобы внести эти изменения и создать БД для каждого из поддерживаемых серверов БД. См. конкретную информацию в разделе, посвящённом Вашему серверу БД.
ПРИМЕЧАНИЕ:
Ваш сервер БД обязан быть настроен и запущен перед началом создания видео-БД, и Вы обязаны сконфигурировать сервер и клиента БД так, как указано в Кроме того, скрипты создания БД используют утилиты БД, поставляемые с Вашими БД. Вы уже должны знать, как пользоваться этими утилитами.
Конфигурирование Установок по Умолчанию
Чтобы конфигурировать установки по умолчанию для Application Manager, щёлкните Configure (в Enteprise Server 3.x) или Preferences (в Enterprise Server 4.0) в верхнем фрэйме Application Manager'а. В ответ Application Manager отобразит форму, показанную на .
Вы можете специфицировать следующие значения по умолчанию:
Web File Path: Путь по умолчанию к рабочей директории.
Default Page: Имя по умолчанию для страницы по умолчанию в новом приложении.
Initial Page: Имя по умолчанию для начальной страницы в новом приложении.
Built-in Maximum Database Connections: Значение по умолчанию - максимальное количество соединений с базами данных, которые могут устанавливаться для предопределённого объекта database.
External Libraries: Путь по умолчанию к директории с внешними исполняемыми библиотеками.
Client Object Maintenance: Техника по умолчанию для обслуживания свойств объекта client.
Если Вы устанавливаете новое приложение, используются значения полей по умолчанию в качестве начальных значений.
Дополнительно Вы можете специфицировать следующие установки:
Confirm on: Требовать ли Вашего подтверждения для выполнения удаления, старта, остановки или рестарта приложения.
Debug Output: Появляется ли окно трассировки, при отладке приложения, в том же окне, что и само приложение, но в отдельном кадре, или в отдельном от приложения окне.
Рисунок 3.6 Форма "Установки по Умолчанию"
![](image/config.gif)
Конструирование HTML-Страницы
Когда Вы компилируете приложение JavaScript, исходники состоят из HTML-страниц, содержащих операторы серверного JavaScript, и, возможно, HTML-страницы, не содержащие операторов серверного JavaScript. Если пользователь получает доступ к странице, которая не содержит серверных операторов, сервер высылает страницу обратно, как и любую другую HTML-страницу. Если пользователь получает доступ к странице, которая содержит серверные операторы, машина выполнения на сервере конструирует HTML-страницу для отправки в ответе, используя одну из исходных страниц Вашего приложения.
Машина выполнения сканирует исходную страницу. При обнаружении операторов HTML клиентского JavaScript она присоединяет их к создаваемой странице. При обнаружении операторов серверного JavaScript она выполняет их. Хотя большинство операторов серверного JavaScript выполняются на сервере, некоторые влияют на конструируемую страницу. В следующих разделах рассматриваются три функции: write, flush и redirect, которые влияют на обрабатываемую HTML-страницу.
Конвертация Данных
Есть два основных формата файлов : ASCII-текст и бинарный. Методы byteToString и stringToByte класса File конвертируют данные этих форматов.
Метод byteToString конвертирует число в односимвольную строку. Это static-метод. Вы можете использовать класс File сам по себе, а не его экземпляр, для вызова этого метода.
File.byteToString(number);
Если аргумент - не число, метод возвращает пустую строку.
Метод stringToByte конвертирует первый символ своего аргумента, строку, в число. Это также static-метод.
File.stringToByte(string);
Метод возвращает числовое значение первого символа или 0.
Конвертация из Java в JavaScript
Значения, переданные из Java в JavaScript конвертируются так:
Java byte, char, short, int, long, float и double конвертируются в числа JavaScript.Java boolean конвертируется в JavaScript boolean.Объект класса netscape.javascript.JSObject конвертируется в оригинальный JavaScript-объект.
Java-массивы конвертируются в объект JavaScript pseudo-Array; этот объект ведёт себя так же, как объект JavaScript Array: Вы можете иметь к нему доступ с синтаксисом arrayName[index] (где index это целое число) и определять его размер с помощью arrayName.length.
Java-объект любого иного класса конвертируется в JavaScript-оболочку, которая может использоваться для доступа к методам и полям Java-объекта:
Конвертация оболочки в строку вызывает метод toString объекта-оригинала.Конвертация в число вызывает метод doubleValue, если возможно, иначе - терпит неудачу.
Конвертация в boolean вызывает метод booleanValue, если возможно, иначе - терпит неудачу.
Обратите внимание, что экземпляры java.lang.Double и java.lang.Integer конвертируются в объекты JavaScript, а не в числа JavaScript. Аналогично, экземпляры java.lang.String также конвертируются в JavaScript-объекты, а не в строки JavaScript.
Java String -объекты также соответствуют оболочкам JavaScript. Если Вы вызываете JavaScript-метод, который требует строки JavaScript, и передаёте его данной оболочке, Вы получите ошибку. Вместо этого конвертируйте оболочку в строку JavaScript, присоединяя к ней пустую строку, как показано здесь:
var JavaString = JavaObj.methodThatReturnsAString(); var JavaScriptString = JavaString + "";
1
2
Конвертация из JavaScript в Java
Если Вы вызываете Java-метод и передаёте ему параметры из JavaScript, типы данных передаваемых параметров конвертируются в соответствии с правилами, описанными в следующих разделах:
Return-значения методов netscape.javascript.JSObject всегда конвертируются в экземпляры java.lang.Object. Правила конвертации этих return-значений также описаны в этих разделах.
Например, если JSObject.eval возвращает число JavaScript, Вы можете найти правило конвертации этого числа в экземпляр java.lang.Object в разделе .
Конвертация Типов Данных
Поскольку Java является строго типизированным, а JavaScript - слабо типизированным языком, машина выполнения JavaScript конвертирует значения аргументов в подходящие типы данных других языков, если Вы пользуетесь LiveConnect. Эта конвертация описана в следующих разделах:
Конвертация Типов Данных Базой Данных
В следующей таблице показана конвертация, выполняемая машиной выполнения JavaScript для баз данных DB2.
char(n), varchar(n), long varchar, clob(n) | string | ||
integer, smallint | integer | ||
decimal, double | double | ||
date, time, timestamp | Date | ||
blob | Blob |
В следующей таблице дана конвертация БД Informix.
char, nchar, text, varchar, nvarchar | string | ||
decimal(p,s), double precision, float, integer, money(p,s), serial, smallfloat, smallint | number | ||
date, datetime | Date | ||
byte | Blob | ||
interval | Не поддерживается |
1
Тип даты Informix datetime имеет точность переменных, определяемых пользователем. Серверный JavaScript выводит данные datetime в формате от YEAR до SECOND. Если datetime -переменная была определена с другой точностью, такой как от MONTH до DAY, она может быть отображена некорректно. В данном случае дата не нарушится некорректным отображением. |
ODBC транслирует типы данных продавца в типы данных ODBC. Например, в Microsoft SQL Server тип данных varchar конвертируется в ODBC-тип SQL_VARCHAR. Дополнительно см. документацию ODBC SDK.
В следующей таблице показана конвертация, выполняемая машиной JavaScript для баз данных ODBC.
SQL_LONGVARCHAR, SQL_VARCHAR, SQL_CHAR | string | ||
SQL_SMALLINT, SQL_INTEGER, SQL_DOUBLE, SQL_FLOAT, SQL_REAL, SQL_BIGINT, SQL_NUMERIC, SQL_DECIMAL | number | ||
SQL_DATE, SQL_TIME, SQL_TIMESTAMP | Date | ||
SQL_BINARY, SQL_VARBINARY, SQL_LONGBINARY | Blob |
В следующей таблице показана конвертация, выполняемая машиной выполнения JavaScript для баз данных Oracle.
long, char(n), varchar2(n), rowid
В следующей таблице показана конвертация, выполняемая машиной выполнения JavaScript для баз данных Sybase.
Sybase- клиент ограничивает числовые типы данных 33 цифрами. Если Вы вставляете число JavaScript с большим количеством цифр в БД Sybase, Вы можете получить ошибку.
LiveConnect
Даёт возможность кодам на Java и JavaScript взаимодействовать друг с другом. Из JavaScript Вы можете инстанциировать Java-объекты и получать доступ к их public-методам и полям. Из Java Вы можете иметь доступ к объектам, свойствам и методам JavaScript.
Локализация Компилятора
Инсталяция Netscape-сервера не изменяет Вашу переменную окружения PATH для включения директории, в которой установлен компилятор приложений JavaScript. Если Вам необходим быстрый доступ к компилятору, Вы обязаны модифицировать эту переменную.
В системах Unix у Вас есть выбор способов изменения переменной окружения PATH. Можно добавить $NSHOME/bin/https/lib, где $NSHOME это директория, в которой установлен Ваш сервер. Поговорите с Вашим системным администратором о том, как это сделать.
Чтобы изменить системный путь NT, запустите Control Panel, найдите диалоговое окно System и установите переменную PATH в разделе Environment settings, включив в неё %NSHOME%\bin\https\bin, где NSHOME это директория, в которой установлен Ваш сервер.
Если вы переместили компилятор JavaScript-приложений в другое место, Вы обязаны добавить эту новую директорию в переменную PATH.
Локальный Informix
Если вы устанавливаете Informix локально, Вы обязаны установить клиента Informix до установки Informix-сервера.
Только для Unix: Если Вы используете 7.22 Online Server для Unix, процесс инсталяции создаёт соответствующую структуру директорий и файл sqlhosts. Вы обязаны установить переменные окружения, как для удалённого сервера.
Только для NT: Вы должны установить Online Server 7.20. Это установит также и клиента; дополнительные шаги не нужны. Если Ваш web-сервер запускается как System, убедитесь, что у вас запущен regcopy.exe.
Локальный Oracle
Только для Unix: Прежде чем Вы сможете подключиться к Oracle под Irix, Вы обязаны иметь соответствующие патчи для Irix. См. в информацию о необходимых патчах.
Все платформы: Вы обязаны установить Oracle Workgroup Enterprise Server 7.3.2 (NT) или Enterprise Server 7.3.x (Unix). Клиенты Oracle 7.1 и 7.2 не поддерживаются. Уточните у вашего поставщика сервера, совместима ли Ваша версия Oracle-сервера с Oracle-клиентом.
Вы обязаны установить следующие переменные окружения:
ORACLE_HOME |
Специфицирует директорию верхнего уровня, в которой установлен Oracle. | |
ORACLE_SID |
Специфицирует Oracle System Identifier (Системный Идентификатор). |
Если у Вас локальный сервер БД Oracle, Вы обязаны передавать пустую строку в качестве второго аргумента методу connect объектов database или DbPool или конструктору DbPool. Таким образом, эти методы используют значение переменной окружения ORACLE_SID. Например:
database.connect ("ORACLE", "" "user", "password", "");
Об инсталяции Oracle см. дополнительно документацию по Oracle.
Локальный Sybase
Только для Unix: Установите следующие переменные окружения:
SYBASE |
Директория верхнего уровня, в которой установлен Sybase. | |
LD_LIBRARY_PATH |
(DEC) Обязана содержать $SYBASE/lib. |
Для Solaris Вы обязаны также следовать инструкциям раздела
Все платформы: Установите Sybase SQL Server версии 11.1; клиентская часть устанавливается вместе с сервером. Поддерживаемые версии перечислены в разделе
Вы можете использовать подходящую утилиту Sybase для ввода в файл sql.ini (NT) и файл interfaces (все платформы) информации об удалённом сервере, с которым Вы хотите установить соединение. Дополнительно см. документацию Sybase.
Манипуляции с Результатами Выполнения Запросов с Помощью Ку́рсоров
Часто Вам необходимо не просто отобразить таблицу с результатами выполнения запроса, но изменить форматирование этих результатов или даже выполнить какую-нибудь их обработку. Для манипуляций результатами выполнения запроса Вы работаете с курсором БД, возвращаемым запросом к БД. Для создания экземпляра класса Cursor вызовите метод cursor объекта database или объекта Connection, передав ему оператор SQL SELECT в качестве параметра.
Вы можете представить курсор как виртуальную таблицу с рядами и столбцами, специфицированный по запросу. Курсор предполагает также понятие текущего ряда, который в реальности является указателем на ряд виртуальной таблицы. Когда Вы выполняете операции с курсором, они обычно воздействуют на текущий ряд.
По окончании работы, закройте курсор БД путём вызова его метода close. Соединение с БД не может быть освобождено, пока не закрыты все ассоциированные с ним курсоры. Например, если Вы вызываете метод release объекта Connection и это соединение имеет ассоциированный курсор, который не был закрыт, соединение не будет освобождено, пока курсор не будет закрыт.
В таблице обобщены методы и свойства класса Cursor.
colName |
Свойства, соответствующие каждому столбцу курсора. Имя каждого свойства colName это имя столбца в БД. | ||
close |
Закрывает курсор. | ||
columns |
Возвращает количество столбцов в курсоре. | ||
columnName |
Возвращает имя столбца в курсоре. | ||
next |
Делает следующий ряд курсора текущим рядом. | ||
insertRow |
Вставляет новый ряд в специфицированную таблицу. | ||
updateRow |
Обновляет записи в текущем ряду специфицированной таблицы. | ||
deleteRow |
Удаляет текущий ряд специфицированной таблицы. |
Полную информацию об этих методах см. в описании класса Cursor в книге "Серверный JavaScript. Справочник".
Манипуляции с Запросами и Ответами
Обычный запрос, высылаемый клиентом на сервер, не имеет content type (тип содержимого). Машина выполнения JavaScript автоматически обрабатывает такие запросы. Однако, если пользователь отправляет форму, то клиент автоматически помещает content type в шапку/header, чтобы сообщить серверу, как интерпретировать данные формы. Этот content type обычно application/x-www-form-urlencoded. Машина выполнения также автоматически обрабатывает запросы с этим content type. В таких ситуациях Вам редко нужен прямой доступ к шапкам/header запроса или ответа. Если, однако, Ваше приложение использует иной content type, оно обязано уметь работать с шапкой запроса.
В свою очередь, типичный ответ сервера клиентку имеет тип содержимого text/html. Машина выполнения автоматически добавляет этот content type в свой ответ. Если Вам в ответе нужен другой content type, Вы обязаны предоставить его сами.
Для поддержки этих потребностей машина выполнения JavaScript на сервере даёт возможность Вашему приложению иметь доступ к (1) шапке/header любого запроса и к (2) телу запроса, имеющего нестандартный content type. Вы уже контролируете тело ответа тэгом SERVER и тэгами HTML. Функциональность, описанная в этом разделе, даёт также возможность управлять шапкой/header ответа.
Вы можете использовать эту функциональность в различных целях. Например, как описано в разделе , можно осуществлять связь серверных и клиентских процессов с помощью кук. Также Вы можете использовать эту функциональность для поддержки выгрузки файлов.
World Wide Web Consortium публикует онлайновую информацию о протоколе HTTP и о том, что может пересылаться по этому протоколу. См., например, .
Менеджер Приложений. Детали.
В этом разделе показано, как изменять установки по умолчанию для Application Manager. Кроме того, говорится о формате файла, в котором Application Manager хранит информацию.
Менеджер Приложений JavaScript. Обзор.
Прежде учиться создавать приложения JavaScript, Вы должны ознакомиться с Менеджером Приложений JavaScript. Вы можете использовать Application Manager для выполнения следующих задач:
Добавления нового JavaScript-приложения.
Модификации любых атрибутов уже установленного приложения.
Останова, старта и рестарта установленного приложения.
Запуска и отладки активного приложения.
Удаления установленного приложения.
Application Manager сам является приложением на JavaScript, демонстрирующим мощь и гибкость JavaScript. Вы запускаете JavaScript Application Manager по следующему URL в Navigator'е:
http://server.domain/appmgr
В ответ Application Manager отобразит страницу, показанную на для Netscape Enterprise Server 3.x и на Рисунке 3.3 - для Enterprise Server 4.0.
Рисунок 3.2 Application Manager в Enterprise Server 3.x
![](image/appmgr2.gif)
Рисунок 3.3 Application Manager в Enterprise Server 4.0
![](image/appmgr4.gif)
Application Manager отображает в прокручиваемом левом фрэйме (кадре/окне) все приложения JavaScript, установленные в данный момент на сервере. Выберите нужное приложение, щёлкнув на его имени в прокручиваемом списке.
Правый фрэйм отображает для выбранного приложения следующую информацию:
название приложения в верхней части фрэйма
путь к web-файлу приложения на сервере
начальную страницу и страницу по умолчанию
максимальное количество соединений с БД, допустимых для предопределённого объекта database
внешние библиотеки (если имеются)
технику обслуживания объекта client
статус приложения: active или stopped (Пользователи могут запускать только активные приложения. Остановленные приложения недоступны.)
Описание этих полей см. в разделе .
Для добавления нового приложения щёлкните вверху кнопку Add Application.
Щёлкните Configure (в Enteprise Server 3.x) или Preferences (в Enterprise Server 4.0) для конфигурирования установок по умолчанию для Application Manager.
Щёлкните Documentation, чтобы перейти на страницу технической поддержки Netscape JavaScript, где имеются ссылки на разнообразную документацию. Щёлкните Help для получения дополнительных инструкций об использовании Application Manager.
Методы и Свойства Результирующего Набора
В таблице дано резюме по методам и свойствам класса Resultset.
colName |
Свойства, соответствующие каждому столбцу результирующего набора. Имя каждого свойства это имя столбца в БД. Поскольку хранимые процедуры Informix и DB2 не возвращают именованных столбцов, эти свойства не создаются для хранимых процедур Informix или DB2. | ||
columns |
Возвращает количество столбцов результирующего набора. Для Informix этот метод возвращает количество return-значений для одного ряда. | ||
columnName |
Возвращает имя столбца в результирующем наборе. Поскольку хранимые процедуры Informix и DB2 не имеют ассоциированных имён столбцов, не используйте этот метод для хранимых процедур этих БД. | ||
close |
Удаляет Resultset -объектobject. | ||
next |
Делает следующий ряд результирующего набора текущим рядом. Возвращает false, если текущий ряд является последним рядом результирующего набора; иначе возвращает true. |
resultSet -объект является объектом "только для чтения"/read-only, объектом последовательного стиля/sequential-style. Исходя из этого, класс не имеет методов insertRow, deleteRow и updateRow, определённых для Cursor -объектов.
Методы Работы с Ошибками
Как уже было сказано, многие методы возвращают числовой статус-код. Если метод возвращает статус-код, может иметься и соответствующие код ошибки и сообщение от сервера БД. LiveWire имеет четыре метода для объектов Connection, DbPool и database для доступа к error-кодам и сообщениям БД.
Вот эти методы:
majorErrorMessage: наивысшее сообщение об ошибке, возвращённое базой данных.
minorErrorMessage: наименьшее сообщение об ошибке, возвращённое базой данных.
majorErrorCode: наивысший error-код, возвращённый БД. Обычно он соответствует SQLCODE сервера.
minorErrorCode: второй/secondary error-код, возвращённый базой данных.
Результаты, возвращаемые этими методами, зависят от используемого сервера БД и статус-кода БД. В большинстве случаев Вам нужно рассматривать только наивысший error-код или сообщение об ошибке, чтобы понять суть ошибки. Меньшие error-код и сообщение используются только в некоторых ситуациях.
ПРИМЕЧАНИЕ:
Вызов другого метода объектов Connection, DbPool или database может зачистить/reset error-коды и сообщения. Чтобы исключить потерю информации, не забудьте проверить эти методы, перед тем как продолжить.
После получения сообщения об ошибке ваше приложение может вывести сообщение пользователю. Ваше сообщение может включать строку, возвращённую majorErrorMessage или minorErrorMessage, или число, возвращённое majorErrorCode или minorErrorCode. Дополнительно можно обработать число или строку, перед тем как вывести их.
При обсчёте строки, возвращённой majorErrorMessage и minorErrorMessage, LiveWire возвращает строку поставщика БД с присоединённым дополнительным текстом. Детальную информацию о возвращаемых значениях см. в описаниях этих методов в книге Серверный JavaScript. Справочник.
Microsoft SQL Server (только для NT)
Прежде чем использовать нижеуказанные инструкции, Вы обязаны сконфигурировать Ваш Sybase-клиент, как указано в разделе Кроме того, в Unix установите DSQUERY так, чтобы она указывала на Ваш сервер.
SQL-файлы для создания видео-БД в MS SQL Server, находятся в двух директориях:
$NSHOME\js\samples\videoapp\mss
$NSHOME\js\samples\oldvideo\mss
Из командной строки DOS запустите пакетный файл:mss_load userid password
Например:c:\netscape\server\js\samples\videoapp\mss\mss_load sa
Теперь можно запускать приложение, сделав изменения, описанные в разделе .
ПРИМЕЧАНИЕ:
Если у Вас на машине установлены и Sybase, и MS SQL Server или DB2, потенциально может возникнуть конфликт имён. Эти производители поставляют утилиты с одинаковыми названиями (bcp и isql). При запуске этих скриптов убедитесь, что переменная окружения настроена для запуска корректной утилиты.
MIME
Multipart Internet Mail Extension. Стандарт, специфицирующий формат данных, пересылаемых по internet.
Модифицирование Приложения Hello World
В этом разделе Вы модифицируете, рекомпилируете и рестартуете приложение-образец. Для редактирования исходного файла Вы сначала должны найти его. Как Вы помните, Application Manager показывает путь к исполняемому файлу приложения (файлу с расширением .web). Исходный файл hello.html должен находиться в той же директории. Отредактируйте файл. HTML-файл начинается такими операторами:
<html>
<head> <title> Hello World </title> </head><body>
<h1> Hello World </h1>
<p>Your IP address is <server>write(request.ip);</server>
<server>
write ("<P>Last time you were " + client.oldname + ".");
</server>
<p>This time you are <server>write(request.newname);</server>
<server>client.oldname = request.newname; </server>
Добавьте строку, выводящую тип пользовательского браузера:
<p>You are using <server>write(request.agent)</server>
Если Вам нужно, можете также персонализировать шапку/head страницы; например, можете сделать такой заголовок: "Fred's Hello World."
Когда вы закончите изменение файла, запустите компилятор приложений JavaScript. В командной строке перейдите в директорию, содержащую исходный файл. Введите такую строку для компиляции приложения:
jsac -v -o hello.web hello.html
Альтернативно Вы можете из этой директории запустить скрипт build (в Unix) или build.bat (в NT). В этом случае компилятор стартует и выводит сообщения. Последнее сообщение должно быть "Compiled and linked successfully/Откомпилировано и скомпоновано успешно".
Опубликуйте файлы на Вашем сервере разработки. Для рестарта войдите в Application Manager, выберите Hello World, затем выберите Restart. Эта операция загрузит на сервер новую откомпилированную версию приложения. Затем Вы можете запустить приложение, выбрав Run. Открывается окно с Hello World. Вы увидите внесённые Вами изменения в приложении.
Модифицирование videoapp
Как способ применения функциональности LiveWire рассмотрим пример модернизации videoapp. Вот что можно сделать:
Изменить предположение о том, что существование массива sharedConnections предполагает наличие соединения у пользователя. Вы можете изменить start.htm, чтобы выполнять проверку наличия ID у данного пользователя в этом массиве и проверить, хранится ли соединение в нужном месте. См. раздел .
Это приложение никогда не возвращает соединения обратно в пул. Следовательно, если некоторое количество пользователей соединились, больше никто соединиться не сможет. Вы можете изменить это двумя путями: добавить новую команду, позволяющую пользователю указывать на завершение работы, или реализовать схему зачистки неиспользуемых соединений. См. .
Модификация Приложения
Чтобы модифицировать приложение, выберите имя приложения в списке приложений и щёлкните Modify.
Вы можете изменить любое поле, определённое при инсталяции приложения, за исключением имени приложения. Чтобы изменить имя приложения, необходимо удалить приложение, а затем реинсталировать его.
Если Вы модифицируете поля остановленного приложения, Application Manager автоматически запускает его. Если Вы модифицируете поля активного приложения, Application Manager автоматически останавливает и запускает его.
Навигация с Помощью Курсоров
Сначала указатель курсора позиционируется перед первым рядом виртуальной таблицы. Метод next используется для перемещения между записями виртуальной таблицы. Этот метод передвигает указатель на следующий ряд и возвращает true, когда следующий ряд виртуальной таблицы найден. Если следующего ряда нет, next возвращает false.
Например, предположим, что виртуальная таблица имеет столбцы с названиями title, rentalDate и dueDate. Следующий код использует next для итерации по рядам и отображения значений столбцов в таблице:
// Создаём курсор.
custs = connobj.cursor ("select * from customer");
// Проверяем курсор и отсутствие ошибок БД.
if ( custs && (connobj.majorErrorCode() == 0) ) {
write ("<TABLE>"); // Итерация по рядам с отображением значений.
while (custs.next()) {
write ("<TR><TD>" + custs.title + "</TD>" +
"<TD>" + custs.rentalDate + "</TD>" +
"<TD>" + custs.dueDate + "</TD></TR>");
}
write ("</TABLE>");
// Всегда закрывайте курсоры по окончании работы!
custs.close();
}
Этот код даст на выходе:
Clockwork Orange |
6/3/97 |
9/3/97 | |||
Philadelphia Story |
8/1/97 |
8/5/97 |
Вы не всегда можете находиться в нужном месте в курсоре. Например, предположим, что Вы создаёте курсор и, пока Вы работаете с ним, кто-то добавляет ряд в таблицу. В зависимости от установок БД, этот ряд может появиться в Вашем курсоре. Исходя из этого, когда это удобно (как при обновлении рядов), Вы можете сделать так, чтобы Ваш код проверял, находится ли указатель в нужном ряду.
Несколько Результирующих Наборов
Хранимая процедура Sybase, Oracle, DB2 или ODBC может создавать несколько результирующих наборов. В этом случае хранимая процедура предоставляет один resultSet -объект для каждого набора.
Предположим, Ваша хранимая процедура выполняет такие операторы SQL:
select name from customers where id = 6767
select * from orders where id = 6767
Вы можете использовать несколько resultSet -объектов, генерируемых этими операторами, таким образом:
// Этот оператор нужен для DB2, ODBC и Sybase.
poolobj.storedProcArgs("GetCustOrderInfo","IN");
spobj = connobj.storedProc("GetCustOrderInfo",6767);
if ( spobj && (connobj.majorErrorCode() == 0) ) {
resobj1 = spobj.resultSet();
// Перед тем как продолжить, убедитесь, что результирующий набор существует.
if ( resobj1 && (connobj.majorErrorCode() == 0) ) {
// Первый результирующий набор возвращает только один ряд.
// Убедитесь, что ряд содержит данные.
rowexists = resobj1.next();
if ( rowexists )
write("<P>Customer " + resobj1.name +
" has the following orders:</P>");
resobj1.close();
// Второй результирующий набор возвращает один ряд для каждого заказа, // помещённого пользователем. Убедитесь, что ряды содержат данные.
resobj2 = spobj.resultSet();
var i = 0; if ( resobj2 && (connobj.majorErrorCode() == 0) ) {
write("\nOrder# Quantity Total</P>");
while(resobj2.next()) {
write(resobj2.orderno + " " + resobj2.quantity
+ " " + resobj2.Totalamount + "</P>");
i++;
}
resobj2.close();
write("Customer has " + i + " orders.</P>");
}
else write("Customer has no orders.</P>");
}
}
spobj.close();
В качестве примера использования нескольких ref-курсоров Oracle в хранимой процедуре см. описание класса Resultset в книге
Серверный JavaScript. Справочник.
Netscape cookie protocol/протокол кук Netscape
Netscape-формат специфицирования параметров кук в "шапках"/header HTTP.
Null-Значения
Когда Вы передаёте null JavaScript в качестве параметра Java-методам, Java конвертирует это значение в соответствии с правилами, описанными в таблице:
Любой класс |
Значение становится null. | ||
byte |
Значение становится 0. | ||
boolean |
Значение становится false. |
О Конвертации Типов Данных
В БД имеется богатый набор типов данных. Машина выполнения JavaScript на сервере конвертирует эти типы данных в значения JavaScript, строки или числа. Число в JavaScript хранится как значение двойной точности с плавающей точкой. Вообще машина выполнения конвертирует символьные типы данных в строки, числовые типы данных - в числа, а даты - в Date -объекты JavaScript. Она также конвертирует null-значения в JavaScript null.
Примечание
Поскольку JavaScript не поддерживает фиксированные или упакованные десятеричные числа, возможна некоторая потеря точности при чтении и записи типов упакованных десятеричных данных. Проверьте результаты до вставки их обратно в БД и используйте соответствующие математические функции для коррекции потери точности.
О Приложениях-Образцах Серверного JavaScript
Если вы устанавливаете Netscape web-сервер, несколько примеров приложений JavaScript устанавливаются одновременно. Для получения представления о возможностях приложений JavaScript запустите их и просмотрите исходный код. Вы можете также изменять эти приложения по мере изучения возможностей JavaScript. Исходные и исполняемые файлы этих приложений установлены в директории $NSHOME\js\samples, где $NSHOME это директория, в которой Вы установили сервер.
В таблице перечислены приложения-образцы.
world | Приложение "Hello World". | |||
hangman | "Виселица". | |||
cipher | Угадай цифру. | |||
Простой интерактивный SQL-доступ с использованием LiveWire.
Если Вы имеете ограниченный доступ к Application Manager, это приложение также защищено именем и паролем администратора сервера. | ||||
videoapp | Приложение видео-магазин, использующее реляционную БД видеоклипов. | |||
oldvideo | Альтернативная версия видео-магазина. | |||
bugbase | Пример БД "жучков" с использованием LiveConnect. | |||
sendmail | Демонстрирует способность отправлять e-mail из вашего приложения JavaScript. | |||
viewer | Даёт возможность просматривать файлы на сервере, используя класс JavaScript File.
Из соображений безопасности это приложение не устанавливается автоматически вместе с Netscape-сервером. Если Вы его устанавливаете, ограничьте к нему доступ. Иначе неавторизованный пользователь сможет читать и записывать файлы на Вашем сервере. Об ограничении доступа к приложению см. руководство администратора Вашего web-сервера. | |||
jsaccall | Пример использования внешних библиотек и предоставления доступа к CGI-переменным. |
1
Эти приложения работают только при наличии поддерживаемого сервера БД, установленного в сети, и корректно сконфигурированного клиентского программного обеспечения. См. . Перед началом использования videoapp или oldvideo выполните указания по их установке. |
ПРИМЕЧАНИЕ:
Помимо указанных, в директории $NSHOME\js\samples имеется также приложение metadata. Оно используется Visual JavaScript. Когда Вы будете просматривать исходный код, не изменяйте исполняемый файл.
Остаток этой главы посвящён двум простым приложениям, которые дадут Вам возможность поработать с приложениями JavaScript. Не беспокойтесь о деталях. Это обсуждение предназначается только для того, чтобы показать Вам возможности приложений JavaScript. Детали обсуждаются далее в этой главе.
В , приложение videoapp рассматривается детально. Вы должны прочесть эту главу перед началом работы с LiveWire Database Service.
О Приложениях Videoapp и Oldvideo
Netscape-серверы поставляются с двумя приложениями-образцами для работы с базами данных, videoapp и oldvideo, которые иллюстрируют работу LiveWire Database Service. Эти приложения весьма похожи; они отслеживают прокат видео в воображаемом видео-салоне. Приложение videoapp демонстрирует использование объектов DbPool и Connection. Приложение oldvideo демонстрирует использование предопределённого объекта database.
Есть несколько небольших ограничений на использование этих приложений:
Приложение videoapp не может базироваться на БД Informix. Приложение oldvideo может использоваться с Informix.Поскольку эти приложения могут использоваться с ODBC и SQL Server, если драйвер на Вашей платформе не поддерживает обновляемые курсоры, приложения работать не будут. О том, какие драйверы поддерживают обновляемые курсоры, см. раздел .
Приложение videoapp использует курсоры, захватывающие несколько HTML-страниц. Если ваш драйвер БД - однопоточный, эти курсоры могут иметь блокировки для БД и препятствовать доступу к ним других пользователей.
О том, какие драйверы являются однопоточными, см. .
О Сервисе CORBA
Netscape Internet Service Broker for Java (ISB for Java) это брокер запроса объектов фирмы Netscape. ISB for Java устанавливает соединения внутри себя и с другими брокерами запроса объектов/object request brokers (ORB) путём использования протокола Internet InterORB Protocol (IIOP).
ISB for Java даёт Вашим приложениям JavaScript доступ к распределённой объектной модели CORBA, опубликованной в ORB, работающем на основе IIOP (включая сам ISB for Java). Эти объекты могут быть частью распределённого приложения. Чтобы получить доступ к такому распределённому объекту, Вы обязаны иметь Java-stub/основу, и этот stub-класс обязан быть в пути Вашей CLASSPATH. В свою очередь, Вы можете использовать Java и LiveConnect для экспонирования частей Вашего серверного приложения JavaScript как распределённых объектов CORBA.
За пределами данного учебника остаётся описание создания CORBA-исполняемых распределённых объектов с использованием ISB for Java, а также то, как делать Java-стабы для таких объектов. Об этом см. учебник .
Приложения серверного JavaScript могут получать доступ к распределённому объекту в зависимости от того как он опубликован. Простейшей альтернативой является создание и запуск распределённого объекта как отдельного процесса, что показано на следующем рисунке.
Рисунок 22.1 Приложение JavaScript CORBA-клиент
![](image/corba1.gif)
Как видно на рисунке, среды запуска Java и JavaScript находятся вместе на одном web-сервере. Они взаимодействуют путём использования LiveConnect стандартным способом, описанным ранее в этой главе. Методы, вызываемые в оболочке стаба в JavaScript, дают в результате вызов методов объекта Java-стаба в Java. Стаб использует Java ORB для взаимодействия с удалённым сервисом. В данной архитектуре серверный процесс объекта может проходить только на машине, которая имеет ORB, и может быть написан на любом языке.
Приложение-образец flexi иллюстрирует это. В нём FlexiServer это отдельное приложение Java, содержащее реализации нескольких распределённых объектов. Этот пример обсуждается в разделе .
После того как поработаете с flexi, прочтите в разделе обсуждение более сложных альтернатив публикации.
О Службе LiveWire Database Service
Одновременно с версиями 3.x и 4.x Netscape-серверов Вы обязаны установить клиентскую библиотеку БД (и к тому же - определённую версию), если хотите использовать LiveWire Database Service. Вы также обязаны сконфигурировать эту клиентскую библиотеку для работы с LiveWire.
Netscape-серверы не поставляются вместе клиентскими библиотеками БД. Вам нужно связаться с поставщиком Вашей БД на предмет получения соответствующей библиотеки. Вам необходимо установить и сконфигурировать клиентские библиотеки только тех БД, которые Вы будете использовать.
Если Вы устанавливаете БД на другую машину (не на ту, где установлен web-сервер), Вы обязаны иметь установленную клиентскую библиотеку БД на машине с web-сервером. Вы обязаны получить соответствующее лицензионное разрешение от поставщика Вашей БД. Netscape не сделает это за Вас.
Требования по конфигурированию Вашей БД могут отличаться в зависимости от того, находятся ли БД и web-сервер на одной или на разных машинах. Если они на одной машине, последующая информация будет касаться локальной конфигурации; если на разных машинах - удалённой конфигурации.
В этой главе рассмотрены только те аспекты установки клиента БД, которые имеют отношение к использованию с LiveWire. Для получения общей информации об установке клиента БД обратитесь к соответствующей документации поставщика БД.
Объект
Если метод возвращает объект, он может быть либо реальным объектом, либо null. Если метод возвращает null, возможно, возникла ошибка JavaScript. В большинстве случаев, если ошибка возникла в БД, метод возвращает верный объект, но программа устанавливает код ошибки.
Глобальная функция blob возвращает объект. Кроме того, следующие методы также возвращают объект:
Connection.cursor
Connection.storedProc
database.cursor
database.storedProc
DbPool (constructor)
DbPool.connection
Stproc.resultSet
Создаёте ли Вы курсор, результирующий набор или хранимую процедуру, Вы должны проверять и существование созданного объекта, и возможное наличие кода ошибки. Вы можете использовать методы majorErrorCode и majorErrorMessage для тестирования ошибки.
Например, Вы можете создать курсор и проверить его корректность кодом такого вида:
// Создаётся Cursor-объект.
custs = connobj.cursor ("select id, name, city
from customer order by id");// Прежде чем продолжить, убедитесь, что возвращён реальный курсор // и что нет ошибки БД.
if ( custs && (connobj.majorErrorCode() == 0) ) {
// Получить первый ряд.
custs.next();
// ... процессинг рядов курсора ... //Закрыть курсор.
custs.close();
}
else
// ... обработка ошибок ...
Объект client
Несколько браузеров-клиентов могут иметь одновременный доступ к приложению JavaScript. Объект client предоставляет метод для работы отдельно с каждым клиентом. Он также имеет технологию для отслеживания работы каждого браузера-клиента с приложением при наличии нескольких запросов.
Машина выполнения JavaScript на сервере конструирует объект client для каждой пары клиент/приложение. Браузер-клиент, соединённый с одним приложением, имеет другой объект client из того же самого браузера-клиента, соединённого с другим приложением. Машина выполнения конструирует новый объект client каждый раз, когда пользователь выполняет доступ к приложению; могут быть сотни и тысячи объектов client, активных одновременно.
ПРИМЕЧАНИЕ:
Вы не можете использовать объект client на начальной странице Вашего приложения. Эта страница начинает работу при старте приложения на сервере. В этот момент клиентского запроса нет, и поэтому нет также и доступного объекта client. Дополнительно см. раздел .
Машина выполнения конструирует и уничтожает объект client
для каждого клиентского запроса. В то же время, при обработке запроса машина выполнения сохраняет имена и значения свойств объекта client. Таким способом машина выполнения может конструировать новый объект client из сохранённых данных, если тот же самый пользователь вновь использует приложение, сделав следующий запрос. Таким образом, концептуально Вы можете представлять объект client как объект, действующий в течение сессии работы клиента с приложением.
JavaScript не сохраняет объекты client, не имеющие значений свойств. Поэтому, если приложению не нужны объекты client и оно не присваивает свойствам объекта client никаких значений, оно не выполняет никакой лишней работы.
У Вас имеются несколько различных опций: как и где машине выполнения сохранять свойства объекта client. Эти опции обсуждаются в разделе .
Резюме по объекту client см. в разделе .
Объект Packages
Если класс Java не является частью пакетов java, sun или netscape, Вы имеете к нему доступ через объект Packages. Например, корпорация Redwood использует пакет Java под названием redwood как контейнер различных Java-классов, которые ею реализованы. Для создания экземпляра класса HelloWorld в redwood Вы вводите конструктор класса:
var red = new Packages.redwood.HelloWorld()
Вы можете также получить доступ к классам в пакете по умолчанию (то есть классам, которые не указывают пакет явно). Например, если класс HelloWorld находится непосредственно в CLASSPATH, а не в пакете, Вы можете получить к нему доступ так:
var red = new Packages.HelloWorld()
Объекты LiveConnect java, sun и netscape являются сокращениями для обычно используемых пакетов Java. Например, можно записать так:
var myString = new java.lang.String("Hello world")
вместо более длинной версии:
var myString = new Packages.java.lang.String("Hello world")
По умолчанию директория $NSHOME\js\samples, где $NSHOME это директория, в которой установлен сервер, находится в CLASSPATH сервера. Вы можете поместить Ваш пакет в эту директорию. Альтернативно Вы можете поместить Ваши пакеты и классы Java в другую директорию. Если Вы это делаете, убедитесь, что директория находится в Вашем CLASSPATH.
Объект project
Объект project содержит глобальные данные приложения и предоставляет метод для совместного использования информации клиентами, выполняющими доступ к приложению. JavaScript конструирует новый объект project, когда приложение стартует при использовании Application Manager. Каждый клиент, получающий доступ к приложению, использует один и тот же объект project. Резюме по объекту project см. в разделе .
В отличие от предыдущих релизов, в этом релизе машина выполнения JavaScript не создаёт и не уничтожает объект project для каждого запроса. Если Вы остановили работу приложения, объект project этого приложения уничтожается. Новый объект project создаётся для приложения, когда оно стартует снова. Типичный период существования объекта project - дни или недели.
JavaScript конструирует набор объектов project для каждого Netscape HTTP-процесса, запущенного на сервере. JavaScript конструирует объект project для каждого приложения, запущенного на каждом отдельном сервере. Например, если один сервер запущен на порте 80, а другой - на порте 142 на той же самой машине, JavaScript конструирует отдельный набор объектов project для каждого процесса.
Объект request
Объект request содержит данные, специфичные для текущего клиентского запроса. Они имеет самое короткое время существования из всех объектов. JavaScript конструирует новый объект request для каждого получаемого клиентского запроса; например, объект создаётся, когда
Пользователь вручную запрашивает URL путём его ввода или выбора закладки/bookmark.
Пользователь щёлкает гиперссылку или иным способом запрашивает документ, относящийся к другой странице.Клиентский JavaScript устанавливает свойство document.location или переходит к странице, используя метод history.
Серверный JavaScript вызывает функцию redirect.
Машина выполнения JavaScript на сервере уничтожает объект request по окончании ответа на запрос (обычно предоставляя запрошенную страницу). Следовательно, типичный период существования объекта request - менее одной секунды.
ПРИМЕЧАНИЕ:
Вы не можете использовать объект request в начальной странице приложения. Эта страница запускается, когда приложение стартует на сервере. В этой точке нет объекта клиентского запроса, и поэтому нет доступного объекта request. О начальных страницах см. раздел .
Резюме по объекту request см. а разделе .
Объект server
Объект server содержит глобальные данные для всего сервера в целом и предоставляет метод для обеспечения совместного использования информации разными приложениями, работающими на сервере. Объект server также автоматически инициализируется информацией о сервере. Резюме по объекту server см. в разделе .
Машина выполнения JavaScript конструирует новый объект server, когда сервер стартует, и уничтожает объект server, когда сервер останавливается. Каждое приложение, запущенное на сервере, использует один и тот же объект server.
JavaScript конструирует объект server для каждого Netscape HTTPD-процесса (на сервере), запущенного на машине. Например, может иметься серверный процесс на порте 80 и другой - на порте 8080. Это совершенно отдельные серверные процессы, и JavaScript конструирует объект server для каждого из них.
Объекты JavaArray и JavaObject
В большинстве случаев, когда Вы передаёте объект JavaScript JavaArray или JavaObject как параметр Java-методу, Java просто разворачивает этот объект (снимает оболочку); иногда объект переводится в другой тип данных по правилам из таблицы:
Любой интерфейс или класс, который совместим в операции присвоения с развёрнутым объектом. |
Оболочка с объекта снимается. | ||
java.lang.String |
Оболочка с объекта снимается, вызывается метод toStringразвёрнутого Java-объекта, а результат возвращается как новый экземпляр java.lang.String. | ||
byte |
Оболочка с объекта снимается, и возникает одна из следующих ситуаций: Если развёрнутый Java-объект имеет метод doubleValue, JavaArray или JavaObject конвертируется в значение, возвращаемой этим методом. Если развёрнутый Java-объект не имеет метода doubleValue, возникает ошибка. | ||
boolean |
Оболочка с объекта снимается, и возникает одна из следующих ситуаций: Если развёрнутый объект имеет метод booleanValue, объект-источник конвертируется в это return-значение. Если развёрнутый объект не имеет метода booleanValue, конвертация терпит неудачу. |
Интерфейс или класс совместимы для присвоения с развёрнутым объектом, если развёрнутый объект является экземпляром типа Java-параметра. То есть, следующий оператор обязан возвращать true:
развёрнутыйОбъект instanceof типПараметра
Объекты JavaClass
Если вы передаёте JavaScript-объект JavaClass в качестве параметра Java-методу, Java конвертирует объект в соответствии с правилами из таблицы:
java.lang.Class |
Оболочка с объекта снимается. | ||
java.lang.JSObject |
Объект JavaClass оборачивается в новый экземпляр java.lang.JSObject. | ||
java.lang.String |
Оболочка с объекта снимается, вызывается метод toString развёрнутого Java-объекта, а результат возвращается как новый экземпляр java.lang.String. | ||
boolean |
Оболочка с объекта снимается, и возникает одна из следующих ситуаций: Если развёрнутый объект имеет метод booleanValue, исходный объект конвертируется в return-значение. Если объект не имеет метода booleanValue, конвертация терпит неудачу. |
Обмен Информацией
Работа хранимых процедур имеет отличия на разных БД, поддерживаемых сервисом LiveWire Database Service. Самое важное для LiveWire - это отличия в передаче информации в и из хранимой процедуры в приложении на JavaScript. Вы всегда используете параметры ввода хранимой процедуры для передачи информации в хранимую процедуру.
Концептуально имеются несколько способов, которыми можно запросить информацию из хранимой процедуры. Не всегда производитель БД даёт возможность запрашивать информацию любым их этих способов.
Обновление Предыдущей Версии
Если у вас имеется установленная версия предыдущего релиза Netscape web-сервера, Вы должны перенести установки сервера при инсталяции Enterprise Server 4.x. См. Enterprise Server 4.0 Installation and Migration Guide.
Если Вы ранее создавали приложения JavaScript, используя Серверный JavaScript 3.x, Вы должны знать об изменениях, выполняемых при обновлении до версии 4.x и переносе старых установок сервера:
Если предыдущий сервер имел включённую службу LiveWire, сервер 3.x будет иметь включённый JavaScript. Требование (или отсутствие) Application Manager'ом пароля также сохраняется. См. также раздел в .
Обновление установок сервера не переносит ваших приложений, а также не рекомпилирует их для использования с сервером 4.x. Вы обязаны вручную рекомпилировать пользовательские приложения перед тем как использовать их с сервером 4.x, как указано в разделе . Вы должны знать, что старые приложения могут перестать работать с их оригинальными версиями Enterprise Server после рекомпиляции. Если Вы хотите использовать приложения с обоими серверами, Вы должны скопировать приложение, а не перемещать его.Об изменениях, которые, возможно, понадобиться сделать в коде при обновлении, см. следующий раздел.
Обработка Исключений JavaScript в Java
Если JavaScript-код, вызванный из Java, потерпел неудачу на этапе прогона/выполнения, он вызывает исключение. Если Вы вызываете JavaScript-код из Java, Вы можете отловить/catch это исключение в блоке операторов try...catch. Исключение JavaScript доступно коду Java как экземпляр netscape.javascript.JSException. JSException это Java-оболочка вокруг исключения любого типа, вызываемого в JavaScript, так же как и экземпляры JSObject являются оболочками для JavaScript-объектов.
Используйте JSException при вычислении JavaScript-кода в Java. Если JavaScript-код не вычисляется из-за ошибки компиляции JavaScript или из-за какой-то другой ошибки времени прогона, интерпретатор JavaScript генерирует сообщение об ошибке, которое конвертируется в экземпляр JSException.
Например, можно использовать блок try...catch для обработки исключений LiveConnect:
try {
global.eval("foo.bar = 999;");
} catch (Exception e) {
if (e instanceof JSException) {
jsCodeFailed()";
} else {
otherCodeFailed();
}
}
В этом примере оператор eval терпит неудачу, если foo не определён. Блок catch выполняет метод jsCodeFailed, если оператор eval в блоке try вызывает JSException; метод otherCodeFailed выполняется, если блок try вызывает какую-то иную ошибку.
Обработка Ошибок в Серверном JavaScript
Функция ssjs_onError, если она определена в Вашем приложении, вызывается в случае ошибки серверного JavaScript, такой как "undefined variable name/имя переменной не определено". В функции ssjs_onError Вы можете делать всё, что можно делать в функции серверного JavaScript, включая доступ к объектам server, project, client и request. Вы можете также выполнять перенаправление и вызывать другие функции.
Функция ssjs_onError имеет следующий синтаксис:
function ssjs_onError (<message>,<file>,<line number>)
<message> текст сообщения об ошибке
<file> имя исходного файла
<line number> номер строки с ошибкой
Ошибка JavaScript в ходе выполнения функции onError записывается в log-файл и трассируется (если активна). Функция ssjs_onError, однако, не вызывается рекурсивно. Ошибка в функции onError вызывает запись сообщения в error log, но не выполняет вызов onError.
Вот пример функции:
function ssjs_onError(msg,file,line) { write("<br>\n<hr>")
write("error message: "+msg+"<br>\n")
write("file name: "+file+"<br>\n")
write("line number: "+line+"<br>\n")
write("<hr>") }
ПРИМЕЧАНИЕ:
Чтобы дать каждой странице её собственную специальную функцию onError, добавьте присвоение ssjs_onError в начале кода страницы. Например:
ssjs_onError = custom_onError;
function custom_onError(msg,file,line) {
// ... }
Серверный JavaScript выполняет всё, что ssjs_onError представляет во время ошибки. Вы можете использовать одну функцию ssjs_onError, которая совместно используется всеми страницами, либо можете динамически переключаться на другую функцию onError в любое время, в том числе в начале каждой страницы. Если два запроса выполняют одну и ту же функцию onError в один момент времени, они имеют различные среды выполнения, как если бы Вы одновременно выполняли какую-нибудь другую функцию.
| | |
Обратная Совместимость с Предыдущими Релизами
Вы также должны знать об изменениях в поведении приложений серверного JavaScript по сравнению с Netscape Enterprise Server 3.x:
Вы обязаны рекомпилировать все ваши существующие приложения JavaScript. об использовании компилятора см. . После рекомпиляции приложений они больше не будут работать под старыми инсталяциями SSJS.
Обратные Кавычки
Используйте обратные кавычки (`) для выделения выражений серверного JavaScript как заместителей для имён атрибутов или значений атрибутов HTML. JavaScript, внедрённый в HTML с помощью обратных кавычек, автоматически генерирует HTML; Вам не нужно использовать write.
В целом тэги HTML имеют форму:
<TAG ATTRIB="value" [...ATTRIB="value"]>
где ATTRIB это атрибут, а "value
" это его значение. Значение в угловых скобках означает, что допускается любое количество пар атрибут/значение.
Если в обратные кавычки заключено выражение JavaScript, используемое как значение атрибута, машина выполнения JavaScript автоматически добавляет знак кавычки вокруг всего значения. Вы сами не вводите знаки кавычек, хотя Вам это может понадобиться для разграничения строковых литералов выражения, как в следующем примере. Машина выполнения не делает это для имён атрибутов, поскольку не предполагается заключение имён атрибутов в кавычки.
Например, рассмотри следующую строку из образца-приложения Hangman:
<IMG SRC=`"images\hang" + client.num_misses + ".gif"`>
Эта строка динамически генерирует имя изображения на основе значения client.num_misses. Обратные кавычки обрамляют выражение JavaScript, конкатенирующее строку "images\hang" и целочисленное значение client.num_misses и строку ".gif", давая строку типа "images\hang0.gif". Результатом будет HTML, такой как
<IMG SRC="images\hang0.gif">
Порядок ввода кавычек является критичным. Сначала идёт обратная кавычка, указывая, что следующее значение является выражением JavaScript, состоящим из строки ("images\hang"), соединяемой с целым числом (client.num_misses) и с другой строкой (".gif"). JavaScript конвертирует всё выражение до строки и добавляет необходимые знаки кавычек вокруг значения атрибута.
Вы должны внимательно использовать знаки двойных кавычек внутри обратных кавычек, поскольку содержащееся внутри них значение интерпретируется как литерал. Поэтому не окружайте выражения JavaScript, которые необходимо вычислить, знаками кавычек. Например, если значение свойства client.val будет NetHead, то данный оператор:
<A NAME=`client.val`>
генерирует такой HTML:
<A NAME="NetHead">
но следующий оператор:
<A NAME=`"client.val"`>
генерирует HTML:
<A NAME="client.val">
В качестве другого примера приведём два атрибута тэга ANCHOR - HREF и NAME. HREF делает тэг гиперссылкой, а NAME делает его именованным якорем. Следующие операторы используют переменную choice для установки свойств attrib и val объекта client и создают затем гиперссылку/hyperlink или цель/target, в зависимости от значений:
<SERVER>
if (choice == "link") {
client.attrib = "HREF";
client.val = "http://www.netscape.com";
}
if (choice == "target") {
client.attrib = "NAME";
client.val = "NetHead";
}
</SERVER><A `client.attrib`=`client.val`>Netscape Communications</A>
Если значением choice будет "link", результат будет:
<A HREF="http://home.netscape.com">Netscape Communications</A>
Если значением choice будет "target", результат будет:
<A NAME="NetHead">Netscape Communications</A>
Обслуживание Пулов Соединений
В любой данный момент времени соединённый объект DbPool или database и все соединения пула ассоциированы с определённой конфигурацией базы данных. То есть всё, что находится в пуле, соединено с определённым сервером БД как отдельный пользователь с отдельным паролем и с определённой БД.
Если Ваше приложение всегда использует одну конфигурацию, то можно использовать единственный объект DbPool или использовать объект database и соединяться однократно. В этом случае Вы должны выполнить соединение на начальной странице Вашего приложения.
Если Вашему приложению требуется несколько конфигураций, или потому что оно обязано соединяться с несколькими БД, или с одной БД, но с разными пользователями, или и то, и другое, Вам необходимо определить, как обслуживать эти конфигурации.
Если Вы используете объект database и несколько соединений, то выбора у Вас нет. Вы обязаны соединяться, отсоединяться и повторно соединяться с объектом database каждый раз, когда Вам нужно изменить что-либо в конфигурации. Вы делаете это под управлением клиентских запросов. В этой ситуации убедитесь, что используются блокировки, как указано в разделе чтобы получать исключительный доступ к объекту database. Иначе другой клиентский запрос может отключить объект до того, как текущий клиентский запрос закончит с ним работу. Хотя Вы и можете использовать объект database таким образом, лучше будет всё-таки использовать объекты DbPool.
Если Вы используете объекты DbPool и несколько конфигураций, Вы также должны соединяться, отсоединяться и повторно соединяться с объектом DbPool. Однако с объектами DbPool у Вас появится больше возможностей. Вы можете создавать столько пулов, сколько нужно, и ставить их под контроль объекта project. (См. в информацию об объекте project.) Использование нескольких пулов более эффективно и обычно надёжнее, чем многократное использование единственного пула (как с объектом database , так и с единственным объектом DbPool).
При определении того, как обслуживать пулы, Вы обязаны учитывать два фактора: ко скольки конфигурациям будут иметь доступ пулы и нужно ли будет одному соединению захватывать несколько клиентских запросов. Если у Вас небольшое количество возможных конфигураций, Вы можете создать отдельные пулы для каждой. В разделе обсуждается этот подход.
Если у Вас имеется очень большое или заранее не известное количество конфигураций (например, если все пользователи БД получают свои индивидуальные ID), нужно предусмотреть два варианта. Если одного соединения достаточно для выполнения одного клиентского запроса, Вы можете создавать отдельные пулы на клиентской странице.
Однако иногда соединение должно захватывать несколько клиентских запросов (например, если одна транзакция в БД захватывает несколько клиентских запросов). Возможно также, что Вы просто не хотите повторно соединяться с БД на каждой странице приложения. Если это так, Вы можете создать массив пулов, который используется совместно. В разделе обсуждается этот подход.
Независимо от используемого подхода, если Вам больше не нужно отдельное соединение в пуле, зачистите ресурсы, используемые этим соединением, чтобы оно стало доступным для других пользователей. Чтобы выполнить это, закройте все открытые курсоры, хранимые процедуры и результирующие наборы. Верните соединение обратно в пул. (Вы не должны освобождать соединение, если используете объект database.)
Если Вы не освободили соединение, то при попытке отсоединить пул система будет ожидать, перед тем как реально отсоединиться, возникновения одного из двух условий:
Вы освобождаете все соединения
Соединения выходят за пределы области видимости и убираются сборщиком мусора
Если Вы создаёте отдельные пулы БД для каждого пользователя, убедитесь, что пул отсоединён, до того как закончить с ним работу. О курсорах см . О хранимых процедурах и результирующих наборах см. .