Studopediya

КАТЕГОРИЯ:


Астрономия- (809) Биология- (7483) Биотехнологии- (1457) Военное дело- (14632) Высокие технологии- (1363) География- (913) Геология- (1438) Государство- (451) Демография- (1065) Дом- (47672) Журналистика и СМИ- (912) Изобретательство- (14524) Иностранные языки- (4268) Информатика- (17799) Искусство- (1338) История- (13644) Компьютеры- (11121) Косметика- (55) Кулинария- (373) Культура- (8427) Лингвистика- (374) Литература- (1642) Маркетинг- (23702) Математика- (16968) Машиностроение- (1700) Медицина- (12668) Менеджмент- (24684) Механика- (15423) Науковедение- (506) Образование- (11852) Охрана труда- (3308) Педагогика- (5571) Полиграфия- (1312) Политика- (7869) Право- (5454) Приборостроение- (1369) Программирование- (2801) Производство- (97182) Промышленность- (8706) Психология- (18388) Религия- (3217) Связь- (10668) Сельское хозяйство- (299) Социология- (6455) Спорт- (42831) Строительство- (4793) Торговля- (5050) Транспорт- (2929) Туризм- (1568) Физика- (3942) Философия- (17015) Финансы- (26596) Химия- (22929) Экология- (12095) Экономика- (9961) Электроника- (8441) Электротехника- (4623) Энергетика- (12629) Юриспруденция- (1492) Ядерная техника- (1748) Arhitektura- (3434) Astronomiya- (809) Biologiya- (7483) Biotehnologii- (1457) Военни бизнесмен (14632) Висока technologies- (1363) Geografiya- (913) Geologiya- (1438) на държавата (451) Demografiya- ( 1065) Къща- (47672) журналистика и смирен (912) Izobretatelstvo- (14524) външен >(4268) Informatika- (17799) Iskusstvo- (1338) историята е (13644) Компютри- (11,121) Kosmetika- (55) Kulinariya- (373) културата е (8427) Lingvistika- (374) Literatura- (1642) маркетинг-(23702) математиците на (16968) Механична инженерно (1700) медицина-(12668) Management- (24684) Mehanika- (15423) Naukovedenie- (506) образователна (11852) truda- сигурност (3308) Pedagogika- (5571) Poligrafiya- (1312) Politika- (7869) Лево- (5454) Priborostroenie- (1369) Programmirovanie- (2801) производствено (97 182 ) индустрия- (8706) Psihologiya- (18388) Religiya- (3217) Svyaz (10668) Agriculture- (299) Sotsiologiya- (6455) на (42831) спортист строително (4793) Torgovlya- (5050) транспорт ( 2929) Turizm- (1568) физик (3942) Filosofiya- (17015) Finansy- (26596) химия (22929) Ekologiya- (12095) Ekonomika- (9961) Electronics- (8441) Elektrotehnika- (4623) Мощност инженерно ( 12629) Yurisprudentsiya- (1492) ядрена technics- (1748)

Динамичен SQL

Концепцията на свързване. От всички SQL-отчети в PL / SQL програми могат да бъдат използвани директно само изявления оператори DML и контрол на операциите. не могат да бъдат използвани DDL изявления. За да се изясни значението на тези ограничения, да приемат принципа за създаване на PL / SQL програми.

Във всеки език за програмиране задължителни променливи могат да бъдат или началото или края. Свързване (свързване) променлива - процес на инструкции памет, съответстващи на идентификатора на програмата. В PL / SQL в процеса на свързване също включва проверка на базата данни за всеки офис, позволявайки схеми обекти за достъп. Този език, който се използва за ранно свързване (началото на свързване), този процес се извършва при съставяне на програмата, и на език, който се използва късно свързване (в края на свързване), се отлага до момента на изпълнение на програмата. Рано свързване означава, че фазата на съставяне на програмата ще отнеме по-дълго време (това е необходимо да се свързва променливи), но програмата ще се извършва по-бързо, защото в този момент свързването е завършено. По този начин, късно свързване намалява съставят време, но това увеличава времето тече на програмата.

При разработването на PL / SQL беше решено да се използва за ранно свързване на обекти на базата данни по време на изпълнение на блока вече са били тествани, и че блокът може да се направи възможно най-бързо. Това е оправдано, тъй като / SQL блокове PL могат да се съхраняват в базата данни като процедури, функции, модули и тригери. Тези обекти се съхраняват в компилирана форма, което означава, че може да бъде изтеглен от базата данни и да изпълнява, както се изисква.

