ДРУГЕ серйозна помилка ОМАНУ ОБ’ЄКТОВОГО ПІДХОДУ

У цьому розділі розглядається другий серйозна помилка як буде видно з подальшого викладу, це друге оману є логічним наслідком з першого, але воно також є значущим саме по собі Насправді, навіть якщо вдається уникнути першого серйозного омани, то можна стати жертвою другого, окремо взятого І наслідки цього омани фактично виявляються майже в усіх обєктно-реляційних програмних продуктах, наявних на ринку, а також у стандарті SQL (див розділ 266) Це помилка полягає в тому, що змішуються покажчики і відносини

Почнемо з повторного розгляду основних особливостей підходу, заснованого на рівнянні змінна відносини = клас обєкту, який описаний в попередньому розділі Не можна заперечувати, що деякі читачі могли порахувати цей розділ трохи заплутаним, оскільки на перший погляд у ньому наведено заперечення проти тих

коштів, на користь яких автор висловлювався в інших розділах цієї книги (такими можна назвати атрибути зі значеннями у вигляді кортежу або у вигляді відношення) Тому автор повинен розяснити свою позицію, як описано нижче

■&nbsp Атрибути зі значеннями у вигляді кортежу або у вигляді відношення Безумовно, автор не заперечує проти таких атрибутів (і на яких підставах він став би проти них заперечувати) Насправді, він заперечує, по-перше, проти тієї ідеї, що такі атрибути повинні мати саме ті значення, які в даний час присутні в деякій іншій (базової) змінної відносини, і, по-друге, проти ідеї, щоб такі атрибути по суті мали значення, які є НЕ кортежами або відносинами як такими, а скоріше покажчиками на кортежі або відносини (а це означає, що насправді мова взагалі не йде про атрибути зі значеннями у вигляді кортежів або у вигляді відносин)  Примітка Насправді ідея використання покажчиків, які посилаються на кортежі або відносини(А під цим маються на увазі саме значення кортежів або відносин) взагалі не має сенсу ця тема обговорюється більш докладно трохи пізніше

■&nbsp&nbsp&nbsp Звязування операторів (методів) з перемінними відносини Автор не заперечує також і проти цієї ідеї вона практично просто визначає поняття тригерів (або збережених процедур) в іншому формулюванні Але автор фактично заперечує проти ідеї, що такі оператори повинні бути повязані з змінними отноше ня (і тільки змінними відносини), але не з доменами або типами Він також заперечує проти ідеї, що вони повинні бути повязані лише з однією певною змінної відносини (оскільки тим самим вводиться поняття цільових факти чеських параметрів, але в іншому формулюванні)

■&nbsp&nbsp&nbsp Підкласи і суперкласу Проти цього автор, безумовно, заперечує У тій систе ме, в якій проводиться знак рівності між змінними відносини і клас самі, підкласи і суперкласу стають підтаблицях і супертабліцамі, а до цих поняттям автор ставиться надзвичайно скептично (див [1413], а також розділ 266) Безумовно, має забезпечуватися правильне спадкування типів, як описано в главі 20

Позначення шляху Автор не заперечує проти таких позначень шляху, які є просто синтаксичними скороченнями для операцій проходження за деякими асоціативним посиланнях, наприклад, від зовнішнього ключа до відповідного потенційному ключу, як було запропоновано в [2615] Але позначення шляху, які розглядалися в розділі 262, скоріше, являють собою скорочення для операцій проходження по деяких ланцюжках покажчиків, і автор проти цього заперечує (оскільки він насамперед заперечує проти застосування покажчиків на рівні моделі)

■&nbsp&nbsp&nbsp Літерали кортежів і відносин Ці кошти є важливими, але їх не обхідно узагальнити до рівня селекторів кортежів і відносин [33]

■&nbsp&nbsp&nbsp Реляційні оператори порівняння Ці кошти також важливі (хоча повинні бути реалізовані правильно)

■&nbsp&nbsp&nbsp Оператори для проходження по ієрархії класів Якщо під ієрархією класів в дей ствительности мається на увазі ієрархія змінних відносини, то (як зазначено в попередньому розділі) автор має серйозні заперечення, оскільки виникає ймовірність порушення реляційного властивості замкненості (див наприклад [2641]) Якби поняття ієрархія класів означало ієрархію типів в тому сенсі, який вказаний у главі 20, то автор не мав би заперечень (але, на жаль, справа йде інакше)

