Шаг 6 - Системная поддержка

В этой разработке я пользуюсь продуктами "Gupta (Centura)", как и любые инструменты, они имеют некоторые особенности (и недостатки)... вот этому я и посвящу сегодняшний рассказ...

Неприятная проблема, с которой нам пришлось бороться это длина number - как мы обнаружили, сервер поддерживает только 15 разрядов, по жизни такая длина нормальна. Но, если говорить о длине индексных полей, и соответственно, объеме индексного пространства, то, оно мне показалось недостаточным. (Для примера, длина number в Oracle 35 разрядов.) А если мы говорили о распределенной (сетевой) системе учета, в основе которой лежат "центры учета" и между которыми, по определенной технологии, осуществляется репликация данных, самым главным свойством индексов есть их уникальность в системе, и, как обеспечить их в "сети"? Проще всего добавить поле с индексом сервера, и "закатать" двойной "примари индекс" но, что - то мне в "двойных индексах" не понравилось, я решил пойти "другим путем". Меня заинтересовал вопрос, а можно ли два индекса заменить одним? понятно же, что количество ункальных серверов данных будет невпример меньше, чем размер индекса... Можно же и выделить для каждого сервера "секвенс"- диапазоны. Как? Да выделяем каждому серверу двухразрядный номер ( если серверов в сети может быть не более 99) или трехразрядный, для 999, берем текущий секвенс умножаем его на 100 (или 1000) и складываем с номером сервера вот вам и уникальные Идентификаторы. Но, что останется от секвенса при умножении? Ведь у нас всего 15 разрядов (а у меня мания переполнения :-)). Я решил перейти на символьные Индексы - и сделал индексную арифметику - по основанию 232. Да, именно, столько - дело в том, что первых 32-х символов в таблице символов сервера нет, и... вот и пришлось несколько ограничить аппетиты. Но, и в этом случае строкой в 18 символов я смоделировал размеры "Ораклового" индексного пространства.

Теперь я расскажу, как это работает. Табличка, совершенно необходимая для процесса:

CREATE TABLE SYSADM.NUR (
	ID DOUBLE PRECISION
)
/

ID - просто номер... им активно пользуемся...

Теперь пора описать процесс создания индексов.

Вот текст процедуры, которая создает новых "членов" в индексной последовательности.

STORE SYSADM.GETMAXID Procedure: GetMaxID static
	Parameters
	String: name_Tbl ! Это некий параметр, - название таблицы 
		- не используется в ЭТОЙ версии...
	Receive String: strSequense ! а вот тут мы получим 
		ГОТОВЫЙ новый секвенс...
	Local variables
	Sql Handle: hSqlUp
	Number: nOk
	Number: FchOk
	Number: IDBase
	Number: codeCurrent ! код текущего символа
	String: chCurrent ! текущий символ
	String: chNext ! текущий символ, с прибавленной еденицей (символ
		следующий в таблице символов за текущим)
	Number: IsGetNext ! если ожидаем увеличение разрядности.
	Number: Lang
	Number: nRow
	String: lRowid
	String: strIDBase