В допълнение, DDL изявления модифицират обекти на база данни, поради това, органът по този въпрос трябва да се потвърдиха, а процесът на потвърждаване орган също изисква задължителни идентификатори.

Помислете блока:

декларирам

v_SQLString varchar2 (100);

2 v_SetClause VARCHAR (100);

v_WhereClause varchar2 (100);

започвам

v_SetClause: = "SET заплата =: заплата, КЪДЕТО";

v_WhereClause: "позиция =: v_position" =;

v_SQLString: = "UPDATE персонал" || v_SetClause || v_WhereClause

Дребна монета (v_SQLString);

приключи;

Това устройство не може да се стартира, за да изпълнява веднага след като е бил написан, защото необходимостта от създаване на предварително дребна монета () рутина.

Имайте предвид, че чрез създаването на подходяща функция дребна монета () винаги е възможно да се изпълни произволен SQL-декларация, като посочва набор от поднизове на това ръководство, и след това се извършва тяхното конкатенация (||).

Въпреки функция дребна монета () в такъв случай трябва да извърши:

1. утвърждаване задача SQL-декларацията, т.е. изпълнява граматика анализ инструкция низ за идентифициране на синтактични и семантични грешки;



2. задължителни параметри на SQL-инструкции;

3. проверява правилното изпълнение на указанията, дадени ORACLE сървър.

По този начин, за да се реализира функцията на всякакви инструкции за обработка на SQL-практически много трудно, защото на произвола на броя и вида на свързване на параметрите на различни инструкции. Въпреки това, за да се създаде функция като дребна монета (), която ще трябва да следвате инструкциите, с фиксирана сума от определен тип параметри по принцип е възможно.

За да се реализират такива функции могат да бъдат динамично SQL. За динамичен поставените по-малко ограничения: много от това, което трябва да знаете по време на компилация, че не е необходимо да се опишат етапите на програмата. Пълното описание на SQL-декларация може да се дава по време на неговото изпълнение.

Така че, ако структурата на SQL-оператор е известно по време на компилация, програмите са статични. Ако задължителни параметри и определянето на правата за достъп трябва да бъдат определени "в движение", а след това ние говорим за SQL динамично, което дава възможност за използване на SQL-изявления в PL / SQL.

Има два начина за използване на динамичен SQL:

1. Стандартен пакет PL / SQL - DBMS_SQL.

2. Вграден динамичен SQL, което се появява в ORACLE 8 аз. При използване на динамични отчети за контрол са вградени директно в езика PL / SQL и така е много по-бързо, отколкото в пакета за DBMS_SQL.

Пакетът DBMS_SQL се използва, когато при съставяне на курсора неизвестна структура, броя и вида на променливите автомати. Тя ви позволява да намерите структурата на курсора в реално време, но е доста сложен синтаксис.

Вграден динамичен SQL (Native Dynamic SQL - NDS) се основава на използването на оператора да изпълни незабавно и курсор цикъл OPEN ... ЗА, които са прости и кратък синтаксис, но от броя и вида на променливи за обвързване трябва да бъдат известни по време на компилация, тъй като структурата на курсора.

Пакетът DBMS_SQL. Обща алгоритъм изпълнение на SQL-оператори, използвайки DBMS_SQL включва следните стъпки:

1. Превръщането на SQL-оператор в низ - разбор;

2. символни низове синтактичния анализ, използвайки DBMS_SQL.PARSE;

3. Свързването на входните променливи, използващи DBMS_SQL.BIND_VARIABLE;

4. Ако изпълним израз е изявление ГСД (UPDATE, DELETE, INSERT) или DDL, след това да го извърши с помощта DBMS_SQL.EXECUTE последвано от четене изход за свързване на променливите величини, които използват DBMS_SQL.VARIABLE_VALUE (ако е необходимо);

5. Ако операторът осигурява извличане на данни (SELECT), първото описание на изходните променливи, използващи DBMS_SQL.DEFINE_COLUMN;

6. След извършване на избрана заявка използвате DBMS_SQL.EXECUTE и примерни резултати, използвайки DBMS_SQL.FETCH_ROWS и DBMS_SQL.COLUMN_VALUE.