■&nbsp&nbsp&nbsp Виклик методів, наприклад, в конструкціях SELECT і WHERE Ніяких заперечень

■&nbsp&nbsp&nbsp Доступ до окремих компонентів у значеннях атрибутів, які виявилися кор тежамі або відносинами Ніяких заперечень

Отже, тепер зосередимося на проблемі змішування покажчиків і відносин В основі доводів автора лежить дуже проста думка За визначенням, покажчики вказують на змінні, а не на значення (оскільки змінні мають адреси, а значення – ні) Тому, знову-таки за визначенням, якщо допускається, щоб змінна відносини R1 мала атрибут, значеннями якого є покажчики, спрямовані в змінну відносини R2, то ці покажчики вказують на змінні кортежів, а не на значення кортежів Але в реляційної моделі не визначено поняття змінної кортежу

Реляційна модель поширюється на значення відносин, які являють собою (висловлюючись неформально) множини значень кортежів, які, в свою чергу (знову висловлюючись неформально), є множинами скалярних значень Крім того, реляційна модель поширюється на змінні відносини, що представляють собою змінні, значеннями яких є відносини Але реляційна модель не поширюється на змінні кортежів (що представляють собою змінні, значеннями яких є кортежі) або на скалярні змінні (що представляють собою змінні, значеннями яких є скаляри) Єдиним видом змінної, включеної в реляційну модель (і єдиним видом змінної, дозволеної для використання в реляційної базі даних), є саме змінна відносини З цього випливає, що ідея змішування покажчиків і відносин представляє собою серйозне відхилення від реляційної моделі, оскільки вона вимагає введення змінної повністю нового виду (І тим самим фактично порушення інформаційного принципу) Як зазначено в попередньому розділі, в дійсності можна сміливо стверджувати, що при цьому відбувається також серйозне порушення концептуальної цілісності реляційної моделі

Оскільки неможливо заперечувати справедливість сказаного вище, дуже сумно спостерігати за тим, що в більшості (а можливо у всіх) сучасних зразках обектнореляціонних програмних продуктів (навіть в тих, в яких вдалося уникнути першого серйозного омани), проте, допускається змішування покажчиків і відносин саме в тій формі, яка була описана і проти якої були наведені заперечення в попередньому розділі Коли Кодд вперше визначив реляционную модель, він цілком свідомо виключив покажчики Нижче наведена цитата з [62]

Цілком припустимо прийняти припущення, що користувачі всіх категорій [включаючи, зокрема, кінцевих користувачів] розуміють суть операції порівняння значень, але лише щодо деякі розуміють всі складнощі, повязані із застосуванням покажчиків Реляційна модель заснована на фундаментальному принципі порівняння значень .. [А] операції маніпулювання з покажчиками більшою мірою можуть служити джерелом помилок, ніж операції порівняння значень, навіть якщо користувач враховує всі нюанси роботи з покажчиками

А саме, застосування покажчиків призводить до того, що з одного покажчика народжуються ланцюжка покажчиків, а використання ланцюжків покажчиків є, за загальним визнанням, джерелом неминучих помилок Як зазначалося у главі 25, саме ця характеристика обєктних систем стала причиною виникаючих час від часу критичних зауважень, які зводяться до того, що подібні системи нагадують злегка оновлену модель CODASYL .

Численні аргументовані доводи на підтримку викладеної вище позиції автора можна знайти в [2519] і [2615] Див також [2612]—[2614] і [2617], де розглядається повязане з цим і дуже важливе понятнесущественності (essentiality)

Несумісність покажчиків і якісної моделі успадкування