Actions
	Call SqlConnect ( hSqlUp )
	Set strSequense = ''
	Set nRow = 0
	Set Lang = 100
	When SqlError
	Set nOk = SqlError (hSqlUp) !на всякий случай, надо и на 
		ошибки проверять...
	Return FALSE

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

	Call SqlRetrieve(hSqlUp, 'sysadm.GetMaxIDCO', '', ':codeCurrent, 
		:chCurrent, :chNext, :Lang, :lRowid, :strIDBase ' )
	Call SqlExecute(hSqlUp)
	While nRow < Lang
		Call SqlFetchRow(hSqlUp,nRow, nOk)
		! выбрав очередной символ из
		последовательности проверяю 
		If ( nRow = 0 ) OR ( IsGetNext = 1 )
			! Если ЭТО начало, то, я могу "вместо
			здрасти" просто начать со "следующего" за
			текущим символа... или же, у нас "переход
			разряда".... 
	
	    	Set strSequense = chNext || strSequense
			If ( codeCurrent = 255 )
				Set IsGetNext = 1
			Else
				Set IsGetNext = 0
		Else
		! в противном случае, просто добавляем текущий
		символ....
		Set strSequense = chCurrent || strSequense
		Set IsGetNext = 0
		If ( IsGetNext = 1 ) AND ( nRow = Lang-1 )
		! а вот если у нас "переход разряда" дошел
		до конца строки, то пора увеличить размер
		строки... (добавить разряд)
		Set strSequense = ' ' || strSequense
		Set nRow = nRow +1
Call SqlRetrieve(hSqlUp, 'sysadm.SetMaxIDCO', ' :strSequense, :lRowid', '' ) Call SqlExecute(hSqlUp) Set strSequense = strIDBase || strSequense Call SqlDisconnect ( hSqlUp ) /

Почему такой вызов процедуры (с параметром - именем таблицы)? - я заменил предыдущую версию, где имя текущей таблички было оправдано, сейчас же осталась просто совместимость с предыдущими версиями.

Вот и основная команда:

SYSADM.GETMAXIDCO select
@code(@MID(a.SENSE, b.ID-1, 1)), @MID(a.SENSE, b.ID-1, 1),
@if(
@mod(@code(@MID(a.SENSE, b.ID-1, 1)), 255),
@char(@code(@MID(a.SENSE, b.ID-1, 1))+1), @char (32)),
@LENGTH ( a.SENSE), a.rowid, c.SENSE
from CONSTCHAR a, NUR b, CONSTCHAR c
where a.ID = ' z'
and b.ID <= @length ( a.SENSE)
and c.ID = ' 9'

Теперь и опишем, что мы получаем и с помощью чего:

  1. Текущее значение "секвенса" хранится в табличке CONSTCHAR, в строке с a.ID = 'z';
  2. Идентификатор текущей базы данных в системе - там же, в строке c.ID = '9'.
  3. Нам нужно ровно столько строк в выходной таблице, какова длина "секвенс последовательности". Вот это мы выполняем сравнивая b.ID <= @length(a.body).
  4. Мы отдаем пользователю коды каждого символа, коды, на единицу большие, чем текущие, и собственно, текущие и следующие "Char".

По полученным значениям в процедуре "собираем" следующее значение "секвенса".

Его уже просто записываем в базу, на "старое" место.

SYSADM.SETMAXIDCO update CONSTCHAR set
SENSE = :1
where
rowid = :2

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

Далее, насколько я понимаю, особенностью работы SQLBase есть возможность использовать не только хранимые процедуры, но и хранимые команды. Пользуемся мы ими очень широко...

Естественно для работы с ними понадобилось написать маленький администратор и пользоваться следующей таблицей:

CREATE TABLE SYSADM.PRCLIST (
	NAME VARCHAR(30) NOT NULL,
	IDTABLES VARCHAR(18),
	STRWHERE LONG VARCHAR
	STRINTO LONG VARCHAR,
	TEXT LONG VARCHAR,
	ISDELLDOCS VARCHAR(1)
)
/

NAME - Имя команды.

IDTABLES - Идентификатор таблицы из списка таблиц

STRWHERE - Строка описание списка задающих параметров

STRINTO - Строка описания получаемых параметров

TEXT - Текст команды

ISDELLDOCS - идентификатор удаляемости, применяется для команд удаления данных в пользовательских документах, - нужны при больших удалениях - типа, удаления пользователя (со всеми его документами).

Ограничения:

ALTER TABLE SYSADM.PRCLIST FOREIGN KEY PRCLst220805 (
IDTABLES) REFERENCES SYSADM.LPATTABLES
/

Естественно, нам нужно отслеживать "взаимосвязь" со списком табличек...(наших)

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

CREATE TABLE SYSADM.LISTDOCSIZE (
	ID_USER VARCHAR(18),
	NAMEFORM VARCHAR(38),
	NLEFTWIDTH DOUBLE PRECISION,
	NLEFTHEIGTH DOUBLE PRECISION,
	NSIZEWIDTH DOUBLE PRECISION,
	NSIZEHEIGTH DOUBLE PRECISION
)
/

ID_USER - Идентификатор пользователя из таблицы со списоком пользователей

NAMEFORM - Имя окна, важно, чтобы все окошки в системе имели уникальные названия окон

NLEFTWIDTH, NLEFTHEIGTH - Положение левого верхнего угла

NSIZEWIDTH, NSIZEHEIGTH - Размер по горизонтали и вертикали

Естественно, при окончании работы (закрытии окон) данные записываются, а при старте приложения считываются, и, естественно, окошки принимают необходимые размеры.

Ну вот... осталась только "добавочка" - набор всего описанного в одном SQL файле, который Вы можете взять из проекта.


Загрузить проект | Предыдущий Шаг | Следующий Шаг | Оглавление
Автор Голиброда Александр - 22.08.2002