Пример. Процедурата, която първо изважда, а след това повторно създаване на временната таблица; описание на таблицата се предава като аргумент на процедурата.

създадете или замени процедура RecreateTempTable

/ * Описание на таблицата се предава на процедурата, използвайки r_Description трябва да бъде съдържанието на CREATE TABLE отчета, който се намира след името на таблицата. Например: RecreateTempTable ( '(num_col НОМЕР, char_col VARCHAR2 ( 2000)) ") * /

(R_Description в varchar2) е

v_Cursor номер;

v_CreateString varchar2 (100);

V_ DropString varchar2 (100);

започвам

--otkryvaem курсора за обработка на данни;

v_Cursor: = DBMS_SOL.OPEN_CURSOR;

--udalyaem маса;

v_DropString: = "DROP TABLE температура маса";

/ * Извършване на синтактична команда "DROP TABLE" и го изпълни. Тези операции се извършват с помощта на DBMS_SQL.PARSE. Ако таблицата не съществува, определен ORA-942 грешка. * /

започвам

СУБД SQL.PARSE (v_Cursor, v_DropString, DBMS_SQL.NATIVE);

изключение

когато другите след това

ако SQLCODE! = -942 след това

ПОВИШАВАНЕ;

крайна сметка, ако;

приключи;

/ * На следващо място, създаване на таблица. Първо, трябва да се инициализира линията Създаване на таблица герои, а след това прекара разбор и изпълни DDL-оператор DBMS_SQL.PARSE повикване * /

V CreateString: = "Създаване на таблица температура маса" || r_Description;

DBMS_SQL.PARSE (v_Cursor, V _ CreateString, DBMS_SQL.NATIVE);

--zakryvaem курсора;

DBMS_SQL.SLOSE_CURSOR (V_ Cursor);

изключение

когато другите след това

/ * Първо затвори курсора, и след това да инсталирате грешката да го предаде на разговори блок * В /

DBMS_SQL.CLOSE_CURSOR (V _ Cursor);

повишаване;

в крайна RecreateTempTable;

В горния пример, анализът трябва да се обърне внимание на следното:

- Низ от символи разбор се извършва, която може да бъде постоянна (тук v_DropString), и програмата може да бъде създаден динамично с помощта на функцията характер, например чрез конкатенация функция (тук v_CreateString);

- Обработка Грешка е същият, както в статичен SQL, грешки са установени и обработени чрез изключения. Разликата е, че сега по време на звеното за изпълнение може да се върне и да компилация грешки;

- Потребителят е снабден с голяма възможност за курсора, по-специално, определянето моменти на тяхното отваряне и затваряне. Всички отворени курсори трябва да бъдат затворени, дори и със създаването на извънредна ситуация. В този случай, затваряне на курсора се предоставя DBMS_SQL.CLOSE_CURSOR повикване по изключение манипулатор.

Фигурата показва блок-схема на използване DBMS_SQL пакет.

Фигура блок схема на алгоритъм за обработка на данни DBMS_SQL

YES в блок изявление DDL

С DBMS_SQL може да се справи три вида оператори: SQL отчети (ГСД, DDL и ALTER сесия), заявки и PL / SQL анонимни блокове. Всеки тип се обработват с помощта на различни процедури, които са описани по-долу:

- OPEN_CURSOR. Както и в статичен SQL и динамичен PL / SQL всеки SQL-декларация се изпълнява в границите на курсора. Освен това, в динамичен PL / SQL курсора може да се контролира процеса на обработка. OPEN_CURSOR курсора връща идентификационния номер, използван да се отнася до областта на съдържание, в която ще бъде изпълнена оператора. Този номер ще бъде показан във всички следващи разговори на курсора.

- Разбор. Разбор на оператора е да го изпраща на сървъра, където синтаксиса и семантиката на оператора проверени. Ако това е искане, след което на този етап се определя от плана за изпълнение. Ако DDL оператор, тя се извършва също.

- BIND_VARIABLE. Свързването с променлива задължителен процес на контейнера е подобен на този, използван в PL / SQL статични SQL-оператори. В контейнера (контейнер) - е специален идентификатор в последователността оператор на героите. В процеса на свързване на кореспонденция между пълнежа и действителната променлива и пакета DBMS_SQL на доклади относно вида и размера на променливата. Свързването се осъществява в продължение на входните променливи са SQL извлечения и да входните и изходните променливи в PL / SQL изявления. Използваните променливи по този начин се наричат променливи автомати.

- DEFINE_COLUMN. Описание на изберете елемент от списъка е подобен на входната променлива задължителен. В този случай, променливите са резултатите от запитването. процедура DEFINE_COLUMN определя вида и размера на променливото PL / SQL, в които данните ще бъдат записани при четене процедура информация FETCH_ROWS на. DEFINE_COLUMN използва само, за да изберете списъка с елементи (резултатите от SELECT заявки), и BIND_VARIABLE - за входящи или изходящи променливи (Запазено място, посочени в операторите).

- Изпълни. Извършва се от оператори, които не са заявки (Изберете), и се връща броя на редовете, обработвани. За да направите заявка Изпълнение определя активния набор (набор редове, които отговарят КЪДЕ заявката за клауза). След това данните се четат FETCH_ROWS процедура. За всички оператори се свързват променливи анализирани по време Изпълнението на функцията.

- FETCH_ROWS. С всяко извикване на процедура за увеличаване на размера на данните се четат от FETCH_ROWS сървъра. След това, получената информация се превръща в типове данни, посочена процедура DEFINE_COLUMN. процедура EXECUTE_AND_FETCH ви позволява да комбинирате операцията по обработка и четене на данни в един разговор.

- COLUMN_VALUE. Връща FETCH_ROWS фактическа информация след обаждането. Той използва променливата от тип определения ред DEFINE_COLUMN. Тя трябва да се използва само за запитвания.

- CLOSE_CURSOR. След обработката на данните на курсора е затворен. На същите ресурси, използвани от курсора са освободени.

ОБРАБОТКА DML изявления в DBMS_SQL. За обработката на актуализиране, изтриване, INSERT DBMS_SQL пакет означава, че вие ​​трябва да изпълните следните стъпки:

1. Отворете курсора. Изпълнено чрез обаждане OPEN_CURSOR процедура на описанието в модула, както следва:

OPEN_CURSOR връщане число;

Параметрите по тази процедура не са налични.

Всяка покана връща цяло число, което представлява курсора ID. Този номер се използва в следващи разговори курсора. В границите на курсора, можете да се редуват, за да се справят с множество SQL извлечения или изпълни същото изявление няколко пъти.

2. Стартирайте граматичен анализ на оператора. Когато разбор на оператора се изпраща към сървъра на базата данни. Сървърът проверява нейната синтаксис и семантика, и се връща грешка (създаване на изключение), ако е нарушил изискванията на граматиката. В допълнение, по време на разбор на изложението се определя от плана. Изпълнено като се обадите на процедура синтактична DBMS_SQL.PARSE описано в пакета е както следва:

процедура разбор (в в цяло число, изявление в varchar2, >

Тук с - номер за идентификация на курсора, трябва преди това да е открита от OPEN_CURSOR, изложение - изявление, разбор, която се извършва, >

3. Направете входните променливи. В режим на работа, посочени в него агрегати се свързват с реалните променливи. Имена на агрегати обикновено предшестват двоеточие. BIND_VARIABLE процедура свързва и класифицирани имена агрегати. Размерът и видът на действителните данни сделка също е настроен BIND_VARIABLE преодоляно чрез набиране на повикването:

процедура BIND_VARIABLE (в в число, име на varchar2, стойност в брой),

процедура BIND_VARIABLE (в в число, име на varchar2, стойност в varchar2),

процедура BIND_VARIABLE (в в цяло число, име в varchar2, стойност в varchar2, out_value_size в цяло число).

когато наименованието - е името на контейнер, който ще бъде свързан с променлива, стойност - актуалните данни, за да бъдат приложени, вида и размера на променливата като чете. Ако е необходимо, данните, съдържащи се в променливата да бъдат преобразувани. Параметър out_value_size - параметър е определено, когато се свързват променливи varchar2 и Чар; ако е посочено, че е максималната стойност на очаквания размер в байтове, ако не е посочено, размера, посочен в стойността на параметъра.

4. Изпълнение на оператора. Приложена чрез функцията изпълни. Описание това в модула, както следва:

функция EXECUTE (C в цяло число) връщане число;

където C - идентификатора рано отворен курсора.

Изпълнението на функцията връща броя на работните линии (в този смисъл, върнатата стойност е подобна на курсора атрибут% ROWCOUNT на). Имайте предвид, че стойността на връщане не е определено за проба от операторите, както и тази на изразите наречени EXECUTE програми.

5. Закриване на курсора. Затварянето на курсора се извършва, като се обадите процедура CLOSE_CURSOR описано, както следва:

процедура CLOSE_CURSOR (в по навън число) .

предава стойността на процеса трябва да бъде валиден курсора ID. След разговора с действителното параметър е настроен на NULL, което показва, курсора се затваря.

Ето един пример:

създадете или замени процедура update_address (p_lname в staff.lname% тип, p_fname в staff.fname% тип, p_newaddress в staff.address% тип, p_rowsupdated от цяло число)

е

v_cursor_id число;

v_updatestmt varchar2 (100);

започвам

v_cursor_id: = DBMS_SQL.OPEN_CURSOR;

v_updatestmt: = "актуализация на персонала

определен адрес = сферата на:

където fname =: fname и lname = : lname ";

DBMS_SQL.PARSE (V _ курсора _ ID, V _ updatestmt, DBMS_SQL.NATIVE);

DBMS_SQL.BIND_VARIABLE (v_cursor_id ,: Na, стр _ newaddress);

DBMS_SQL.BIND_VARIABLE (v_cursor_id ,: fname, стр _ fname);

DBMS_SQL.BIND_VARIABLE (V _ курсора _id ,: lname, стр _ lname);

р _ rowsupdated: = DBMS_SQL.EXECUTE (v_cursor_id );

DBMS_SQL.CLOSE_CURSOR (v_cursor_id);

изключение

когато другите след това

DBMS_SQL.CLOSE_CURSOR (v_cursor_id);

повишаване;

в крайна update_address;

Обработка на молби за извличане на информация се извършва в следната последователност:

1. Отворете курсора (OPEN_CURSOR),

2. Run разбор (разбор),

3. Стартирайте свързването на входните променливи (BIND_VARIABLE),

4. Опишете елементите на списъка за избор (DEFINE_COLUMN),

5. Run Query (стартирани),

6. Продължение на линията (FETCH_ROWS),

7. Запис на резултатите в променливите (COLUMN_VALUE),

8. Затворете курсора (CLOSE_CURSOR).

За динамична заявка трябва да използвате една и съща процедури DBMS_SQL пакета, и че при изпълнение на DML отчети, с изключение DEFINE_COLUMN, FETCH_ROWS и COLUMN_VALUE. Помислете за тези процедури синтаксис:

DEFINE_COLUMN списък избор определя елементите, подобни на свързване на входните променливи, с изключение, че списък селекция елементи трябва да се спазват, но само определени. В DEFINE_COLUMN ред, определен тип и размер на променливите, които се четат от елементите на списъка за избор. Всеки елемент в този случай се превръща в съответния тип променлива.

процедура DEFINE_COLUMN (в в цяло число, позиция в цяло число, колона в брой),

процедура DEFINE_COLUMN (в в цяло число, позиция в цяло число, колона в varchar2, колона _ размер в цяло число).

За VARCHAR2 видове променливи трябва да бъдат уточнени параметрите колона _ размер, защото PL система / SQL подкрепа трябва да знае максималният размер на тези променливи по време на изпълнение, за разлика от номер, дата на данните от тези видове не са с фиксирана дължина, известни предварително на компилатора. Вид и цел процедура DEFINE_COLUMN параметри са дадени в таблицата.

Таблица Settings DEFINE_COLUMN

параметър тип дестинация
с цяло число курсора ID.
позиция цяло число Позицията на списъка за избор т.
колона номер, varchar2 Променливата, която определя вида и размера на изходната променлива. Името на променливата не играе роля, но от вида и размера са важни. Въпреки това, в DEFINE_COLUMN, и обикновено се използват в същите COLUMN_VALUE променливи.
column_size цяло число Максималната очаквания размер на данните. Задължително за тези видове, които не са предварително известни дължината на PL / система за подпомагане SQL.

FETCH_ROWS искане чете набор от редове в буфер. процедура Синтаксис:

функционални FETCH_ROWS (в в цяло число) върнете число;

FETCH_ROWS връща броя на редовете, за да се чете. FETCH_ROWS и COLUMN_VALUE предизвика в цикъл няколко пъти, докато, докато FETCH_ROWS не се връщат NULL.

COLUMN_VALUE използва за записване на резултатите в променливи PL / SQL. Тази процедура се нарича след успешна FETCH_ROWS. Ако пробата не е бил върнат COLUMN_VALUE линия определя изходната променлива нулевата стойност. По-долу е описание на процедурата, в пакета за DBMS_SQL:

процедура COLUMN_VALUE (в в цяло число, позиция в цяло число, стойността на брой);

процедура COLUMN_VALUE (в в цяло число, позиция в цяло число, стойността на брой, колона _ грешка на брой, действителната _ дължина на брой);

процедура COLUMN_VALUE (в в цяло число, позиция в цяло число, стойността на varchar2);

процедура COLUMN_VALUE (в в цяло число, позиция в цяло число, стойността на varchar2, _ грешка на номер колона, действителният брой _ дължина вън).

Вид и цел процедура COLUMN_VALUE параметри са дадени в таблицата.

Таблица Settings процедура COLUMN_VALUE

параметър тип дестинация
с цяло число курсора ID.
позиция цяло число Относителната позиция в списъка за избор, както в DEFINE_COLUMN, позицията на първия елемент от списъка = 1.
стойност номер, varchar2 Променливата за изход, ако типът на този параметър е различен от вида, посочен в DEFINE_COLUMN възникне грешка, която съответства на извънредна ситуация DBMS_SQL.INCONSISTENT_TYPES.
column_error номер Колоната код за грешка се дава с отрицателна стойност. Грешка ще създаде изключение и колона _ грешка, за да се определи коя от колоните е причината за конкретна грешка. Ако колоната е била успешно чете, колоната _ грешка = 0.
ACTUAL_LENGTH номер Ако е посочено, това променлива ще бъде източник на колоната е размера (размер на колоната, преди да се чете). Това е полезно, когато размерът на променливата не е достатъчно и пресечен (това също води до грешка).

Пример. За да се създаде процедура, която определя имената на офицерите, дадени за служителя по процедура:

създадете или замени процедура DynamicQuery (р _ позиция в staff.position% тип) е

V _ курсора _ ID число;

v_select_stmt varchar2 (500);

v_first_name staff.fname тип%;

v_last_name staff.lname тип%;

v_dummy число;

започвам

v_cursor_id: = DBMS_SQL.OPEN_CURSOR;

v_select_stmt: изберете lname = ', fname

от персонала

където позиция =: поз

поръчка от lname ";

DBMS_SQL.PARSE (V _ курсора _ ID, V _ изберете _ stmt, DBMS_SQL.NATIVE);

DBMS_SQL.BIND_VARIABLE (v_cursor_id ": поз" , стр _ позиция);

DBMS_SQL.DEFINE_COLUMN (v_cursor_id, 1, v_last _ име, 25);

DBMS_SQL.DEFINE_COLUMN (v_cursor_id, 2, v_first_name, 25);

v_dummy: = DBMS_SQL.EXECUTE (v_cursor_id);

контур

ако DBMS_SQL.FETCH_ROWS (v_cursor_id) = 0, тогава

изход;

край ако;

DBMS_SQL.COLUMN_VALUE (v_cursor_id, 1, v_last_name);

DBMS_SQL.COLUMN_VALUE (v_cursor_id, 2, v_first_name);

вмъкнете в temp_table (name_col)

ценности (V_last_name || '' || v_first_name) ;

край контур;

DBMS_SQL.CLOSE_CURSOR (V _ курсора _ ID) ;

ангажират;

изключение

когато другите след това

DBMS_SQL.CLOSE_CURSOR (V _ курсора _ ID) ;

повишаване;

в крайна DynamicQuery;

<== Предишна лекция | На следващата лекция ==>
| Динамичен SQL

; Дата: 04.01.2014; ; Прегледи: 295; Нарушаването на авторските права? ;


Ние ценим Вашето мнение! Беше ли полезна публикуван материал? Да | не



ТЪРСЕНЕ:


Вижте също:



zdes-stroika.ru - Studopediya (2013 - 2017) на година. Тя не е автор на материали, и дава на студентите с безплатно образование и използва! Най-новото допълнение , Al IP: 66.102.9.26
Page генерирана за 0.07 секунди.