У даному розділі фактично наведено ще один обгрунтований аргумент проти підтримки покажчиків, про який Кодд, можливо, не знав, коли готував роботу [62] Проілюструємо цей довід на дуже простому прикладі (Даний приклад сформульований в термінах звичайних програмних змінних, а не відносин бази даних, щоб можна

було зосередитися на реальній проблемі, а не відволікатися на непотрібні подробиці) Ще раз розглянемо типи ELLIPSE і CIRCLE Припустимо, що PTR_TO_ELLIPSE І PTR_TO_CIRCLE – це відповідні типи вказівників іншими словами, припустимо, що значення типів PTR_TO_ELLIPSE І PTR_TO_CIRCLE (висловлюючись неформально) є, відповідно, покажчиками на еліпси і покажчиками на колі Нарешті, припустимо, що ELLIPSE – строгий супертіп типу CIRCLE і тому приймемо припущення, що PTR_TO_ELLIPSE – строгий супертіп типу PTR_TO_CIRCLE Тепер розглянемо наступний фрагмент коду

VAR E ELLIPSE

VAR XC PTR_TO_CIRCLE

Е: = CIRCLE (LENGTH (50), POINT (00, 00)) XC: = TREAT_DOWN_AS_PTR_TO_CIRCLE (PTR_TO (E)) THE_A (E): = LENGTH (60)

Пояснення

1 Два оголошення змінних говорять самі за себе

2 Після першого присвоювання (змінної Е) ця змінна містить окруж ність з радіусом пять5 Зверніть увагу на те, що в цьому операторі присвоюються вання використовується властивість заменяемости слід також відзначити, що тепер найбільш конкретним типом змінної Е є CIRCLE

3 Оператор PTR_TO, який присутній у виразі праворуч від другого операто ра присвоювання, являє собою те, що зазвичай називається оператором адре сації: якщо дана змінна V, він повертає адресу змінної V (тобто покажчик на цю змінну) Тому в розглянутому прикладі даний оператор віз обертає значення покажчика типу PTR_TO_ELLIPSE АЛЕ оскільки змінна, на яку вказує значення даного покажчика, має найбільш конкретний тип CIRCLE, то значення покажчика фактично має тип PTR_TO_CIRCLE, а не про сто тип PTR_TO_ELLIPSE Таким чином, операція приведення до підкласу TREAT DOWN завершується успішно і тому в другій операції привласнення в змінну хс поміщається покажчик на змінну Е (іншими словами, адресу цієї змінної)

4 Третя операція присвоювання значення (псевдопеременной ТНЕ_А (Е)) є найбільш важливою Що відбувається при її виконанні Швидше за все, тут можуть бути три можливості, які описані нижче, і всі вони не зовсім прийнятні

а) Виникає помилка на етапі прогону через невідповідність типів, оскільки присвоювання псевдопеременной ТНЕ_А не дозволені для змінних найбільш конкретного типу CIRCLE Іншими словами, не підтримується узагальнення за допомогою обмеження, тому не підтримується також уточнення за допомогою обмеження, а це означає, що модель успадкування неприйнятна

5 Як і в главі 20, в цьому розділі передбачається, що декартово можливе подання для точок називається POINT, а не CARTESIANПоэтомувданномпримеревторымфактическимпараметромселектора CIRCLEявляется виклик відповідного селектора POINT

(Безумовно, її не можна назвати достовірної моделлю реальності, як було описано в розділі 20) Так чи інакше, виникають на етапі прогону помилки через невідповідність типів завжди небажані

б) Операція присвоювання начебто завершується успішно, але узагальнення за допомогою обмеження не відбувається Результатом цього стає те, що змінна Е тепер містить некруглу окружність (Її найбільш конкурують вим типом все ще залишається CIRCLE, але ця окружність має півосі раз ної довжини) Тому, знову-таки, модель успадкування є неприйнятною (і не може розглядатися як достовірна модель реальності), оскільки узагальнення за допомогою обмеження і уточнення за допомогою обмеження не підтримуються Більш того, не тільки змінна Е тепер містить некруг лую окружність, але і змінна хс вказує також на некруглу окруж ність. Мало того, не можуть підтримуватися обмеження типу Адже якби вони підтримувалися, то не могли б виникнути некруглі колу. Іншими словами, можна сміливо стверджувати, що виключена можливість під держки обмеження цілісності найбільш фундаментального виду: визначаючи тип, ми не можемо вказати, які значення цього типу є допустимими

До речі, слід зазначити, що ця помилка допущена і в специфікації

SQL: 1999 Див главу 20 і розділ 266

в) Операція присвоювання завершується успішно і відбувається узагальнення з по потужністю обмеження це означає, що змінна Е тепер містить просто еліпс і її найбільш конкретним типом служить ELLIPSE Але й тоді модель успадкування є неприйнятною, оскільки змінна хс, оголошений ним типом якої служить PTR_TO_CIRCLE, тепер містить значення наи більш конкретного типу PTR_TO_ELLIPSE Ід цього знову випливає, що ограни чения типу не можуть підтримуватися

Примітка Навіть сама ідея про те, що змінної деякого оголошеного типу Т може бути дозволено містити значення найбільш конкретного типу деякого суворого супертіпа т, є логічною нісенітницею, тому більш імовірно, що або перша операція присвоювання завершиться невдачею, як в п а), або зовні завершиться успішно без узагальнення за допомогою обмеження, як в п б) Іншими словами, варіант, описаний в цьому пункті, можливо, взагалі є нездійсненним

З цього прикладу випливає, що якщо підтримуються покажчики, то модель успадкування обовязково стає неприйнятною іншими словами, покажчики і якісна модель успадкування несумісні Мабуть, ці міркування можуть служити ще одним незаперечним доказом на користь відмови від покажчиків

Аналіз причин виникнення другого серйозного омани

У літературі важко виявити причини, за якими виникло другий серйозна помилка (вірніше, відсутні будь теоретичні обгрунтування підтримки покажчиків, але є свідчення, що рішення про їх застосування було прийнято взагалі не з теоретичних міркувань, а скоріше на підставі адміністративного рішення) Враховуючи той факт, що всі обєктні системи і обєктні мови передбачають

використання покажчиків у формі ідентифікаторів обєктів, ідея змішування покажчиків і відносин майже напевно стала результатом прагнення зробити реляційні системи більш схожими на обєктні. Але таке обгрунтування просто переводить зазначену проблему на інший рівень автор вже навів вичерпні аргументи на користь сформованого у нього думки про те, що в обєктних системах користувачеві надається доступ до покажчиків саме тому, що в них не проводяться належним чином відмінності між моделлю і реалізацією

Тому автор може зробити єдино допустиме припущення, що причиною, по якій ідея змішування покажчиків і відносин отримала настільки широке поширення, є саме те, що лише деякі розуміють, чому з реляційної моделі були з самого початку виключені покажчики Джон Сантаяна (John Santayana) сформулював це так: Ті, хто не здатний памятати минуле, приречені його повторювати (Зазвичай цитується у формі: Для тих, хто не знає історії, вона повторюється) З цього приводу автор висловлює повну згоду з Морісом Уилксом (Maurice Wilkes), якому належить наведена нижче цитата [2646]

“Я хотів би, щоб навчання компютерним наукам спеціально проводилося в історичному контексті .. Студенти повинен розуміти, як склалася сучасна ситуація, які робилися спроби, що виявилося вдалим, а що – ні, і які удосконалення в апаратних засобах стали передумовою прогресу Відсутність у навчанні такої складової змушує людей підходити до вирішення будь-якої задачі виходячи з самих найпростіших уявлень Тому вони стають схильними пропонувати рішення, від яких вже давно відмовилися в минулому Замість того щоб встати на плечі своїх попередників, вони намагаються самостійно піднятися над горизонтом .

262 ПРОБЛЕМИ РЕАЛІЗАЦІЇ

Одним важливим наслідком забезпечення правильної підтримки типів даних є те, що вона дозволяє незалежним постачальникам (а також постачальникам самих СУБД) створювати і поставляти окремі пакети типів,які можуть ефективно вбудовуватися в СУБД Як приклади можна назвати пакети, що підтримують складні алгоритми обробки тексту, обробки фінансових часових рядів, аналізу геопросторових (Картографічних) даних і тд Такі пакети називаються по-різному:пластинами даних- data blade (Informix), картриджами даних- data cartridge  (Oracle), реляційними розширниками – relational extender6  (IBM),  прикладними пакетами – application package (це термін використовується в стандарті SQL / MM [2625]) і тд У даному розділі зупинимося на терміні пакети типів

Але введення нового пакету типів в систему – нетривіальне захід, і для надання такої можливості необхідно внести суттєві зміни до проекту і структуру самої СУБД Для того щоб всебічно розібратися в цьому питанні, розглянемо, що відбудеться, якщо, наприклад, деякий запит включає посилання на дані якогось визначається користувачем типу або виклики якогось визначається користувачем оператора (або те й інше)

6 Помнениюавтора,этоттерминявляетсяисключительнонеудачным

і По-перше, компілятор мови запитів повинен мати здатність проводити синтаксичний аналіз і перевірку типів у відповідному запиті, тому повинен мати певну інформацію про ці визначаються користувачем типах і операторах

■ По-друге, оптимізатор повинен мати здатність прийняти відповідний план обробки такого запиту, тому він повинен також мати відомості про конкретні властивості таких визначених користувачем типів і операторів Зокрема, він повинен мати відомості про те, як організовано фізичне зберігання даних (див наступний пункт)

■ По-третє, компонент, який управляє фізичною памяттю, повинен мати підтримку відповідних більш нових структур зберігання (квадрадеревьев, R-дерев і тд), які згадувалися при обговоренні завдання з прямокутників ками в розділі 261 Може навіть знадобитися, щоб цей компонент дозволяв користувачам, що володіє відповідними навичками, самостійно вво дить нові структури зберігання та методи доступу [2629], [2643]

Одним важливим наслідком з усього сказаного вище є те, що система обовязково повинна бути розширюваної, а фактично здатність до розширення повинна забезпечуватися на декількох рівнях Нижче коротко описано кожен з рівнів

Синтаксичний аналіз та перевірка типів

Оскільки в звичайній системі все єдино доступні типи та оператори є вбудованими, що відноситься до них інформацію можна жорстко закодувати в компіляторі (що зазвичай і робиться) На відміну від цього, в системі, в якій користувачі можуть визначати свої власні типи та оператори, такий підхід з жорстким кодуванням, безумовно, неприйнятний Таким чином, замість цього необхідно застосовувати рішення, подібні наведеним нижче

■ Інформація, що стосується визначених користувачем типів і операторів (і можливо також вбудованих типів і операторів) зберігається в системному каталозі З цього випливає, що сам каталог вимагає перепроектування (або, принаймні, розширення) із цього також випливає, що введення кожного нового пакета типів тягне за собою суттєве оновлення каталогу (В термінах мови Tutorial D таке оновлення непомітно для користувача здійснюється у складі процесу випелненія відповідних означальних пропозицій TYPE і OPERATOR)

■ Необхідно переробити сам компілятор для того, щоб він міг звертатися до каталогу для отримання необхідної інформації про типи і операторах Потім він може використовувати цю інформацію для проведення всієї тієї перевірки типів на етапі компіляції, яка була описана в розділах 5 і 20

Оптимізація

Вирішення цього завдання повязане з подоланням надзвичайно численних проблем, і в даній книзі ми можемо лише привести їх короткий опис Але, принаймні, необхідно зупинитися на деяких перелічених нижче питаннях

■&nbsp&nbsp&nbsp&nbsp Перетворення виразу (перезапис запиту) Як було показано в главі 18, для перезапису запиту у звичайному оптимізаторі застосовуються деякі закони перетворення Але за традицією такі закони перетворення завжди були жорстко закодовані в оптимізаторі (оскільки, знову-таки, всі доступні типи даних і оператори були вбудованими) На відміну від цього, в обектнореляціонной системі відповідні відомості (принаймні, та їх частина, яка відноситься саме до визначеним користувачем типам і операторам), повинні зберігатися в каталозі з цього випливає, що при розширенні каталогу не обходимо враховувати і цей факт, крім того, в наявності такий наслідок, що вимагає доопрацювання і сам оптимізатор Нижче наведені деякі ілюстрації до ска занному

а) Якщо дано такий вислів, як NOT (STATUS> 2 0), то якісний звичайний оптимізатор перетворює його в STATUS> 20 (оскільки в другій версії можна скористатися індексом на стовпці STATUS, а в першу – не можна) З аналогічних причин потрібен спосіб, за допомогою якого можна було б повідомити оптимізаторові, що один визначається користувачем опе ратор є запереченням іншого

б) Якісний звичайний оптимізатор має також інформацію про те, що, на приклад, вираження STATUS> 20 і 20 < STATUS логічно еквівалентні. Тому повинен бути передбачений спосіб передачі оптимізаторові інформації ції про те, що два обумовлених користувачем оператора є противо положностей один одному в зазначеному сенсі.

в) Крім того, якісний звичайний оптимізатор має інформацію про те, що, наприклад, оператори + і – взаємно компенсують один одного (тобто є зворотними по відношенню один до одного) наприклад, вираз STATUS + 20 20 можна скоротити просто до STATUS Повинен бути преду бачено спосіб передачі оптимізаторові відомостей про те, що два обумовлених користувачем оператора є зворотними по відношенню один до одного, у зазначеному сенсі

■&nbsp&nbsp&nbsp&nbsp Вибірковість Якщо дано логічне вираження, таке як STATUS> 20, то оптимізатори зазвичай приймають припущення про вибірковість цього ви ражения (тобто про те, яка процентна частка кортежів, при обробці яких цей вираз прийме значення TRUE) Відносно вбудованих типів даних і операторів ця інформація про вибірковість також може бути жорстко зако складованої в оптимізаторі на відміну від цього, стосовно до визначеним користувачем типами та операторам повинен бути передбачений спосіб предостав лення оптимізаторові деякого визначається користувачем коду, який він міг би викликати, щоб виробити припущення про вибірковість

■&nbsp&nbsp&nbsp&nbsp Визначення вартості Оптимізатор повинен мати інформацію про те, скільки коштуватиме виконання конкретного визначається користувачем оператора Наприклад, якщо дано такий вислів, як р AND q, де р – (скажімо) виклик опе ратора AREA для визначення площі якогось складного багатокутника, aq – просте порівняння зразок STATUS> 20, то, ймовірно, слід було б предпо честь, щоб система спочатку виконала вираз q так, щоб вираз р

виконалось тільки на кортежі, для який q приймає значення TRUE Безумовно, деякі евристичні методи перетворення виразів, що стали класичними (зокрема, такий метод, який завжди передбачає виконання операторів скорочення перед операціями зєднання), не обовязково будуть дійсними для визначених користувачем типів і операторів (див, наприклад, [2610] і [2624])

■&nbsp&nbsp Структури зберігання і методи доступу Оптимізатор, безумовно, повинен мати інформацію про використані структурах зберігання та методах доступу (див наступний підрозділ)

Структури зберігання даних

Цілком очевидно, що для обєктно-реляційних систем потрібно більше способів зберігання і доступу до даних на фізичному рівні (а по всій видимості, навіть набагато більше таких способів), ніж зазвичай було передбачено (наприклад) в системах SQL Нижче наведені деякі міркування поданому питанню

■&nbsp&nbsp&nbsp&nbsp Нові структури зберігання Як вже зазначалося, для системи, мабуть, буде потрібна підтримка нових жорстко закодованих структур зберігання (R-дерева і тд) і може навіть знадобитися спосіб, який дозволяв би поль зователя, що володіє відповідною кваліфікацією, самостійно визна делять додаткові структури зберігання і методи доступу

■&nbsp&nbsp&nbsp&nbsp Індекси на даних визначається користувачем типу Традиційні індекси ос Нова на даних певного вбудованого типу, а також на вбудованої ін формації про те, що означає оператор <". В об'єктно-реляційних системах повинна бути передбачена можливість створювати індекси на даних визна ляемого користувачем типу виходячи з семантики застосовного до них і визна ляемого користувачем оператора "<" (У першу чергу, безумовно, для цього передбачається, що подібний оператор уже визначений).

■&nbsp&nbsp&nbsp&nbsp Індекси на результатах виконання операцій Мабуть, не має сенсу ство давати індекси безпосередньо на безлічі значень даних, наприклад, типу POLYGON, оскільки більш ймовірно те, що такі індекси будуть служити для упо рядоченія відповідних багатокутників за їх внутрішніми закодованим уявленням у вигляді рядка байтів Але індекс, заснований на значеннях пло Щадей цих багатокутників, міг би виявитися досить корисним

Примітка У главі 22 такі індекси згадувалися під назвою функціональних індексів

Джерело: Дейт К Дж, Введення в системи баз даних, 8-е видання: Пер з англ – М: Видавничий дім «Вільямс», 2005 – 1328 с: Ил – Парал тит англ

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*